//------------------------------------------------------------------------------ // // Testbench: CPLD1 - SPI Communication & Register R/W // Project: NewCalBoard DIG // Tool: Lattice Diamond Verilog-2001 simulator // Purpose: Verify SPI protocol (MISO/MOSI timing) and register read/write // on the full RelayConTop design. // // Protocol: // Write: [WR=1][Addr:7b][Data:24b] = 32 bits // Read: [WR=0][Addr:7b][Don'tCare:24b] -> MISO returns [8'h00][24-bit rdata] // //------------------------------------------------------------------------------ `timescale 1ns / 1ps `define SYS_CLK_PERIOD 20 // 50 MHz system clock `define SPI_CLK_PERIOD 400 // 1 MHz SPI clock module tb_SPI_RegRW; ////========================================================================== // Signal declarations - mirrors RelayConTop pinout exactly ////========================================================================== // Clock & reset reg i_sys_clk; reg i_rst_n; // SPI interface (Zynq PS drives these) reg i_sclk; reg i_mosi; reg i_cs; // Flow control (from Zynq PS / SPI_Con IP) reg i_rready; reg i_wvalid; // Status outputs (monitored by testbench) wire o_miso; wire o_wready; wire o_err; wire o_con_done; // Relay control outputs wire o_IO_RC1; wire o_RC_VSel; wire o_RC_ISel; wire [17:0] o_RC_RLSel; wire [1:0] o_RC_LOF; wire [1:0] o_RC_LOS; wire o_RC_T27; wire o_RC_T28; wire o_RC_T29; wire o_RC_T30; wire o_RC_T31; wire o_RC_T32; // PMU output channels (4 x 32-bit) wire [31:0] o_PMU_OC_1; wire [31:0] o_PMU_OC_2; wire [31:0] o_PMU_OC_3; wire [31:0] o_PMU_OC_4; // DMM enable bus (19 bits) wire [18:0] o_DMM_EN; ////========================================================================== // DUT instantiation - connect every pin ////========================================================================== RelayConTop DUT ( .i_sys_clk (i_sys_clk), .i_rst_n (i_rst_n), .i_sclk (i_sclk), .i_mosi (i_mosi), .i_cs (i_cs), .o_miso (o_miso), .i_rready (i_rready), .i_wvalid (i_wvalid), .o_wready (o_wready), .o_err (o_err), .o_con_done (o_con_done), .o_DMM_EN (o_DMM_EN), .o_IO_RC1 (o_IO_RC1), .o_RC_T27 (o_RC_T27), .o_RC_T28 (o_RC_T28), .o_RC_T29 (o_RC_T29), .o_RC_T30 (o_RC_T30), .o_RC_T31 (o_RC_T31), .o_RC_T32 (o_RC_T32), .o_RC_RLSel (o_RC_RLSel), .o_RC_VSel (o_RC_VSel), .o_RC_ISel (o_RC_ISel), .o_RC_LOF (o_RC_LOF), .o_RC_LOS (o_RC_LOS), .o_PMU_OC_1 (o_PMU_OC_1), .o_PMU_OC_2 (o_PMU_OC_2), .o_PMU_OC_3 (o_PMU_OC_3), .o_PMU_OC_4 (o_PMU_OC_4) ); //========================================================================== // Clock Generation //========================================================================== initial begin i_sys_clk = 0; forever #(`SYS_CLK_PERIOD / 2) i_sys_clk = ~i_sys_clk; end initial begin i_sclk = 0; forever #(`SPI_CLK_PERIOD / 2) i_sclk = ~i_sclk; end //========================================================================== // Test Statistics //========================================================================== integer test_pass; integer test_fail; integer test_num; // assertion count integer test_case_num; // test case count (7 main tests + optional) initial begin test_pass = 0; test_fail = 0; test_num = 0; test_case_num = 0; end task tb_pass; input string msg; begin test_pass = test_pass + 1; $display("[PASS] Assertion %0d: %s", test_num, msg); end endtask task tb_fail; input string msg; input string detail; begin test_fail = test_fail + 1; $display("[FAIL] Assertion %0d: %s >> %s", test_num, msg, detail); end endtask task tb_assert; input condition; input string msg; input string detail; begin test_num = test_num + 1; if (condition) begin tb_pass(msg); end else begin tb_fail(msg, detail); end end endtask //========================================================================== // SPI Helper Tasks // // SPI Mode 0: CPOL=0, CPHA=0 // - SCLK idle LOW // - MOSI sampled on RISING edge // - MISO shifted on FALLING edge // - MSB first, 32 bits per transaction // // MISO is tri-stated (high-Z) when CS is HIGH. //========================================================================== // --- spi_send: Drive a 32-bit word out through MOSI --- task spi_send; input [31:0] data; integer i; begin @(negedge i_sclk); i_cs = 1'b0; @(negedge i_sclk); for (i = 31; i >= 0; i = i - 1) begin i_mosi = data[i]; @(posedge i_sclk); end @(negedge i_sclk); i_cs = 1'b1; i_mosi = 1'b0; @(negedge i_sclk); end endtask // --- spi_read: Send command, capture response on MISO --- // C1 Fix: Added @(posedge i_sys_clk) after CS low to allow BUS_Con // 2-stage sync chain (cs_sync/sclk_sync) to settle before MISO sampling. // W2 Fix: #1 delay = 1ps (min time step) for clock-to-Q timing margin. task spi_read; input [31:0] cmd; output [31:0] rdata; integer i; begin @(negedge i_sclk); i_cs = 1'b0; @(posedge i_sys_clk); // C1: System clock sync for BUS_Con cross-domain settle rdata = 32'b0; for (i = 31; i >= 0; i = i - 1) begin i_mosi = cmd[i]; @(posedge i_sclk); @(negedge i_sclk); #1; // W2: 1ps clock-to-Q timing margin for MISO sampling rdata[i] = o_miso; end @(negedge i_sclk); i_cs = 1'b1; i_mosi = 1'b0; @(negedge i_sclk); end endtask // --- spi_write: Send a write command --- task spi_write; input [31:0] data; begin spi_send(data); end endtask //--- wait_wready: Wait for SPI to be ready --- task wait_wready; input [15:0] max_cycles; output [1:0] result; integer i; begin result = 2'b0; for (i = 0; i < max_cycles; i = i + 1) begin #(`SYS_CLK_PERIOD); if (o_wready) begin result = 2'b1; return; end end end endtask //========================================================================== // Convenience: Build SPI frames //========================================================================== function [31:0] mk_write; input [6:0] addr; input [23:0] data; begin mk_write = {1'b1, addr, data}; end endfunction function [31:0] mk_read; input [6:0] addr; begin mk_read = {1'b0, addr, 24'b0}; end endfunction //========================================================================== // Main Test Sequence //========================================================================== initial begin // Initialize i_rst_n = 1'b0; i_cs = 1'b1; i_mosi = 1'b0; #(`SYS_CLK_PERIOD * 4); i_rst_n = 1'b1; #(`SYS_CLK_PERIOD * 10); $display(""); $display("============================================================="); $display(" CPLD1 SPI Communication & Register R/W Testbench"); $display(" System clock: %d MHz | SPI clock: %d MHz", 1000 / `SYS_CLK_PERIOD, 1000 / `SPI_CLK_PERIOD); $display("============================================================="); $display(""); test_spi_miso_mosi_timing(); test_ident_register(); test_register_rw_cycle(); test_write_then_read(); test_rapid_spi_transactions(); test_error_conditions(); test_miso_tri_state(); test_con_done_flow(); // S3: execution flow test print_summary(); #(`SYS_CLK_PERIOD * 20); $finish; end //========================================================================== // Test 1: MISO/MOSI SPI Timing //========================================================================== task test_spi_miso_mosi_timing; reg [31:0] rdata; reg [1:0] wait_result; begin test_case_num = test_case_num + 1; $display(""); $display("-------------------------------------------------------------"); $display(" Test 1: MISO/MOSI SPI Timing"); $display("-------------------------------------------------------------"); // 1a. MISO is high-Z when CS is HIGH $display(" 1a. MISO tri-state when CS=HIGH"); i_cs = 1'b1; @(negedge i_sclk); tb_assert(o_miso === 1'bz, "MISO is high-Z when CS=HIGH", $sformatf("o_miso = %b (expected z)", o_miso)); // 1b. MISO responds after CS goes LOW $display(" 1b. MISO active after CS=LOW"); spi_read(mk_read(7'd0), rdata); tb_assert(o_miso !== 1'bz, "MISO is active (not high-Z) when CS=LOW", ""); // 1c. Verify data alignment: first 8 bits are 0, then 24-bit data $display(" 1c. Verify read response alignment"); spi_read(mk_read(7'd0), rdata); tb_assert(rdata[7:0] === 8'h00, "First 8 bits of read response are 0 padding", $sformatf("rdata[7:0] = 0x%02h (expected 0x00)", rdata[7:0])); tb_assert(rdata[23:0] === 24'h200010, "Last 24 bits are IDENT register value", $sformatf("rdata[23:0] = 0x%06h (expected 0x200010)", rdata[23:0])); // 1d. Write command: verify MOSI is sampled correctly $display(" 1d. Write command sent correctly"); spi_write(mk_write(7'd2, (24'h0DEADBEE >> 8))); // W3: parentheses for clarity wait_wready(100, wait_result); // C2: explicit wready check tb_assert(wait_result[1] === 1'b1, "wready asserted after write", $sformatf("wait_result = %b", wait_result)); #(`SPI_CLK_PERIOD); end endtask //========================================================================== // Test 2: IDENT Register (ADDR 0) //========================================================================== task test_ident_register; reg [31:0] rdata; begin test_case_num = test_case_num + 1; $display(""); $display("-------------------------------------------------------------"); $display(" Test 2: IDENT Register (ADDR 0)"); $display("-------------------------------------------------------------"); // 2a. Read IDENT register $display(" 2a. Read IDENT register"); spi_read(mk_read(7'd0), rdata); tb_assert(rdata[23:0] === 24'h200010, "IDENT register returns 24'h200010 (CPLD1, v1.1.0)", $sformatf("rdata[23:0] = 0x%06h", rdata[23:0])); // 2b. Read IDENT multiple times (should always return same value) $display(" 2b. Read IDENT multiple times"); spi_read(mk_read(7'd0), rdata); tb_assert(rdata[23:0] === 24'h200010, "IDENT register returns same value on repeat read", ""); spi_read(mk_read(7'd0), rdata); tb_assert(rdata[23:0] === 24'h200010, "IDENT register returns same value on 3rd read", ""); #(`SPI_CLK_PERIOD); end endtask //========================================================================== // Test 3: Register Read/Write Cycle //========================================================================== task test_register_rw_cycle; reg [31:0] rdata; reg [1:0] wait_result; begin test_case_num = test_case_num + 1; $display(""); $display("-------------------------------------------------------------"); $display(" Test 3: Register Read/Write Cycle"); $display("-------------------------------------------------------------"); // 3a. Write to ADDR 2 (Freq_Slot1), then read back $display(" 3a. Write ADDR 2 = 0x000005, read back"); spi_write(mk_write(7'd2, 24'h000005)); wait_wready(100, wait_result); // C2: explicit wready check tb_assert(wait_result[1] === 1'b1, "wready asserted after write to ADDR 2", $sformatf("wait_result = %b", wait_result)); spi_read(mk_read(7'd2), rdata); tb_assert(rdata[23:0] === 24'h000005, "ADDR 2: write 0x000005, read back 0x000005", $sformatf("rdata[23:0] = 0x%06h", rdata[23:0])); // 3b. Write to ADDR 3, read back $display(" 3b. Write ADDR 3 = 0x003001, read back"); spi_write(mk_write(7'd3, 24'h003001)); wait_wready(100, wait_result); // C2: explicit wready check tb_assert(wait_result[1] === 1'b1, "wready asserted after write to ADDR 3", $sformatf("wait_result = %b", wait_result)); spi_read(mk_read(7'd3), rdata); tb_assert(rdata[23:0] === 24'h003001, "ADDR 3: write 0x003001, read back 0x003001", $sformatf("rdata[23:0] = 0x%06h", rdata[23:0])); // 3c. Write to ADDR 4, read back $display(" 3c. Write ADDR 4 = 0x001040, read back"); spi_write(mk_write(7'd4, 24'h001040)); wait_wready(100, wait_result); // C2: explicit wready check tb_assert(wait_result[1] === 1'b1, "wready asserted after write to ADDR 4", $sformatf("wait_result = %b", wait_result)); spi_read(mk_read(7'd4), rdata); tb_assert(rdata[23:0] === 24'h001040, "ADDR 4: write 0x001040, read back 0x001040", $sformatf("rdata[23:0] = 0x%06h", rdata[23:0])); // 3d. Write to ADDR 5, read back $display(" 3d. Write ADDR 5 = 0x000802, read back"); spi_write(mk_write(7'd5, 24'h000802)); wait_wready(100, wait_result); // C2: explicit wready check tb_assert(wait_result[1] === 1'b1, "wready asserted after write to ADDR 5", $sformatf("wait_result = %b", wait_result)); spi_read(mk_read(7'd5), rdata); tb_assert(rdata[23:0] === 24'h000802, "ADDR 5: write 0x000802, read back 0x000802", $sformatf("rdata[23:0] = 0x%06h", rdata[23:0])); // 3e. Write to ADDR 6 (DC_Slot1), read back $display(" 3e. Write ADDR 6 = 0x002003, read back"); spi_write(mk_write(7'd6, 24'h002003)); wait_wready(100, wait_result); // C2: explicit wready check tb_assert(wait_result[1] === 1'b1, "wready asserted after write to ADDR 6", $sformatf("wait_result = %b", wait_result)); spi_read(mk_read(7'd6), rdata); tb_assert(rdata[23:0] === 24'h002003, "ADDR 6: write 0x002003, read back 0x002003", $sformatf("rdata[23:0] = 0x%06h", rdata[23:0])); // 3f. Write all DC registers $display(" 3f. Write ADDR 7-9, read back"); spi_write(mk_write(7'd7, 24'h004005)); wait_wready(100, wait_result); // C2: explicit wready check tb_assert(wait_result[1] === 1'b1, "wready asserted after write to ADDR 7", $sformatf("wait_result = %b", wait_result)); spi_read(mk_read(7'd7), rdata); tb_assert(rdata[23:0] === 24'h004005, "ADDR 7: write 0x004005, read back 0x004005", ""); spi_write(mk_write(7'd8, 24'h006007)); wait_wready(100, wait_result); // C2: explicit wready check tb_assert(wait_result[1] === 1'b1, "wready asserted after write to ADDR 8", $sformatf("wait_result = %b", wait_result)); spi_read(mk_read(7'd8), rdata); tb_assert(rdata[23:0] === 24'h006007, "ADDR 8: write 0x006007, read back 0x006007", ""); spi_write(mk_write(7'd9, 24'h008009)); wait_wready(100, wait_result); // C2: explicit wready check tb_assert(wait_result[1] === 1'b1, "wready asserted after write to ADDR 9", $sformatf("wait_result = %b", wait_result)); spi_read(mk_read(7'd9), rdata); tb_assert(rdata[23:0] === 24'h008009, "ADDR 9: write 0x008009, read back 0x008009", ""); #(`SPI_CLK_PERIOD); end endtask //========================================================================== // Test 4: Write Then Read (separate transactions) //========================================================================== task test_write_then_read; reg [31:0] rdata; reg [1:0] wait_result; begin test_case_num = test_case_num + 1; $display(""); $display("-------------------------------------------------------------"); $display(" Test 4: Write Then Read (separate transactions)"); $display("-------------------------------------------------------------"); // 4a. Write value, wait, then read (verify persistence) $display(" 4a. Write 0xABCDEF to ADDR 2, read after delay"); spi_write(mk_write(7'd2, 24'hABCDEF)); wait_wready(100, wait_result); // C2: explicit wready check tb_assert(wait_result[1] === 1'b1, "wready asserted after write to ADDR 2", $sformatf("wait_result = %b", wait_result)); // Simulate some delay (multiple SPI clock cycles) #(`SPI_CLK_PERIOD * 3); spi_read(mk_read(7'd2), rdata); tb_assert(rdata[23:0] === 24'hABCDEF, "ADDR 2: value persists after delay", $sformatf("rdata[23:0] = 0x%06h (expected 0xABCDEF)", rdata[23:0])); // 4b. Write another value, read immediately $display(" 4b. Write 0x112233 to ADDR 3, read immediately"); spi_write(mk_write(7'd3, 24'h112233)); wait_wready(100, wait_result); // C2: explicit wready check tb_assert(wait_result[1] === 1'b1, "wready asserted after write to ADDR 3", $sformatf("wait_result = %b", wait_result)); spi_read(mk_read(7'd3), rdata); tb_assert(rdata[23:0] === 24'h112233, "ADDR 3: value reads back immediately", $sformatf("rdata[23:0] = 0x%06h", rdata[23:0])); // 4c. Write 0 to register, read back $display(" 4c. Write 0x000000 to ADDR 4, read back"); spi_write(mk_write(7'd4, 24'h000000)); wait_wready(100, wait_result); // C2: explicit wready check tb_assert(wait_result[1] === 1'b1, "wready asserted after write to ADDR 4", $sformatf("wait_result = %b", wait_result)); spi_read(mk_read(7'd4), rdata); tb_assert(rdata[23:0] === 24'h000000, "ADDR 4: write 0x000000, read back 0x000000", ""); #(`SPI_CLK_PERIOD); end endtask //========================================================================== // Test 5: Rapid SPI Transactions //========================================================================== task test_rapid_spi_transactions; reg [31:0] rdata; reg [1:0] wait_result; begin test_case_num = test_case_num + 1; $display(""); $display("-------------------------------------------------------------"); $display(" Test 5: Rapid SPI Transactions"); $display("-------------------------------------------------------------"); // 5a. Multiple rapid writes $display(" 5a. Rapid successive writes"); spi_write(mk_write(7'd2, 24'h000001)); spi_write(mk_write(7'd3, 24'h000002)); spi_write(mk_write(7'd4, 24'h000003)); spi_write(mk_write(7'd5, 24'h000004)); wait_wready(100, wait_result); // C2: explicit wready check tb_assert(wait_result[1] === 1'b1, "wready asserted after rapid writes", $sformatf("wait_result = %b", wait_result)); // Verify all values spi_read(mk_read(7'd2), rdata); tb_assert(rdata[23:0] === 24'h000001, "Rapid write: ADDR 2 = 0x000001", $sformatf("rdata[23:0] = 0x%06h", rdata[23:0])); spi_read(mk_read(7'd3), rdata); tb_assert(rdata[23:0] === 24'h000002, "Rapid write: ADDR 3 = 0x000002", ""); spi_read(mk_read(7'd4), rdata); tb_assert(rdata[23:0] === 24'h000003, "Rapid write: ADDR 4 = 0x000003", ""); spi_read(mk_read(7'd5), rdata); tb_assert(rdata[23:0] === 24'h000004, "Rapid write: ADDR 5 = 0x000004", ""); // 5b. Interleaved write/read $display(" 5b. Interleaved write/read"); spi_write(mk_write(7'd6, (24'h0DEADBEE >> 8))); // W3: parentheses for clarity wait_wready(100, wait_result); // C2: explicit wready check tb_assert(wait_result[1] === 1'b1, "wready asserted after write to ADDR 6", $sformatf("wait_result = %b", wait_result)); spi_read(mk_read(7'd6), rdata); tb_assert(rdata[23:0] === (24'h0DEADBEE >> 8), "Interleaved: ADDR 6 correct", ""); spi_write(mk_write(7'd7, (24'hCAFEBE >> 8))); // W3: parentheses for clarity wait_wready(100, wait_result); // C2: explicit wready check tb_assert(wait_result[1] === 1'b1, "wready asserted after write to ADDR 7", $sformatf("wait_result = %b", wait_result)); spi_read(mk_read(7'd7), rdata); tb_assert(rdata[23:0] === (24'hCAFEBE >> 8), "Interleaved: ADDR 7 correct", ""); #(`SPI_CLK_PERIOD); end endtask //========================================================================== // Test 6: Error Conditions //========================================================================== task test_error_conditions; reg [31:0] rdata; reg [1:0] wait_result; begin test_case_num = test_case_num + 1; $display(""); $display("-------------------------------------------------------------"); $display(" Test 6: Error Conditions"); $display("-------------------------------------------------------------"); // 6a. Read out-of-bounds address (ADDR 16) $display(" 6a. Read ADDR 16 (out of bounds)"); tb_assert(o_err === 1'b0, // W1: pre-check o_err is cleared before test "o_err should be low before Test 6a", $sformatf("o_err = %b", o_err)); spi_read(mk_read(7'd16), rdata); @(negedge i_sclk); #(`SYS_CLK_PERIOD * 5); tb_assert(o_err === 1'b1, "o_err HIGH after reading ADDR 16", ""); i_rst_n = 1'b0; #(`SYS_CLK_PERIOD * 4); i_rst_n = 1'b1; #(`SYS_CLK_PERIOD * 4); tb_assert(o_err === 1'b0, "o_err cleared after reset", ""); // 6b. Write to out-of-bounds address (ADDR 31) $display(" 6b. Write ADDR 31 (out of bounds)"); tb_assert(o_err === 1'b0, // W1: pre-check o_err is cleared before test "o_err should be low before Test 6b", $sformatf("o_err = %b", o_err)); spi_write(mk_write(7'd31, 24'h123456)); wait_wready(100, wait_result); // C2: explicit wready check #(`SYS_CLK_PERIOD * 5); tb_assert(o_err === 1'b1, "o_err HIGH after writing ADDR 31", ""); i_rst_n = 1'b0; #(`SYS_CLK_PERIOD * 4); i_rst_n = 1'b1; #(`SYS_CLK_PERIOD * 4); tb_assert(o_err === 1'b0, "o_err cleared after reset", ""); // 6c. Short SPI transaction (16 bits) $display(" 6c. Short SPI transaction (16 bits)"); tb_assert(o_err === 1'b0, // W1: pre-check o_err is cleared before test "o_err should be low before Test 6c", $sformatf("o_err = %b", o_err)); i_cs = 1'b0; #(`SYS_CLK_PERIOD * 2); // W4: allow BUS_Con sync chain to settle @(negedge i_sclk); @(negedge i_sclk); for (integer bi = 0; bi < 16; bi = bi + 1) begin i_mosi = 1'b0; @(posedge i_sclk); @(negedge i_sclk); end i_cs = 1'b1; @(negedge i_sclk); #(`SYS_CLK_PERIOD * 5); tb_assert(o_err === 1'b1, "o_err HIGH after short SPI transaction", ""); i_rst_n = 1'b0; #(`SYS_CLK_PERIOD * 4); i_rst_n = 1'b1; #(`SYS_CLK_PERIOD * 4); tb_assert(o_err === 1'b0, "o_err cleared after reset", ""); // 6d. Brief CS pulse (too short) $display(" 6d. Brief CS pulse"); tb_assert(o_err === 1'b0, // W1: pre-check o_err is cleared before test "o_err should be low before Test 6d", $sformatf("o_err = %b", o_err)); i_cs = 1'b0; #(`SYS_CLK_PERIOD * 2); // W4: allow BUS_Con sync chain to settle @(negedge i_sclk); @(negedge i_sclk); i_cs = 1'b1; @(negedge i_sclk); #(`SYS_CLK_PERIOD * 5); tb_assert(o_err === 1'b1, "o_err detected brief CS pulse", ""); i_rst_n = 1'b0; #(`SYS_CLK_PERIOD * 4); i_rst_n = 1'b1; #(`SYS_CLK_PERIOD * 4); tb_assert(o_err === 1'b0, "o_err cleared after reset", ""); #(`SPI_CLK_PERIOD * 2); end endtask //========================================================================== // Test 7: MISO Tri-State Behavior //========================================================================== task test_miso_tri_state; begin test_case_num = test_case_num + 1; $display(""); $display("-------------------------------------------------------------"); $display(" Test 7: MISO Tri-State Behavior"); $display("-------------------------------------------------------------"); // 7a. MISO is high-Z when CS is HIGH $display(" 7a. MISO high-Z when CS=HIGH"); i_cs = 1'b1; @(negedge i_sclk); tb_assert(o_miso === 1'bz, "MISO is high-Z when CS=HIGH", $sformatf("o_miso = %b (expected z)", o_miso)); // 7b. MISO is active when CS is LOW $display(" 7b. MISO active when CS=LOW"); i_cs = 1'b0; @(negedge i_sclk); tb_assert(o_miso !== 1'bz, "MISO is active (not high-Z) when CS=LOW", ""); // 7c. MISO returns to high-Z when CS goes HIGH again $display(" 7c. MISO returns to high-Z when CS=HIGH"); i_cs = 1'b1; @(negedge i_sclk); tb_assert(o_miso === 1'bz, "MISO returns to high-Z when CS=HIGH", $sformatf("o_miso = %b (expected z)", o_miso)); #(`SPI_CLK_PERIOD); end endtask //========================================================================== // Test 8: o_con_done Execution Flow (S3) //========================================================================== task test_con_done_flow; reg [31:0] rdata; reg [1:0] wait_result; begin test_case_num = test_case_num + 1; $display(""); $display("-------------------------------------------------------------"); $display(" Test 8: o_con_done Execution Flow"); $display("-------------------------------------------------------------"); // 8a. Write EXEC bit to ADDR 1 (STATE_REG), then verify o_con_done $display(" 8a. Write EXEC bit, wait for o_con_done"); spi_write(mk_write(7'd1, 24'h800001)); // Set EXEC bit wait_wready(100, wait_result); tb_assert(wait_result[1] === 1'b1, "wready asserted after EXEC write", $sformatf("wait_result = %b", wait_result)); // Wait for o_con_done to go high (controller execution complete) // Poll o_con_done for up to 500 system clock cycles begin integer j; reg found; found = 1'b0; for (j = 0; j < 500; j = j + 1) begin #(`SYS_CLK_PERIOD); if (o_con_done === 1'b1 && found === 1'b0) begin tb_assert(1'b1, "o_con_done asserted within 500 sys clock cycles", ""); found = 1'b1; end end tb_assert(found === 1'b1, "o_con_done not asserted within 500 sys clock cycles", ""); end // 8b. Read back ADDR 1 to verify STATE bit changed $display(" 8b. Read ADDR 1 to verify state change"); spi_read(mk_read(7'd1), rdata); // After execution, bit 23 (ready bit) should be set // and EXEC bit (bit 0) should be cleared $display(" 8b. ADDR 1 read value = 0x%06h", rdata[23:0]); #(`SPI_CLK_PERIOD); end endtask //========================================================================== // Summary //========================================================================== task print_summary; begin $display(""); $display("============================================================="); $display(" Test Summary"); $display("============================================================="); $display(" Test cases run: %0d", test_case_num); $display(" Total assertions: %0d", test_pass + test_fail); $display(" Passed: %0d", test_pass); $display(" Failed: %0d", test_fail); $display("============================================================="); if (test_fail == 0) begin $display(" *** ALL TESTS PASSED ***"); end else begin $display(" *** SOME TESTS FAILED - CHECK DESIGN ***"); end $display("============================================================="); $display(""); end endtask endmodule