Added a secondary clock output, going to the user area, that is derived
from the 90-degree phase PLL clock and run on an independent divider.
The use of the 90-degree phase clock is mostly to balance the output
loads.
diff --git a/verilog/rtl/caravel.v b/verilog/rtl/caravel.v
index f0708d2..a73cf98 100644
--- a/verilog/rtl/caravel.v
+++ b/verilog/rtl/caravel.v
@@ -266,6 +266,7 @@
// SoC core
wire caravel_clk;
+ wire caravel_clk2;
wire caravel_rstn;
wire [7:0] spi_ro_config_core;
@@ -336,6 +337,7 @@
// Clocks and reset
.clock(clock_core),
.core_clk(caravel_clk),
+ .user_clk(caravel_clk2),
.core_rstn(caravel_rstn),
// Logic Analyzer
.la_input(la_data_out_mprj),
@@ -379,6 +381,7 @@
/* the vccd1 domain. */
wire mprj_clock;
+ wire mprj_clock2;
wire mprj_resetn;
wire mprj_cyc_o_user;
wire mprj_stb_o_user;
@@ -395,6 +398,7 @@
.vssd1(vssd1),
`endif
.caravel_clk(caravel_clk),
+ .caravel_clk2(caravel_clk2),
.caravel_rstn(caravel_rstn),
.mprj_cyc_o_core(mprj_cyc_o_core),
.mprj_stb_o_core(mprj_stb_o_core),
@@ -406,6 +410,7 @@
.la_oen(la_oen),
.user_clock(mprj_clock),
+ .user_clock2(mprj_clock2),
.user_resetn(mprj_resetn),
.mprj_cyc_o_user(mprj_cyc_o_user),
.mprj_stb_o_user(mprj_stb_o_user),
diff --git a/verilog/rtl/caravel_clocking.v b/verilog/rtl/caravel_clocking.v
index db249d2..ecf8215 100644
--- a/verilog/rtl/caravel_clocking.v
+++ b/verilog/rtl/caravel_clocking.v
@@ -9,9 +9,12 @@
input ext_clk_sel, // 0=use PLL clock, 1=use external (pad) clock
input ext_clk, // External pad (slow) clock
input pll_clk, // Internal PLL (fast) clock
+ input pll_clk90, // Internal PLL (fast) clock, 90 degree phase
input [2:0] sel, // Select clock divider value (0=thru, 1=divide-by-2, etc.)
+ input [2:0] sel2, // Select clock divider value for 90 degree phase divided clock
input ext_reset, // Positive sense reset from housekeeping SPI.
output core_clk, // Output core clock
+ output user_clk, // Output user (secondary) clock
output resetb_sync // Output propagated and buffered reset
);
@@ -50,10 +53,23 @@
.resetb(resetb)
);
+ // Secondary PLL clock divider for user space access
+
+ clock_div #(
+ .SIZE(3)
+ ) divider2 (
+ .in(pll_clk90),
+ .out(pll_clk90_divided),
+ .N(sel2),
+ .resetb(resetb)
+ );
+
+
// Multiplex the clock output
assign core_ext_clk = (use_pll_first) ? ext_clk_syncd : ext_clk;
assign core_clk = (use_pll_second) ? pll_clk_divided : core_ext_clk;
+ assign user_clk = (use_pll_second) ? pll_clk90_divided : core_ext_clk;
// Reset assignment. "reset" comes from POR, while "ext_reset"
// comes from standalone SPI (and is normally zero unless
diff --git a/verilog/rtl/housekeeping_spi.v b/verilog/rtl/housekeeping_spi.v
index 10ea1b3..2942b27 100644
--- a/verilog/rtl/housekeeping_spi.v
+++ b/verilog/rtl/housekeeping_spi.v
@@ -53,8 +53,8 @@
`endif
RSTB, SCK, SDI, CSB, SDO, sdo_enb,
pll_ena, pll_dco_ena, pll_div, pll_sel,
- pll_trim, pll_bypass, irq, reset, trap,
- mask_rev_in, pass_thru_reset,
+ pll90_sel, pll_trim, pll_bypass, irq, reset,
+ trap, mask_rev_in, pass_thru_reset,
pass_thru_mgmt_sck, pass_thru_mgmt_csb,
pass_thru_mgmt_sdi, pass_thru_mgmt_sdo,
pass_thru_user_sck, pass_thru_user_csb,
@@ -78,6 +78,7 @@
output pll_dco_ena;
output [4:0] pll_div;
output [2:0] pll_sel;
+ output [2:0] pll90_sel;
output [25:0] pll_trim;
output pll_bypass;
output irq;
@@ -101,6 +102,7 @@
reg [25:0] pll_trim;
reg [4:0] pll_div;
reg [2:0] pll_sel;
+ reg [2:0] pll90_sel;
reg pll_dco_ena;
reg pll_ena;
reg pll_bypass;
@@ -186,7 +188,7 @@
(iaddr == 8'h0e) ? pll_trim[15:8] :
(iaddr == 8'h0f) ? pll_trim[23:16] :
(iaddr == 8'h10) ? {6'b000000, pll_trim[25:24]} :
- (iaddr == 8'h11) ? {5'b00000, pll_sel} :
+ (iaddr == 8'h11) ? {2'b00, pll90_sel, pll_sel} :
(iaddr == 8'h12) ? {3'b000, pll_div} :
8'h00; // Default
@@ -198,6 +200,7 @@
// pll_trim[12] must be set to zero for proper startup.
pll_trim <= 26'b11111111111110111111111111;
pll_sel <= 3'b010; // Default output divider divide-by-2
+ pll90_sel <= 3'b010; // Default secondary output divider divide-by-2
pll_div <= 5'b00100; // Default feedback divider divide-by-8
pll_dco_ena <= 1'b1; // Default free-running PLL
pll_ena <= 1'b0; // Default PLL turned off
@@ -234,6 +237,7 @@
end
8'h11: begin
pll_sel <= idata[2:0];
+ pll90_sel <= idata[5:3];
end
8'h12: begin
pll_div <= idata[4:0];
diff --git a/verilog/rtl/mgmt_core.v b/verilog/rtl/mgmt_core.v
index 8435a5e..45f65a4 100644
--- a/verilog/rtl/mgmt_core.v
+++ b/verilog/rtl/mgmt_core.v
@@ -68,6 +68,7 @@
output [31:0] xbar_dat_o,
output core_clk,
+ output user_clk,
output core_rstn,
// Metal programmed user ID / mask revision vector
@@ -86,10 +87,13 @@
.ext_clk_sel(ext_clk_sel),
.ext_clk(clock),
.pll_clk(pll_clk),
+ .pll_clk90(pll_clk90),
.resetb(resetb),
.sel(spi_pll_sel),
+ .sel2(spi_pll90_sel),
.ext_reset(ext_reset), // From housekeeping SPI
.core_clk(core_clk),
+ .user_clk(user_clk),
.resetb_sync(core_rstn)
);
@@ -217,6 +221,7 @@
// Housekeeping SPI vectors
wire [4:0] spi_pll_div;
wire [2:0] spi_pll_sel;
+ wire [2:0] spi_pll90_sel;
wire [25:0] spi_pll_trim;
// Housekeeping SPI (SPI slave module)
@@ -233,6 +238,7 @@
.sdo_enb(sdo_outenb),
.pll_dco_ena(spi_pll_dco_ena),
.pll_sel(spi_pll_sel),
+ .pll90_sel(spi_pll90_sel),
.pll_div(spi_pll_div),
.pll_ena(spi_pll_ena),
.pll_trim(spi_pll_trim),
diff --git a/verilog/rtl/mgmt_protect.v b/verilog/rtl/mgmt_protect.v
index 24b9cbc..1b04731 100644
--- a/verilog/rtl/mgmt_protect.v
+++ b/verilog/rtl/mgmt_protect.v
@@ -22,6 +22,7 @@
`endif
input caravel_clk,
+ input caravel_clk2,
input caravel_rstn,
input mprj_cyc_o_core,
input mprj_stb_o_core,
@@ -33,6 +34,7 @@
input [127:0] la_oen,
output user_clock,
+ output user_clock2,
output user_resetn,
output mprj_cyc_o_user,
output mprj_stb_o_user,
@@ -43,9 +45,9 @@
output [127:0] la_data_in_mprj
);
- wire [72:0] mprj_logic1;
+ wire [73:0] mprj_logic1;
- sky130_fd_sc_hd__conb_1 mprj_logic_high [72:0] (
+ sky130_fd_sc_hd__conb_1 mprj_logic_high [73:0] (
`ifdef LVS
.VPWR(vccd1),
.VGND(vssd1),
@@ -80,6 +82,18 @@
.TE(mprj_logic1[1])
);
+ sky130_fd_sc_hd__einvp_8 mprj_clk2_buf (
+ `ifdef LVS
+ .VPWR(vccd),
+ .VGND(vssd),
+ .VPB(vccd),
+ .VNB(vssd),
+ `endif
+ .Z(user_clock2),
+ .A(~caravel_clk2),
+ .TE(mprj_logic1[2])
+ );
+
sky130_fd_sc_hd__einvp_8 mprj_cyc_buf (
`ifdef LVS
.VPWR(vccd),
@@ -89,7 +103,7 @@
`endif
.Z(mprj_cyc_o_user),
.A(~mprj_cyc_o_core),
- .TE(mprj_logic1[2])
+ .TE(mprj_logic1[3])
);
sky130_fd_sc_hd__einvp_8 mprj_stb_buf (
@@ -101,7 +115,7 @@
`endif
.Z(mprj_stb_o_user),
.A(~mprj_stb_o_core),
- .TE(mprj_logic1[3])
+ .TE(mprj_logic1[4])
);
sky130_fd_sc_hd__einvp_8 mprj_we_buf (
@@ -113,7 +127,7 @@
`endif
.Z(mprj_we_o_user),
.A(~mprj_we_o_core),
- .TE(mprj_logic1[4])
+ .TE(mprj_logic1[5])
);
sky130_fd_sc_hd__einvp_8 mprj_sel_buf [3:0] (
@@ -125,7 +139,7 @@
`endif
.Z(mprj_sel_o_user),
.A(~mprj_sel_o_core),
- .TE(mprj_logic1[8:5])
+ .TE(mprj_logic1[9:6])
);
sky130_fd_sc_hd__einvp_8 mprj_adr_buf [31:0] (
@@ -137,7 +151,7 @@
`endif
.Z(mprj_adr_o_user),
.A(~mprj_adr_o_core),
- .TE(mprj_logic1[40:9])
+ .TE(mprj_logic1[41:10])
);
sky130_fd_sc_hd__einvp_8 mprj_dat_buf [31:0] (
@@ -149,7 +163,7 @@
`endif
.Z(mprj_dat_o_user),
.A(~mprj_dat_o_core),
- .TE(mprj_logic1[72:41])
+ .TE(mprj_logic1[73:42])
);
/* The LA buffers are controlled from the user side, so */