From 3b7661dfd5df53e26a9610911547305644b625cd Mon Sep 17 00:00:00 2001 From: naichewa Date: Tue, 3 Sep 2024 14:58:46 -0700 Subject: [PATCH] SckDiv Zero bug fixes --- config/derivlist.txt | 10 ++++ src/uncore/spi_apb.sv | 49 ++++++++++++++----- .../references/WALLY-spi-01.reference_output | 32 ++++++++++++ .../rv32i_m/privilege/src/WALLY-spi-01.S | 39 +++++++++++++++ .../references/WALLY-spi-01.reference_output | 32 ++++++++++++ .../rv64i_m/privilege/src/WALLY-spi-01.S | 41 ++++++++++++++++ 6 files changed, 190 insertions(+), 13 deletions(-) diff --git a/config/derivlist.txt b/config/derivlist.txt index ab9ee703f..73b59a6be 100644 --- a/config/derivlist.txt +++ b/config/derivlist.txt @@ -59,6 +59,16 @@ SDC_SUPPORTED 1 PLIC_SDC_ID 32'd20 BPRED_SIZE 32'd12 +# temporary spitest configuration +deriv spitest rv64gc +UNCORE_RAM_RANGE 64'h0FFFFFFF +SPI_LOOPBACK_TEST 1 +UART_PRESCALE 32'd0 +PLIC_NUM_SRC 32'd53 +SDC_SUPPORTED 1 +PLIC_SDC_ID 32'd20 +BPRED_SIZE 32'd12 + # The syn configurations are trimmed down for faster synthesis. deriv syn_rv32e rv32e DTIM_RANGE 64'h1FF diff --git a/src/uncore/spi_apb.sv b/src/uncore/spi_apb.sv index 0701956a3..4c2cea733 100644 --- a/src/uncore/spi_apb.sv +++ b/src/uncore/spi_apb.sv @@ -100,7 +100,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( rsrstatetype ReceiveState; // Transmission signals - // logic sck; + logic ZeroDiv; // High when SckDiv is 0 logic [11:0] DivCounter; // Counter for sck logic SCLKenable; // Flip flop enable high every sclk edge @@ -114,6 +114,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( logic ZeroDelayHoldMode; // High when ChipSelectMode is hold and Delay1[15:8] (InterXFR delay) is 0 // Frame counting signals + logic FirstFrame; logic [3:0] FrameCount; // Counter for number of frames in transmission logic ReceivePenultimateFrame; // High when penultimate frame in transmission has been reached @@ -128,11 +129,15 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( logic SampleEdge; // Determines which edge of sck to sample from ReceiveShiftReg logic [7:0] TransmitDataEndian; // Reverses TransmitData from txFIFO if littleendian, since TransmitReg always shifts MSB logic TransmitShiftRegLoad; // Determines when to load TransmitShiftReg + logic TransmitShiftRegLoadSingleCycle; // Version of TransmitShiftRegLoad which is only high for a single SCLK cycle to prevent double loads + logic TransmitShiftRegLoadDelay; // TransmitShiftRegLoad delayed by an SCLK cycle, inverted and anded with TransmitShiftRegLoad to create a single cycle signal + logic TransmitFIFOReadIncrement; // Increments Tx FIFO read ptr 1 cycle after Tx FIFO is read logic ReceiveShiftFull; // High when receive shift register is full logic TransmitShiftEmpty; // High when transmit shift register is empty logic ShiftIn; // Determines whether to shift from SPIIn or SPIOut (if SPI_LOOPBACK_TEST) logic [3:0] LeftShiftAmount; // Determines left shift amount to left-align data when little endian - logic [7:0] ASR; // AlignedReceiveShiftReg + logic [7:0] ASR; // AlignedReceiveShiftReg + logic ShiftEdgeSPICLK; // Changes ShiftEdge when SckDiv is 0 // CS signals logic [3:0] ChipSelectAuto; // Assigns ChipSelect value to selected CS signal based on CS ID @@ -145,6 +150,10 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( logic TransmitFIFOReadEmptyDelay; logic SCLKenableEarly; // SCLKenable 1 PCLK cycle early, needed for on time register changes when ChipSelectMode is hold and Delay1[15:8] (InterXFR delay) is 0 + + + + // APB access assign Entry = {PADDR[7:2],2'b00}; // 32-bit word-aligned accesses assign Memwrite = PWRITE & PENABLE & PSEL; // Only write in access phase @@ -225,7 +234,9 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( // SPI enable generation, where SCLK = PCLK/(2*(SckDiv + 1)) // Asserts SCLKenable at the rising and falling edge of SCLK by counting from 0 to SckDiv // Active at 2x SCLK frequency to account for implicit half cycle delays and actions on both clock edges depending on phase - assign SCLKenable = (DivCounter == SckDiv); + // When SckDiv is 0, count doesn't work and SCLKenable is simply PCLK + assign ZeroDiv = ~|(SckDiv[10:0]); + assign SCLKenable = ZeroDiv ? PCLK : (DivCounter == SckDiv); assign SCLKenableEarly = ((DivCounter + 12'b1) == SckDiv); always_ff @(posedge PCLK) if (~PRESETn) DivCounter <= '0; @@ -234,6 +245,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( // Asserts when transmission is one frame before complete assign ReceivePenultimateFrame = ((FrameCount + 4'b0001) == Format[4:1]); + assign FirstFrame = (FrameCount == 4'b0); // Computing delays // When sckmode.pha = 0, an extra half-period delay is implicit in the cs-sck delay, and vice-versa for sck-cs @@ -276,9 +288,18 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( always_ff @(posedge PCLK) if (~PRESETn) ReceiveFIFOReadIncrement <= 1'b0; else ReceiveFIFOReadIncrement <= ((Entry == SPI_RXDATA) & ~ReceiveFIFOReadEmpty & PSEL & ~ReceiveFIFOReadIncrement); - + + assign TransmitShiftRegLoad = ~TransmitShiftEmpty & ~Active | (((ChipSelectMode == 2'b10) & ~|(Delay1[15:8])) & ((ReceiveShiftFullDelay | ReceiveShiftFull) & ~SampleEdge & ~TransmitFIFOReadEmpty)); + + always_ff @(posedge PCLK) + if (~PRESETn) TransmitShiftRegLoadDelay <=0; + else if (SCLKenable) TransmitShiftRegLoadDelay <= TransmitShiftRegLoad; + assign TransmitShiftRegLoadSingleCycle = TransmitShiftRegLoad & ~TransmitShiftRegLoadDelay; + always_ff @(posedge PCLK) + if (~PRESETn) TransmitFIFOReadIncrement <= 0; + else if (SCLKenable) TransmitFIFOReadIncrement <= TransmitShiftRegLoadSingleCycle; // Tx/Rx FIFOs - spi_fifo #(3,8) txFIFO(PCLK, 1'b1, SCLKenable, PRESETn, TransmitFIFOWriteIncrement, TransmitShiftEmpty, TransmitData[7:0], TransmitWriteWatermarkLevel, TransmitWatermark[2:0], + spi_fifo #(3,8) txFIFO(PCLK, 1'b1, SCLKenable, PRESETn, TransmitFIFOWriteIncrement, TransmitFIFOReadIncrement, TransmitData[7:0], TransmitWriteWatermarkLevel, TransmitWatermark[2:0], TransmitFIFOReadData[7:0], TransmitFIFOWriteFull, TransmitFIFOReadEmpty, TransmitWriteMark, TransmitReadMark); spi_fifo #(3,8) rxFIFO(PCLK, SCLKenable, 1'b1, PRESETn, ReceiveShiftFullDelay, ReceiveFIFOReadIncrement, ReceiveShiftRegEndian, ReceiveWatermark[2:0], ReceiveReadWatermarkLevel, ReceiveData[7:0], ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty, RecieveWriteMark, RecieveReadMark); @@ -294,7 +315,8 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( if (~PRESETn) ReceiveShiftFullDelayPCLK <= 1'b0; else if (SCLKenableEarly) ReceiveShiftFullDelayPCLK <= ReceiveShiftFull; - assign TransmitShiftRegLoad = ~TransmitShiftEmpty & ~Active | (((ChipSelectMode == 2'b10) & ~|(Delay1[15:8])) & ((ReceiveShiftFullDelay | ReceiveShiftFull) & ~SampleEdge & ~TransmitFIFOReadEmpty)); + + // Main FSM which controls SPI transmission typedef enum logic [2:0] {CS_INACTIVE, DELAY_0, ACTIVE_0, ACTIVE_1, DELAY_1,INTER_CS, INTER_XFR} statetype; @@ -365,7 +387,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( FrameCount <= 4'b0; InterCSCount <= 9'b10; InterXFRCount <= InterXFRCount + 9'b1; - if ((InterXFRCount >= ({Delay1[15:8], 1'b0})) & ~TransmitFIFOReadEmptyDelay) begin + if ((InterXFRCount >= ({Delay1[15:8], 1'b0})) & (~TransmitFIFOReadEmptyDelay | ~TransmitShiftEmpty)) begin state <= ACTIVE_0; SPICLK <= ~SckMode[1]; end else if (~|ChipSelectMode[1:0]) state <= CS_INACTIVE; @@ -384,22 +406,23 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( assign ZeroDelayHoldMode = ((ChipSelectMode == 2'b10) & (~|(Delay1[7:4]))); assign TransmitInactive = ((state == INTER_CS) | (state == CS_INACTIVE) | (state == INTER_XFR) | (ReceiveShiftFullDelayPCLK & ZeroDelayHoldMode) | ((state == ACTIVE_1) & ((ChipSelectMode[1:0] == 2'b10) & ~|(Delay1[15:8]) & (~TransmitFIFOReadEmpty) & (FrameCount == Format[4:1])))); assign Active0 = (state == ACTIVE_0); + assign ShiftEdgeSPICLK = ZeroDiv ? ~SPICLK : SPICLK; // Signal tracks which edge of sck to shift data always_comb case(SckMode[1:0]) - 2'b00: ShiftEdge = SPICLK & SCLKenable; - 2'b01: ShiftEdge = (~SPICLK & (|(FrameCount) | (CS_SCKCount >= (({Delay0[7:0], 1'b0}) + ImplicitDelay1))) & SCLKenable & (FrameCount != Format[4:1]) & ~TransmitInactive); - 2'b10: ShiftEdge = ~SPICLK & SCLKenable; - 2'b11: ShiftEdge = (SPICLK & (|(FrameCount) | (CS_SCKCount >= (({Delay0[7:0], 1'b0}) + ImplicitDelay1))) & SCLKenable & (FrameCount != Format[4:1]) & ~TransmitInactive); - default: ShiftEdge = SPICLK & SCLKenable; + 2'b00: ShiftEdge = ShiftEdgeSPICLK & SCLKenable; + 2'b01: ShiftEdge = (~ShiftEdgeSPICLK & ~FirstFrame & (|(FrameCount) | (CS_SCKCount >= (({Delay0[7:0], 1'b0}) + ImplicitDelay1))) & SCLKenable & (FrameCount != Format[4:1]) & ~TransmitInactive); + 2'b10: ShiftEdge = ~ShiftEdgeSPICLK & SCLKenable; + 2'b11: ShiftEdge = (ShiftEdgeSPICLK & ~FirstFrame & (|(FrameCount) | (CS_SCKCount >= (({Delay0[7:0], 1'b0}) + ImplicitDelay1))) & SCLKenable & (FrameCount != Format[4:1]) & ~TransmitInactive); + default: ShiftEdge = ShiftEdgeSPICLK & SCLKenable; endcase // Transmit shift register assign TransmitDataEndian = Format[0] ? {TransmitFIFOReadData[0], TransmitFIFOReadData[1], TransmitFIFOReadData[2], TransmitFIFOReadData[3], TransmitFIFOReadData[4], TransmitFIFOReadData[5], TransmitFIFOReadData[6], TransmitFIFOReadData[7]} : TransmitFIFOReadData[7:0]; always_ff @(posedge PCLK) if(~PRESETn) TransmitShiftReg <= 8'b0; - else if (TransmitShiftRegLoad) TransmitShiftReg <= TransmitDataEndian; + else if (TransmitShiftRegLoadSingleCycle) TransmitShiftReg <= TransmitDataEndian; else if (ShiftEdge & Active) TransmitShiftReg <= {TransmitShiftReg[6:0], TransmitShiftReg[0]}; assign SPIOut = TransmitShiftReg[7]; diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/references/WALLY-spi-01.reference_output b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/references/WALLY-spi-01.reference_output index b006e3229..f62d9b088 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/references/WALLY-spi-01.reference_output +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/references/WALLY-spi-01.reference_output @@ -84,6 +84,38 @@ 000000FF +000000AE + +000000AD + +000000AC + +000000AB + +000000AE + +000000AD + +000000AC + +000000AB + +000000AE + +000000AD + +000000AC + +000000AB + +000000AE + +000000AD + +000000AC + +000000AB + 000000A0 0000000B diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-spi-01.S b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-spi-01.S index 68d3785e8..4048c4c4c 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-spi-01.S +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-spi-01.S @@ -162,6 +162,45 @@ test_cases: .4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end .4byte rx_data, 0x000000FF, read32_test # read rx_data +# Test min sck_div + +.4byte sck_div, 0x000000000, write32_test #set sck_div to 0 +.4byte tx_data, 0xABACADAE, spi_burst_send +.4byte 0x0, 0x00000003, spi_data_wait +.4byte rx_data, 0x000000AE, read32_test +.4byte rx_data, 0x000000AD, read32_test +.4byte rx_data, 0x000000AC, read32_test +.4byte rx_data, 0x000000AB, read32_test + +# min sck_div, sckmode 01 + +.4byte sck_mode, 0x00000001, write32_test +.4byte tx_data, 0xABACADAE, spi_burst_send +.4byte 0x0, 0x00000003, spi_data_wait +.4byte rx_data, 0x000000AE, read32_test +.4byte rx_data, 0x000000AD, read32_test +.4byte rx_data, 0x000000AC, read32_test +.4byte rx_data, 0x000000AB, read32_test + +#min sck_div, sckmode 10 +.4byte sck_mode, 0x00000002, write32_test +.4byte tx_data, 0xABACADAE, spi_burst_send +.4byte 0x0, 0x00000003, spi_data_wait +.4byte rx_data, 0x000000AE, read32_test +.4byte rx_data, 0x000000AD, read32_test +.4byte rx_data, 0x000000AC, read32_test +.4byte rx_data, 0x000000AB, read32_test + +#min sck_div, sckmode 11 +.4byte sck_mode, 0x00000003, write32_test +.4byte tx_data, 0xABACADAE, spi_burst_send +.4byte 0x0, 0x00000003, spi_data_wait +.4byte rx_data, 0x000000AE, read32_test +.4byte rx_data, 0x000000AD, read32_test +.4byte rx_data, 0x000000AC, read32_test +.4byte rx_data, 0x000000AB, read32_test + + # Test phase .4byte sck_div, 0x00000003, write32_test # reset sck_div to 0x03 so only sck_mode is different diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-spi-01.reference_output b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-spi-01.reference_output index 673395696..7520479ce 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-spi-01.reference_output +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-spi-01.reference_output @@ -84,6 +84,38 @@ 00000000 000000FF 00000000 +000000AE +00000000 +000000AD +00000000 +000000AC +00000000 +000000AB +00000000 +000000AE +00000000 +000000AD +00000000 +000000AC +00000000 +000000AB +00000000 +000000AE +00000000 +000000AD +00000000 +000000AC +00000000 +000000AB +00000000 +000000AE +00000000 +000000AD +00000000 +000000AC +00000000 +000000AB +00000000 000000A0 00000000 0000000B diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S index 21b38f9b8..2a04f02f0 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S @@ -164,6 +164,47 @@ test_cases: .8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end .8byte rx_data, 0x000000FF, read32_test # read rx_data +# Test min sck_div + +.8byte sck_div, 0x000000000, write32_test #set sck_div to 0 +.8byte tx_data, 0xABACADAE, spi_burst_send +.8byte 0x0, 0x00000003, spi_data_wait +.8byte rx_data, 0x000000AE, read32_test +.8byte rx_data, 0x000000AD, read32_test +.8byte rx_data, 0x000000AC, read32_test +.8byte rx_data, 0x000000AB, read32_test + +# min sck_div, sckmode 01 + +.8byte sck_mode, 0x00000001, write32_test +.8byte tx_data, 0xABACADAE, spi_burst_send +.8byte 0x0, 0x00000003, spi_data_wait +.8byte rx_data, 0x000000AE, read32_test +.8byte rx_data, 0x000000AD, read32_test +.8byte rx_data, 0x000000AC, read32_test +.8byte rx_data, 0x000000AB, read32_test + +#min sck_div, sckmode 10 +.8byte sck_mode, 0x00000002, write32_test +.8byte tx_data, 0xABACADAE, spi_burst_send +.8byte 0x0, 0x00000003, spi_data_wait +.8byte rx_data, 0x000000AE, read32_test +.8byte rx_data, 0x000000AD, read32_test +.8byte rx_data, 0x000000AC, read32_test +.8byte rx_data, 0x000000AB, read32_test + +#min sck_div, sckmode 11 +.8byte sck_mode, 0x00000003, write32_test +.8byte tx_data, 0xABACADAE, spi_burst_send +.8byte 0x0, 0x00000003, spi_data_wait +.8byte rx_data, 0x000000AE, read32_test +.8byte rx_data, 0x000000AD, read32_test +.8byte rx_data, 0x000000AC, read32_test +.8byte rx_data, 0x000000AB, read32_test + + + + # Test phase .8byte sck_div, 0x00000003, write32_test # reset sck_div to 0x03 so only sck_mode is different