Merge branch 'spi_debug'

This commit is contained in:
naichewa 2024-09-03 15:00:59 -07:00
commit 58be9e0556
6 changed files with 190 additions and 13 deletions

View File

@ -59,6 +59,16 @@ SDC_SUPPORTED 1
PLIC_SDC_ID 32'd20 PLIC_SDC_ID 32'd20
BPRED_SIZE 32'd12 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. # The syn configurations are trimmed down for faster synthesis.
deriv syn_rv32e rv32e deriv syn_rv32e rv32e
DTIM_RANGE 64'h1FF DTIM_RANGE 64'h1FF

View File

@ -100,7 +100,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
rsrstatetype ReceiveState; rsrstatetype ReceiveState;
// Transmission signals // Transmission signals
// logic sck; logic ZeroDiv; // High when SckDiv is 0
logic [11:0] DivCounter; // Counter for sck logic [11:0] DivCounter; // Counter for sck
logic SCLKenable; // Flip flop enable high every sclk edge 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 logic ZeroDelayHoldMode; // High when ChipSelectMode is hold and Delay1[15:8] (InterXFR delay) is 0
// Frame counting signals // Frame counting signals
logic FirstFrame;
logic [3:0] FrameCount; // Counter for number of frames in transmission logic [3:0] FrameCount; // Counter for number of frames in transmission
logic ReceivePenultimateFrame; // High when penultimate frame in transmission has been reached 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 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 [7:0] TransmitDataEndian; // Reverses TransmitData from txFIFO if littleendian, since TransmitReg always shifts MSB
logic TransmitShiftRegLoad; // Determines when to load TransmitShiftReg 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 ReceiveShiftFull; // High when receive shift register is full
logic TransmitShiftEmpty; // High when transmit shift register is empty logic TransmitShiftEmpty; // High when transmit shift register is empty
logic ShiftIn; // Determines whether to shift from SPIIn or SPIOut (if SPI_LOOPBACK_TEST) 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 [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 // CS signals
logic [3:0] ChipSelectAuto; // Assigns ChipSelect value to selected CS signal based on CS ID 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 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 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 // APB access
assign Entry = {PADDR[7:2],2'b00}; // 32-bit word-aligned accesses assign Entry = {PADDR[7:2],2'b00}; // 32-bit word-aligned accesses
assign Memwrite = PWRITE & PENABLE & PSEL; // Only write in access phase 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)) // 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 // 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 // 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); assign SCLKenableEarly = ((DivCounter + 12'b1) == SckDiv);
always_ff @(posedge PCLK) always_ff @(posedge PCLK)
if (~PRESETn) DivCounter <= '0; 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 // Asserts when transmission is one frame before complete
assign ReceivePenultimateFrame = ((FrameCount + 4'b0001) == Format[4:1]); assign ReceivePenultimateFrame = ((FrameCount + 4'b0001) == Format[4:1]);
assign FirstFrame = (FrameCount == 4'b0);
// Computing delays // Computing delays
// When sckmode.pha = 0, an extra half-period delay is implicit in the cs-sck delay, and vice-versa for sck-cs // 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) always_ff @(posedge PCLK)
if (~PRESETn) ReceiveFIFOReadIncrement <= 1'b0; if (~PRESETn) ReceiveFIFOReadIncrement <= 1'b0;
else ReceiveFIFOReadIncrement <= ((Entry == SPI_RXDATA) & ~ReceiveFIFOReadEmpty & PSEL & ~ReceiveFIFOReadIncrement); 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 // 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); TransmitFIFOReadData[7:0], TransmitFIFOWriteFull, TransmitFIFOReadEmpty, TransmitWriteMark, TransmitReadMark);
spi_fifo #(3,8) rxFIFO(PCLK, SCLKenable, 1'b1, PRESETn, ReceiveShiftFullDelay, ReceiveFIFOReadIncrement, ReceiveShiftRegEndian, ReceiveWatermark[2:0], ReceiveReadWatermarkLevel, spi_fifo #(3,8) rxFIFO(PCLK, SCLKenable, 1'b1, PRESETn, ReceiveShiftFullDelay, ReceiveFIFOReadIncrement, ReceiveShiftRegEndian, ReceiveWatermark[2:0], ReceiveReadWatermarkLevel,
ReceiveData[7:0], ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty, RecieveWriteMark, RecieveReadMark); 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; if (~PRESETn) ReceiveShiftFullDelayPCLK <= 1'b0;
else if (SCLKenableEarly) ReceiveShiftFullDelayPCLK <= ReceiveShiftFull; 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 // 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; 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; FrameCount <= 4'b0;
InterCSCount <= 9'b10; InterCSCount <= 9'b10;
InterXFRCount <= InterXFRCount + 9'b1; 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; state <= ACTIVE_0;
SPICLK <= ~SckMode[1]; SPICLK <= ~SckMode[1];
end else if (~|ChipSelectMode[1:0]) state <= CS_INACTIVE; 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 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 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 Active0 = (state == ACTIVE_0);
assign ShiftEdgeSPICLK = ZeroDiv ? ~SPICLK : SPICLK;
// Signal tracks which edge of sck to shift data // Signal tracks which edge of sck to shift data
always_comb always_comb
case(SckMode[1:0]) case(SckMode[1:0])
2'b00: ShiftEdge = SPICLK & SCLKenable; 2'b00: ShiftEdge = ShiftEdgeSPICLK & SCLKenable;
2'b01: ShiftEdge = (~SPICLK & (|(FrameCount) | (CS_SCKCount >= (({Delay0[7:0], 1'b0}) + ImplicitDelay1))) & SCLKenable & (FrameCount != Format[4:1]) & ~TransmitInactive); 2'b01: ShiftEdge = (~ShiftEdgeSPICLK & ~FirstFrame & (|(FrameCount) | (CS_SCKCount >= (({Delay0[7:0], 1'b0}) + ImplicitDelay1))) & SCLKenable & (FrameCount != Format[4:1]) & ~TransmitInactive);
2'b10: ShiftEdge = ~SPICLK & SCLKenable; 2'b10: ShiftEdge = ~ShiftEdgeSPICLK & SCLKenable;
2'b11: ShiftEdge = (SPICLK & (|(FrameCount) | (CS_SCKCount >= (({Delay0[7:0], 1'b0}) + ImplicitDelay1))) & SCLKenable & (FrameCount != Format[4:1]) & ~TransmitInactive); 2'b11: ShiftEdge = (ShiftEdgeSPICLK & ~FirstFrame & (|(FrameCount) | (CS_SCKCount >= (({Delay0[7:0], 1'b0}) + ImplicitDelay1))) & SCLKenable & (FrameCount != Format[4:1]) & ~TransmitInactive);
default: ShiftEdge = SPICLK & SCLKenable; default: ShiftEdge = ShiftEdgeSPICLK & SCLKenable;
endcase endcase
// Transmit shift register // 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]; 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) always_ff @(posedge PCLK)
if(~PRESETn) TransmitShiftReg <= 8'b0; 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]}; else if (ShiftEdge & Active) TransmitShiftReg <= {TransmitShiftReg[6:0], TransmitShiftReg[0]};
assign SPIOut = TransmitShiftReg[7]; assign SPIOut = TransmitShiftReg[7];

View File

@ -84,6 +84,38 @@
000000FF 000000FF
000000AE
000000AD
000000AC
000000AB
000000AE
000000AD
000000AC
000000AB
000000AE
000000AD
000000AC
000000AB
000000AE
000000AD
000000AC
000000AB
000000A0 000000A0
0000000B 0000000B

View File

@ -162,6 +162,45 @@ test_cases:
.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end .4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.4byte rx_data, 0x000000FF, read32_test # read rx_data .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 # Test phase
.4byte sck_div, 0x00000003, write32_test # reset sck_div to 0x03 so only sck_mode is different .4byte sck_div, 0x00000003, write32_test # reset sck_div to 0x03 so only sck_mode is different

View File

@ -84,6 +84,38 @@
00000000 00000000
000000FF 000000FF
00000000 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 000000A0
00000000 00000000
0000000B 0000000B

View File

@ -164,6 +164,47 @@ test_cases:
.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end .8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x000000FF, read32_test # read rx_data .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 # Test phase
.8byte sck_div, 0x00000003, write32_test # reset sck_div to 0x03 so only sck_mode is different .8byte sck_div, 0x00000003, write32_test # reset sck_div to 0x03 so only sck_mode is different