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

View file

@ -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];

View file

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

View file

@ -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

View file

@ -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

View file

@ -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