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 */