From d4b4b7abb80d1c27f527f033bf3d1d4df923b46b Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Mon, 6 Dec 2021 21:37:51 -0500 Subject: [PATCH] Fixed one bad error in clock_div which had been done without my knowledge and which went undetected since before MPW-one. Modified the "pll" and "sysctrl" testbenches so that they run and measure something useful. Both exercise the clock monitoring on GPIO outputs functions. The PLL test also runs the digital locked loop (behavioral verilog). The PLL test overlaps sysctrl, but "pll" cannot be run on gate level verilog, whereas "sysctrl" can. --- verilog/dv/caravel/mgmt_soc/pll/pll.c | 19 ++- verilog/dv/caravel/mgmt_soc/pll/pll_tb.v | 24 +++- verilog/dv/caravel/mgmt_soc/sysctrl/sysctrl.c | 111 +++++----------- .../dv/caravel/mgmt_soc/sysctrl/sysctrl_tb.v | 124 +++++++----------- verilog/rtl/clock_div.v | 9 +- 5 files changed, 126 insertions(+), 161 deletions(-) diff --git a/verilog/dv/caravel/mgmt_soc/pll/pll.c b/verilog/dv/caravel/mgmt_soc/pll/pll.c index 6bb80317..978b53e3 100644 --- a/verilog/dv/caravel/mgmt_soc/pll/pll.c +++ b/verilog/dv/caravel/mgmt_soc/pll/pll.c @@ -60,7 +60,6 @@ void main() while (reg_mprj_xfer == 1); // Start test - reg_mprj_datal = 0xA0400000; /* *------------------------------------------------------------- @@ -88,12 +87,14 @@ void main() *------------------------------------------------------------- */ - // Write checkpoint for clock counting (PLL bypassed) - reg_mprj_datal = 0xA0410000; - - // Monitor the core clock and user clock on mprj_io[14] and mprj_io[15] + // reg_clk_out_dest = 0x6 to turn on, 0x0 to turn off + + // Write checkpoint for clock counting (PLL bypassed) + reg_mprj_datal = 0xA0400000; reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x0; + reg_mprj_datal = 0xA0410000; // Set PLL enable, no DCO mode reg_hkspi_pll_ena = 0x1; @@ -103,6 +104,8 @@ void main() // Write checkpoint for clock counting (PLL bypassed) reg_mprj_datal = 0xA0420000; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x0; reg_mprj_datal = 0xA0430000; // Disable PLL bypass @@ -110,6 +113,8 @@ void main() // Write checkpoint for clock counting reg_mprj_datal = 0xA0440000; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x0; reg_mprj_datal = 0xA0450000; // Write 0x03 to feedback divider (was 0x04) @@ -117,6 +122,8 @@ void main() // Write checkpoint reg_mprj_datal = 0xA0460000; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x0; reg_mprj_datal = 0xA0470000; // Write 0x04 to PLL output divider @@ -124,6 +131,8 @@ void main() // Write checkpoint reg_mprj_datal = 0xA0480000; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x0; reg_mprj_datal = 0xA0490000; // End test diff --git a/verilog/dv/caravel/mgmt_soc/pll/pll_tb.v b/verilog/dv/caravel/mgmt_soc/pll/pll_tb.v index ffcb0799..6d662c34 100644 --- a/verilog/dv/caravel/mgmt_soc/pll/pll_tb.v +++ b/verilog/dv/caravel/mgmt_soc/pll/pll_tb.v @@ -84,6 +84,10 @@ module pll_tb; ccount = 0; wait(checkbits == 16'hA041); $display("Monitor: ucount = %d ccount = %d", ucount, ccount); + if (ucount !== 129 || ccount != 129) begin + $display("Monitor: Test PLL Failed"); + $finish; + end wait(checkbits == 16'hA042); $display("Monitor: Test 2 PLL (RTL) Started"); @@ -91,6 +95,10 @@ module pll_tb; ccount = 0; wait(checkbits == 16'hA043); $display("Monitor: ucount = %d ccount = %d", ucount, ccount); + if (ucount !== 193 || ccount != 193) begin + $display("Monitor: Test PLL Failed"); + $finish; + end wait(checkbits == 16'hA044); $display("Monitor: Test 3 PLL (RTL) Started"); @@ -98,6 +106,10 @@ module pll_tb; ccount = 0; wait(checkbits == 16'hA045); $display("Monitor: ucount = %d ccount = %d", ucount, ccount); + if (ucount !== 385 || ccount != 129) begin + $display("Monitor: Test PLL Failed"); + $finish; + end wait(checkbits == 16'hA046); $display("Monitor: Test 4 PLL (RTL) Started"); @@ -105,6 +117,10 @@ module pll_tb; ccount = 0; wait(checkbits == 16'hA047); $display("Monitor: ucount = %d ccount = %d", ucount, ccount); + if (ucount !== 385 || ccount != 129) begin + $display("Monitor: Test PLL Failed"); + $finish; + end wait(checkbits == 16'hA048); $display("Monitor: Test 5 PLL (RTL) Started"); @@ -112,11 +128,15 @@ module pll_tb; ccount = 0; wait(checkbits == 16'hA049); $display("Monitor: ucount = %d ccount = %d", ucount, ccount); + if (ucount !== 513 || ccount != 129) begin + $display("Monitor: Test PLL Failed"); + $finish; + end wait(checkbits == 16'hA090); - $display("Monitor: Test PLL (RTL) Passed"); - $finish; + $display("Monitor: Test PLL (RTL) Passed"); + $finish; end initial begin diff --git a/verilog/dv/caravel/mgmt_soc/sysctrl/sysctrl.c b/verilog/dv/caravel/mgmt_soc/sysctrl/sysctrl.c index a104729e..f55bc3f9 100644 --- a/verilog/dv/caravel/mgmt_soc/sysctrl/sysctrl.c +++ b/verilog/dv/caravel/mgmt_soc/sysctrl/sysctrl.c @@ -20,39 +20,23 @@ // -------------------------------------------------------- /* - * System Control Test - * - Enables SPI master - * - Uses SPI master to internally access the housekeeping SPI - * - Reads default value of SPI-Controlled registers - * - Flags failure/success using mprj_io + * System control test + * - Sets GPIO to monitor the core and user clocks + * + * This test is basically just the first part of the + * PLL test, with the PLL bypassed. Unlike the PLL + * test, it can be run on a gate-level netlist. + * */ void main() { int i; - uint32_t value; - - // Force housekeeping SPI into a disabled state so that the CSB - // pin can be used as an output without the system failing - - reg_hkspi_disable = 1; reg_mprj_datal = 0; - // Configure upper 6 bits of user GPIO for generating testbench + // Configure upper 16 bits of user GPIO for generating testbench // checkpoints. - reg_mprj_io_37 = GPIO_MODE_MGMT_STD_OUTPUT; - reg_mprj_io_36 = GPIO_MODE_MGMT_STD_OUTPUT; - reg_mprj_io_35 = GPIO_MODE_MGMT_STD_OUTPUT; - reg_mprj_io_34 = GPIO_MODE_MGMT_STD_OUTPUT; - reg_mprj_io_33 = GPIO_MODE_MGMT_STD_OUTPUT; - reg_mprj_io_32 = GPIO_MODE_MGMT_STD_OUTPUT; - - // Configure all lower 32 bits for writing the SPI value read on GPIO - // NOTE: Converting reg_mprj_io_3 (CSB) to output will disable the - // SPI. But that should not disable the back-door access to the SPI - // register values! - reg_mprj_io_31 = GPIO_MODE_MGMT_STD_OUTPUT; reg_mprj_io_30 = GPIO_MODE_MGMT_STD_OUTPUT; reg_mprj_io_29 = GPIO_MODE_MGMT_STD_OUTPUT; @@ -70,71 +54,48 @@ void main() reg_mprj_io_17 = GPIO_MODE_MGMT_STD_OUTPUT; reg_mprj_io_16 = GPIO_MODE_MGMT_STD_OUTPUT; + /* Monitor pins must be set to output */ reg_mprj_io_15 = GPIO_MODE_MGMT_STD_OUTPUT; reg_mprj_io_14 = GPIO_MODE_MGMT_STD_OUTPUT; - reg_mprj_io_13 = GPIO_MODE_MGMT_STD_OUTPUT; - reg_mprj_io_12 = GPIO_MODE_MGMT_STD_OUTPUT; - reg_mprj_io_11 = GPIO_MODE_MGMT_STD_OUTPUT; - reg_mprj_io_10 = GPIO_MODE_MGMT_STD_OUTPUT; - reg_mprj_io_9 = GPIO_MODE_MGMT_STD_OUTPUT; - reg_mprj_io_8 = GPIO_MODE_MGMT_STD_OUTPUT; - reg_mprj_io_7 = GPIO_MODE_MGMT_STD_OUTPUT; - reg_mprj_io_6 = GPIO_MODE_MGMT_STD_OUTPUT; - reg_mprj_io_5 = GPIO_MODE_MGMT_STD_OUTPUT; - reg_mprj_io_4 = GPIO_MODE_MGMT_STD_OUTPUT; - reg_mprj_io_3 = GPIO_MODE_MGMT_STD_OUTPUT; - reg_mprj_io_2 = GPIO_MODE_MGMT_STD_OUTPUT; - reg_mprj_io_1 = GPIO_MODE_MGMT_STD_OUTPUT; - reg_mprj_io_0 = GPIO_MODE_MGMT_STD_OUTPUT; /* Apply configuration */ reg_mprj_xfer = 1; while (reg_mprj_xfer == 1); // Start test - reg_mprj_datah = 0x04; - // Read manufacturer and product ID - value = reg_hkspi_chip_id; - reg_mprj_datal = value; // Mfgr + product ID - reg_mprj_datah = 0x05; + /* + *------------------------------------------------------------- + * Register 2620_0004 reg_clk_out_dest + * SPI address 0x1b = Output redirect + * bit 0 = trap to mprj_io[13] + * bit 1 = clk to mprj_io[14] + * bit 2 = clk2 to mprj_io[15] + *------------------------------------------------------------- + */ - // Read user ID - value = reg_hkspi_user_id; - reg_mprj_datal = value; // User ID - reg_mprj_datah = 0x06; + // Monitor the core clock and user clock on mprj_io[14] and mprj_io[15] + // reg_clk_out_dest = 0x6 to turn on, 0x0 to turn off - // Read PLL enables - value = reg_hkspi_pll_ena; - reg_mprj_datal = value; // DLL enables - reg_mprj_datah = 0x07; + // Write checkpoint for making sure nothing is counted when monitoring is off + reg_mprj_datal = 0xA0400000; + reg_clk_out_dest = 0x0; + reg_clk_out_dest = 0x0; + reg_mprj_datal = 0xA0410000; - // Read PLL bypass state - value = reg_hkspi_pll_bypass; - reg_mprj_datal = value; // DLL bypass state - reg_mprj_datah = 0x08; + // Write checkpoint for core clock counting (PLL bypassed) + reg_mprj_datal = 0xA0420000; + reg_clk_out_dest = 0x2; + reg_clk_out_dest = 0x0; + reg_mprj_datal = 0xA0430000; - // Read PLL trim - value = reg_hkspi_pll_trim; - reg_mprj_datal = value; // DLL trim - reg_mprj_datah = 0x09; - - // Read PLL source - value = reg_hkspi_pll_source; - reg_mprj_datal = value; // DLL source - reg_mprj_datah = 0x0a; - - // Read PLL divider - value = reg_hkspi_pll_divider; - reg_mprj_datal = value; // DLL divider - reg_mprj_datah = 0x0b; - - // Read a GPIO configuration word - value = reg_mprj_io_6; - reg_mprj_datal = value; // DLL divider - reg_mprj_datah = 0x0c; + // Write checkpoint for user clock counting (PLL bypassed) + reg_mprj_datal = 0xA0440000; + reg_clk_out_dest = 0x4; + reg_clk_out_dest = 0x0; + reg_mprj_datal = 0xA0450000; // End test - reg_mprj_datah = 0x0d; + reg_mprj_datal = 0xA0900000; } diff --git a/verilog/dv/caravel/mgmt_soc/sysctrl/sysctrl_tb.v b/verilog/dv/caravel/mgmt_soc/sysctrl/sysctrl_tb.v index 0ef9ba41..26d279ce 100644 --- a/verilog/dv/caravel/mgmt_soc/sysctrl/sysctrl_tb.v +++ b/verilog/dv/caravel/mgmt_soc/sysctrl/sysctrl_tb.v @@ -23,13 +23,13 @@ module sysctrl_tb; reg clock; + reg power1; + reg power2; reg RSTB; - reg csb_set; - reg power1, power2; wire gpio; - wire [5:0] checkbits; - wire [31:0] spivalue; + wire [15:0] checkbits; + wire [7:0] spivalue; wire [37:0] mprj_io; wire flash_csb; wire flash_clk; @@ -37,11 +37,11 @@ module sysctrl_tb; wire flash_io1; wire SDO; - assign checkbits = mprj_io[37:32]; - assign spivalue = mprj_io[31:0]; + integer ccount; + integer ucount; - // mrpj_io[3] = CSB needs to be set until the program disables the SPI. - assign mprj_io[3] = (csb_set) ? 1'b1 : 1'bz; + assign checkbits = mprj_io[31:16]; + assign spivalue = mprj_io[15:8]; // External clock is used by default. Make this artificially fast for the // simulation. Normally this would be a slow clock and the digital PLL @@ -49,6 +49,16 @@ module sysctrl_tb; always #10 clock <= (clock === 1'b0); + // User clock monitoring + always @(posedge mprj_io[15]) begin + ucount = ucount + 1; + end + + // Core clock monitoring + always @(posedge mprj_io[14]) begin + ccount = ccount + 1; + end + initial begin clock = 0; end @@ -61,80 +71,50 @@ module sysctrl_tb; $display("+1000 cycles"); end $display("%c[1;31m",27); - `ifdef GL - $display ("Monitor: Timeout, Test Sysctrl (GL) Failed"); - `else - $display ("Monitor: Timeout, Test Sysctrl (RTL) Failed"); - `endif - $display("%c[0m",27); + $display ("Monitor: Timeout, Test Sysctrl (RTL) Failed"); + $display("%c[0m",27); $finish; end // Monitor initial begin - wait(checkbits == 6'h04); - `ifdef GL - $display("Monitor: Test Sysctrl (GL) Started"); - `else - $display("Monitor: Test Sysctrl (RTL) Started"); - `endif - wait(checkbits == 6'h05); - $display(" Chip ID value = 0x%x (should be 0x00045611)", spivalue); - if(spivalue !== 32'h00045611) begin + wait(checkbits == 16'hA040); + $display("Monitor: Test 1 Sysctrl (RTL) Started"); + ucount = 0; + ccount = 0; + wait(checkbits == 16'hA041); + $display("Monitor: ucount = %d ccount = %d", ucount, ccount); + if (ucount !== 0 || ccount != 0) begin $display("Monitor: Test Sysctrl Failed"); $finish; end - wait(checkbits == 6'h06); - $display(" User ID value = 0x%x (should be 0x00000000)", spivalue); - if(spivalue !== 32'h00000000) begin + + wait(checkbits == 16'hA042); + $display("Monitor: Test 1 Sysctrl (RTL) Started"); + ucount = 0; + ccount = 0; + wait(checkbits == 16'hA043); + $display("Monitor: ucount = %d ccount = %d", ucount, ccount); + if (ucount !== 129 || ccount != 0) begin $display("Monitor: Test Sysctrl Failed"); $finish; end - wait(checkbits == 6'h07); - $display(" PLL enables value = 0x%x (should be 0x00000002)", spivalue); - if(spivalue !== 32'h00000002) begin - $display("Monitor: Test Sysctrl Failed"); - $finish; - end - wait(checkbits == 6'h08); - $display(" PLL bypass value = 0x%x (should be 0x00000001)", spivalue); - if(spivalue !== 32'h00000001) begin - $display("Monitor: Test Sysctrl Failed"); - $finish; - end - wait(checkbits == 6'h09); - $display(" PLL trim value = 0x%x (should be 0x03ffefff)", spivalue); - if(spivalue !== 32'h03ffefff) begin - $display("Monitor: Test Sysctrl Failed"); - $finish; - end - wait(checkbits == 6'h0a); - $display(" PLL divider value = 0x%x (should be 0x00000012)", spivalue); - if(spivalue !== 32'h00000012) begin - $display("Monitor: Test Sysctrl Failed"); - $finish; - end - wait(checkbits == 6'h0b); - $display(" PLL source value = 0x%x (should be 0x00000004)", spivalue); - if(spivalue !== 32'h00000004) begin - $display("Monitor: Test Sysctrl Failed"); - $finish; - end - wait(checkbits == 6'h0c); - $display(" GPIO config value = 0x%x (should be 0x00001809)", spivalue); - if(spivalue !== 32'h00001809) begin + + wait(checkbits == 16'hA044); + $display("Monitor: Test 2 Sysctrl (RTL) Started"); + ucount = 0; + ccount = 0; + wait(checkbits == 16'hA045); + $display("Monitor: ucount = %d ccount = %d", ucount, ccount); + if (ucount !== 0 || ccount != 129) begin $display("Monitor: Test Sysctrl Failed"); $finish; end + wait(checkbits == 16'hA090); - wait(checkbits == 6'h0d); - `ifdef GL - $display("Monitor: Test Sysctrl (GL) Passed"); - `else - $display("Monitor: Test Sysctrl (RTL) Passed"); - `endif - $finish; + $display("Monitor: Test Sysctrl (RTL) Passed"); + $finish; end initial begin @@ -144,16 +124,13 @@ module sysctrl_tb; #2000; end - initial begin // Power-up sequence + initial begin power1 <= 1'b0; power2 <= 1'b0; - csb_set <= 1'b1; #200; power1 <= 1'b1; #200; power2 <= 1'b1; - #200000; - csb_set <= 1'b0; // Release CSB after SPI is disabled end always @(checkbits) begin @@ -168,21 +145,18 @@ module sysctrl_tb; assign VDD1V8 = power2; assign VSS = 1'b0; - + assign mprj_io[3] = 1'b1; // Force CSB high. + caravel uut ( .vddio (VDD3V3), - .vddio_2 (VDD3V3), .vssio (VSS), - .vssio_2 (VSS), .vdda (VDD3V3), .vssa (VSS), .vccd (VDD1V8), .vssd (VSS), .vdda1 (VDD3V3), - .vdda1_2 (VDD3V3), .vdda2 (VDD3V3), .vssa1 (VSS), - .vssa1_2 (VSS), .vssa2 (VSS), .vccd1 (VDD1V8), .vccd2 (VDD1V8), diff --git a/verilog/rtl/clock_div.v b/verilog/rtl/clock_div.v index 49ff44bf..a2bbf195 100644 --- a/verilog/rtl/clock_div.v +++ b/verilog/rtl/clock_div.v @@ -102,9 +102,10 @@ module odd #( end reg [SIZE-1:0] initial_begin; // this is used to offset the negative edge counter - // wire [SIZE:0] interm_3; // from the positive edge counter in order to - // assign interm_3 = {1'b0,N} + 2'b11; // guarante 50% duty cycle. - localparam [SIZE:0] interm_3 = {1'b0,`CLK_DIV} + 2'b11; + wire [SIZE:0] interm_3; // from the positive edge counter in order to + assign interm_3 = {1'b0, N} + 2'b11; // guarantee 50% duty cycle. + + localparam [SIZE:0] interm_init = {1'b0,`CLK_DIV} + 2'b11; // Counter driven by negative edge of clock. @@ -112,7 +113,7 @@ module odd #( if (resetb == 1'b0) begin // reset the counter at system reset counter2 <= `CLK_DIV; - initial_begin <= interm_3[SIZE:1]; + initial_begin <= interm_init[SIZE:1]; out_counter2 <= 1; end else if (rst_pulse) begin // reset the counter at change of N.