mirror of
https://github.com/openhwgroup/cvw
synced 2025-02-11 06:05:49 +00:00
Refactored SPI peripheral based on SPI controller module. Works in tests/custom/spitest.
This commit is contained in:
parent
784630b945
commit
b667581ffa
@ -62,10 +62,6 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
||||
localparam SPI_IE = 8'h70;
|
||||
localparam SPI_IP = 8'h74;
|
||||
|
||||
// receive shift register states
|
||||
typedef enum logic [1:0] {ReceiveShiftFullState, ReceiveShiftNotFullState, ReceiveShiftDelayState} rsrstatetype;
|
||||
|
||||
|
||||
// SPI control registers. Refer to SiFive FU540-C000 manual
|
||||
logic [11:0] SckDiv;
|
||||
logic [1:0] SckMode;
|
||||
@ -75,89 +71,68 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
||||
logic [15:0] Delay0, Delay1;
|
||||
logic [4:0] Format;
|
||||
logic [7:0] ReceiveData;
|
||||
logic [2:0] TransmitWatermark, ReceiveWatermark;
|
||||
logic [8:0] TransmitData;
|
||||
logic [2:0] TransmitWatermark, ReceiveWatermark;
|
||||
logic [1:0] InterruptEnable, InterruptPending;
|
||||
|
||||
// Bus interface signals
|
||||
logic [7:0] Entry;
|
||||
logic Memwrite;
|
||||
logic [31:0] Din, Dout;
|
||||
logic TransmitInactive; // High when there is no transmission, used as hardware interlock signal
|
||||
|
||||
// SPI Controller signals
|
||||
logic SCLKenable;
|
||||
logic EndOfFrame;
|
||||
logic EndOfFrameDelay;
|
||||
logic Transmitting;
|
||||
logic InactiveState;
|
||||
|
||||
logic ResetSCLKenable;
|
||||
logic TransmitStart;
|
||||
|
||||
// Transmit Start State Machine Variables
|
||||
typedef enum logic [1:0] {READY, START, WAIT} txState;
|
||||
txState CurrState, NextState;
|
||||
|
||||
// FIFO FSM signals
|
||||
// Watermark signals - TransmitReadMark = ip[0], ReceiveWriteMark = ip[1]
|
||||
logic TransmitWriteMark, TransmitReadMark, RecieveWriteMark, RecieveReadMark;
|
||||
logic TransmitFIFOWriteFull, TransmitFIFOReadEmpty;
|
||||
logic TransmitFIFOWriteIncrement;
|
||||
logic ReceiveFiFoWriteInc;
|
||||
logic [7:0] TransmitFIFOReadData;
|
||||
|
||||
logic ReceiveFIFOWriteInc;
|
||||
logic ReceiveFIFOReadIncrement;
|
||||
logic ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty;
|
||||
logic [7:0] TransmitFIFOReadData;
|
||||
|
||||
/* verilator lint_off UNDRIVEN */
|
||||
logic [2:0] TransmitWriteWatermarkLevel, ReceiveReadWatermarkLevel; // unused generic FIFO outputs
|
||||
/* verilator lint_off UNDRIVEN */
|
||||
logic [7:0] ReceiveShiftRegEndian; // Reverses ReceiveShiftReg if Format[2] set (little endian transmission)
|
||||
rsrstatetype ReceiveState;
|
||||
logic ReceiveFiFoTakingData;
|
||||
|
||||
// Transmission signals
|
||||
logic ZeroDiv; // High when SckDiv is 0
|
||||
logic [11:0] DivCounter; // Counter for sck
|
||||
logic SCLKenable; // Flip flop enable high every sclk edge
|
||||
|
||||
// Delay signals
|
||||
logic [8:0] ImplicitDelay1; // Adds implicit delay to cs-sck delay counter based on phase
|
||||
logic [8:0] ImplicitDelay2; // Adds implicit delay to sck-cs delay counter based on phase
|
||||
logic [8:0] CS_SCKCount; // Counter for cs-sck delay
|
||||
logic [8:0] SCK_CSCount; // Counter for sck-cs delay
|
||||
logic [8:0] InterCSCount; // Counter for inter cs delay
|
||||
logic [8:0] InterXFRCount; // Counter for inter xfr delay
|
||||
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
|
||||
|
||||
// State fsm signals
|
||||
logic Active; // High when state is either Active1 or Active0 (during transmission)
|
||||
logic Active0; // High when state is Active0
|
||||
|
||||
// Shift reg signals
|
||||
logic ShiftEdge; // Determines which edge of sck to shift from TransmitShiftReg
|
||||
logic [7:0] TransmitShiftReg; // Transmit shift register
|
||||
logic [7:0] ReceiveShiftReg; // Receive shift register
|
||||
logic ShiftEdge; // Determines which edge of sck to shift from TransmitReg
|
||||
logic SampleEdge; // Determines which edge of sck to sample from ReceiveShiftReg
|
||||
logic [7:0] TransmitReg; // Transmit shift register
|
||||
logic [7:0] ReceiveShiftReg; // Receive shift register
|
||||
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 TransmitLoad; // Determines when to load TransmitReg
|
||||
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
|
||||
|
||||
// Shift stuff due to Format register?
|
||||
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 ShiftEdgeSPICLK; // Changes ShiftEdge when SckDiv is 0
|
||||
|
||||
// CS signals
|
||||
logic [3:0] ChipSelectAuto; // Assigns ChipSelect value to selected CS signal based on CS ID
|
||||
logic [3:0] ChipSelectInternal; // Defines what each ChipSelect signal should be based on transmission status and ChipSelectDef
|
||||
logic DelayMode; // Determines where to place implicit half cycle delay based on sck phase for CS assertion
|
||||
|
||||
// Miscellaneous signals delayed/early by 1 PCLK cycle
|
||||
logic ReceiveShiftFullDelay; // Delays ReceiveShiftFull signal by 1 PCLK cycle
|
||||
logic ReceiveShiftFullDelayPCLK; // ReceiveShiftFull delayed by 1 PCLK cycle
|
||||
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
|
||||
assign PREADY = Entry == SPI_TXDATA | Entry == SPI_RXDATA | Entry == SPI_IP | TransmitInactive; // Tie PREADY to transmission for hardware interlock
|
||||
// assign PREADY = Entry == SPI_TXDATA | Entry == SPI_RXDATA | Entry == SPI_IP;
|
||||
assign PREADY = 1'b1;
|
||||
|
||||
// Account for subword read/write circuitry
|
||||
// -- Note SPI registers are 32 bits no matter what; access them with LW SW.
|
||||
@ -183,10 +158,8 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
||||
InterruptEnable <= 2'b0;
|
||||
InterruptPending <= 2'b0;
|
||||
end else begin // writes
|
||||
|
||||
|
||||
/* verilator lint_off CASEINCOMPLETE */
|
||||
if (Memwrite & TransmitInactive)
|
||||
if (Memwrite)
|
||||
case(Entry) // flop to sample inputs
|
||||
SPI_SCKDIV: SckDiv <= Din[11:0];
|
||||
SPI_SCKMODE: SckMode <= Din[1:0];
|
||||
@ -234,227 +207,121 @@ 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
|
||||
// When SckDiv is 0, count doesn't work and SCLKenable is simply PCLK *** dh 10/26/24: this logic is seriously broken. SCLK is not scaled to PCLK/(2*(SckDiv + 1)). SCLKenableEarly doesn't work right for SckDiv=0
|
||||
assign ZeroDiv = ~|(SckDiv[10:0]);
|
||||
assign SCLKenable = ZeroDiv ? 1 : (DivCounter == SckDiv);
|
||||
assign SCLKenableEarly = ((DivCounter + 12'b1) == SckDiv);
|
||||
always_ff @(posedge PCLK)
|
||||
if (~PRESETn) DivCounter <= '0;
|
||||
else if (SCLKenable) DivCounter <= 12'b0;
|
||||
else DivCounter <= DivCounter + 12'b1;
|
||||
// When SckDiv is 0, count doesn't work and SCLKenable is simply PCLK *** dh 10/26/24: this logic is seriously broken. SCLK is not scaled to PCLK/(2*(SckDiv + 1)).
|
||||
|
||||
// Asserts when transmission is one frame before complete
|
||||
assign ReceivePenultimateFrame = ((FrameCount + 4'b0001) == Format[4:1]);
|
||||
assign FirstFrame = (FrameCount == 4'b0);
|
||||
// SPI Controller module -------------------------------------------
|
||||
// This module controls state and timing signals that drive the rest of this module
|
||||
assign ResetSCLKenable = Memwrite & (Entry == SPI_SCKDIV);
|
||||
|
||||
// Computing delays
|
||||
// When sckmode.pha = 0, an extra half-period delay is implicit in the cs-sck delay, and vice-versa for sck-cs
|
||||
assign ImplicitDelay1 = SckMode[0] ? 9'b0 : 9'b1;
|
||||
assign ImplicitDelay2 = SckMode[0] ? 9'b1 : 9'b0;
|
||||
|
||||
// Calculate when tx/rx shift registers are full/empty
|
||||
|
||||
// Transmit Shift FSM
|
||||
always_ff @(posedge PCLK)
|
||||
if (~PRESETn) TransmitShiftEmpty <= 1'b1;
|
||||
else if (TransmitShiftEmpty) begin
|
||||
if (TransmitFIFOReadEmpty | (~TransmitFIFOReadEmpty & (ReceivePenultimateFrame & Active0))) TransmitShiftEmpty <= 1'b1;
|
||||
else if (~TransmitFIFOReadEmpty) TransmitShiftEmpty <= 1'b0;
|
||||
end else begin
|
||||
if (ReceivePenultimateFrame & Active0) TransmitShiftEmpty <= 1'b1;
|
||||
else TransmitShiftEmpty <= 1'b0;
|
||||
end
|
||||
|
||||
// Receive Shift FSM
|
||||
always_ff @(posedge PCLK)
|
||||
if (~PRESETn) ReceiveState <= ReceiveShiftNotFullState;
|
||||
else if (SCLKenable) begin
|
||||
case (ReceiveState)
|
||||
ReceiveShiftFullState: ReceiveState <= ReceiveShiftNotFullState;
|
||||
ReceiveShiftNotFullState: if (ReceivePenultimateFrame & (SampleEdge)) ReceiveState <= ReceiveShiftDelayState;
|
||||
else ReceiveState <= ReceiveShiftNotFullState;
|
||||
ReceiveShiftDelayState: ReceiveState <= ReceiveShiftFullState;
|
||||
endcase
|
||||
end
|
||||
|
||||
assign ReceiveShiftFull = SckMode[0] ? (ReceiveState == ReceiveShiftFullState) : (ReceiveState == ReceiveShiftDelayState);
|
||||
|
||||
// Calculate tx/rx fifo write and recieve increment signals
|
||||
|
||||
always_ff @(posedge PCLK)
|
||||
if (~PRESETn) TransmitFIFOWriteIncrement <= 1'b0;
|
||||
else TransmitFIFOWriteIncrement <= (Memwrite & (Entry == SPI_TXDATA) & ~TransmitFIFOWriteFull);
|
||||
|
||||
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, 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, ReceiveFiFoWriteInc, ReceiveFIFOReadIncrement, ReceiveShiftRegEndian, ReceiveWatermark[2:0], ReceiveReadWatermarkLevel,
|
||||
ReceiveData[7:0], ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty, RecieveWriteMark, RecieveReadMark);
|
||||
|
||||
always_ff @(posedge PCLK)
|
||||
if (~PRESETn) TransmitFIFOReadEmptyDelay <= 1'b1;
|
||||
else if (SCLKenable) TransmitFIFOReadEmptyDelay <= TransmitFIFOReadEmpty;
|
||||
|
||||
always_ff @(posedge PCLK)
|
||||
if (~PRESETn) ReceiveShiftFullDelay <= 1'b0;
|
||||
else if (SCLKenable) ReceiveShiftFullDelay <= ReceiveShiftFull;
|
||||
|
||||
assign ReceiveFiFoTakingData = ReceiveFiFoWriteInc & ~ReceiveFIFOWriteFull;
|
||||
|
||||
always_ff @(posedge PCLK)
|
||||
if (~PRESETn) ReceiveFiFoWriteInc <= 1'b0;
|
||||
else if (SCLKenable & ReceiveShiftFull) ReceiveFiFoWriteInc <= 1'b1;
|
||||
else if (SCLKenable & ReceiveFiFoTakingData) ReceiveFiFoWriteInc <= 1'b0;
|
||||
always_ff @(posedge PCLK)
|
||||
if (~PRESETn) ReceiveShiftFullDelayPCLK <= 1'b0;
|
||||
else if (SCLKenableEarly) ReceiveShiftFullDelayPCLK <= ReceiveShiftFull;
|
||||
|
||||
|
||||
|
||||
|
||||
// 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;
|
||||
statetype state;
|
||||
spi_controller controller(PCLK, PRESETn,
|
||||
// Transmit Signals
|
||||
TransmitStart, ResetSCLKenable,
|
||||
// Register Inputs
|
||||
SckDiv, SckMode, ChipSelectMode, Delay0, Delay1,
|
||||
// txFIFO stuff
|
||||
TransmitFIFOReadEmpty,
|
||||
// Timing
|
||||
SCLKenable, ShiftEdge, SampleEdge, EndOfFrame, EndOfFrameDelay,
|
||||
// State stuff
|
||||
Transmitting, InactiveState,
|
||||
// Outputs
|
||||
SPICLK);
|
||||
|
||||
// Transmit FIFO ---------------------------------------------------
|
||||
always_ff @(posedge PCLK)
|
||||
if (~PRESETn) begin
|
||||
state <= CS_INACTIVE;
|
||||
FrameCount <= 4'b0;
|
||||
SPICLK <= SckMode[1];
|
||||
TransmitFIFOWriteIncrement <= 1'b0;
|
||||
TransmitFIFOReadIncrement <= 1'b0;
|
||||
end else begin
|
||||
TransmitFIFOWriteIncrement <= (Memwrite & (Entry == SPI_TXDATA) & ~TransmitFIFOWriteFull);
|
||||
TransmitFIFOReadIncrement <= TransmitLoad;
|
||||
end
|
||||
|
||||
// Setup TransmitStart state machine
|
||||
always_ff @(posedge PCLK) begin
|
||||
if (~PRESETn) begin
|
||||
CurrState <= READY;
|
||||
end else if (SCLKenable) begin
|
||||
/* verilator lint_off CASEINCOMPLETE */
|
||||
case (state)
|
||||
CS_INACTIVE: begin
|
||||
CS_SCKCount <= 9'b1;
|
||||
SCK_CSCount <= 9'b10;
|
||||
FrameCount <= 4'b0;
|
||||
InterCSCount <= 9'b10;
|
||||
InterXFRCount <= 9'b1;
|
||||
if ((~TransmitFIFOReadEmpty | ~TransmitShiftEmpty) & ((|(Delay0[7:0])) | ~SckMode[0])) state <= DELAY_0;
|
||||
else if ((~TransmitFIFOReadEmpty | ~TransmitShiftEmpty)) begin
|
||||
state <= ACTIVE_0;
|
||||
SPICLK <= ~SckMode[1];
|
||||
end else SPICLK <= SckMode[1];
|
||||
end
|
||||
DELAY_0: begin
|
||||
CS_SCKCount <= CS_SCKCount + 9'b1;
|
||||
if (CS_SCKCount >= (({Delay0[7:0], 1'b0}) + ImplicitDelay1)) begin
|
||||
state <= ACTIVE_0;
|
||||
SPICLK <= ~SckMode[1];
|
||||
CurrState <= NextState;
|
||||
end
|
||||
end
|
||||
ACTIVE_0: begin
|
||||
FrameCount <= FrameCount + 4'b1;
|
||||
SPICLK <= SckMode[1];
|
||||
state <= ACTIVE_1;
|
||||
end
|
||||
ACTIVE_1: begin
|
||||
InterXFRCount <= 9'b1;
|
||||
if (FrameCount < Format[4:1]) begin
|
||||
state <= ACTIVE_0;
|
||||
SPICLK <= ~SckMode[1];
|
||||
end
|
||||
else if ((ChipSelectMode[1:0] == 2'b10) & ~|(Delay1[15:8]) & (~TransmitFIFOReadEmpty)) begin
|
||||
state <= ACTIVE_0;
|
||||
SPICLK <= ~SckMode[1];
|
||||
CS_SCKCount <= 9'b1;
|
||||
SCK_CSCount <= 9'b10;
|
||||
FrameCount <= 4'b0;
|
||||
InterCSCount <= 9'b10;
|
||||
end
|
||||
else if (ChipSelectMode[1:0] == 2'b10) state <= INTER_XFR;
|
||||
else if (~|(Delay0[15:8]) & (~SckMode[0])) state <= INTER_CS;
|
||||
else state <= DELAY_1;
|
||||
end
|
||||
DELAY_1: begin
|
||||
SCK_CSCount <= SCK_CSCount + 9'b1;
|
||||
if (SCK_CSCount >= (({Delay0[15:8], 1'b0}) + ImplicitDelay2)) state <= INTER_CS;
|
||||
end
|
||||
INTER_CS: begin
|
||||
InterCSCount <= InterCSCount + 9'b1;
|
||||
SPICLK <= SckMode[1];
|
||||
if (InterCSCount >= ({Delay1[7:0],1'b0})) state <= CS_INACTIVE;
|
||||
end
|
||||
INTER_XFR: begin
|
||||
CS_SCKCount <= 9'b1;
|
||||
SCK_CSCount <= 9'b10;
|
||||
FrameCount <= 4'b0;
|
||||
InterCSCount <= 9'b10;
|
||||
InterXFRCount <= InterXFRCount + 9'b1;
|
||||
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;
|
||||
else SPICLK <= SckMode[1];
|
||||
end
|
||||
|
||||
// State machine for starting transmissions
|
||||
always_comb begin
|
||||
case (CurrState)
|
||||
READY: if (~TransmitFIFOReadEmpty) NextState = START;
|
||||
else NextState = READY;
|
||||
START: NextState = WAIT;
|
||||
WAIT: if (TransmitFIFOReadEmpty & ~Transmitting) NextState = READY;
|
||||
else NextState = WAIT;
|
||||
endcase
|
||||
/* verilator lint_off CASEINCOMPLETE */
|
||||
end
|
||||
|
||||
assign TransmitStart = (CurrState == START);
|
||||
|
||||
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);
|
||||
|
||||
|
||||
assign DelayMode = SckMode[0] ? (state == DELAY_1) : (state == ACTIVE_1 & ReceiveShiftFull);
|
||||
assign ChipSelectInternal = (state == CS_INACTIVE | state == INTER_CS | DelayMode & ~|(Delay0[15:8])) ? ChipSelectDef : ~ChipSelectDef;
|
||||
assign Active = (state == ACTIVE_0 | state == ACTIVE_1);
|
||||
assign SampleEdge = SckMode[0] ? (state == ACTIVE_1) : (state == ACTIVE_0);
|
||||
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;
|
||||
// Receive FIFO ----------------------------------------------------
|
||||
always_ff @(posedge PCLK)
|
||||
if (~PRESETn) begin
|
||||
ReceiveFIFOReadIncrement <= 1'b0;
|
||||
ReceiveFIFOWriteInc <= 1'b0;
|
||||
end else begin
|
||||
ReceiveFIFOReadIncrement <= ((Entry == SPI_RXDATA) & ~ReceiveFIFOReadEmpty & PSEL & ~ReceiveFIFOReadIncrement);
|
||||
ReceiveFIFOWriteInc <= EndOfFrameDelay;
|
||||
end
|
||||
|
||||
// Signal tracks which edge of sck to shift data
|
||||
always_comb
|
||||
case(SckMode[1:0])
|
||||
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
|
||||
spi_fifo #(3,8) rxFIFO(PCLK, SCLKenable, 1'b1, PRESETn,
|
||||
ReceiveFIFOWriteInc, ReceiveFIFOReadIncrement,
|
||||
ReceiveShiftRegEndian, ReceiveWatermark[2:0],
|
||||
ReceiveReadWatermarkLevel,
|
||||
ReceiveData[7:0],
|
||||
ReceiveFIFOWriteFull,
|
||||
ReceiveFIFOReadEmpty,
|
||||
RecieveWriteMark, RecieveReadMark);
|
||||
|
||||
// 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 TransmitLoad = TransmitStart | (EndOfFrameDelay & ~TransmitFIFOReadEmpty);
|
||||
assign TransmitDataEndian = Format[0] ? {<<{TransmitFIFOReadData[7:0]}} : TransmitFIFOReadData[7:0];
|
||||
always_ff @(posedge PCLK)
|
||||
if(~PRESETn) TransmitShiftReg <= 8'b0;
|
||||
else if (TransmitShiftRegLoadSingleCycle) TransmitShiftReg <= TransmitDataEndian;
|
||||
else if (ShiftEdge & Active) TransmitShiftReg <= {TransmitShiftReg[6:0], TransmitShiftReg[0]};
|
||||
if(~PRESETn) TransmitReg <= 8'b0;
|
||||
else if (TransmitLoad) TransmitReg <= TransmitDataEndian;
|
||||
else if (ShiftEdge) TransmitReg <= {TransmitReg[6:0], TransmitReg[0]};
|
||||
|
||||
assign SPIOut = TransmitShiftReg[7];
|
||||
assign SPIOut = TransmitReg[7];
|
||||
|
||||
// If in loopback mode, receive shift register is connected directly to module's output pins. Else, connected to SPIIn
|
||||
// There are no setup/hold time issues because transmit shift register and receive shift register always shift/sample on opposite edges
|
||||
// If in loopback mode, receive shift register is connected directly
|
||||
// to module's output pins. Else, connected to SPIIn. There are no
|
||||
// setup/hold time issues because transmit shift register and receive
|
||||
// shift register always shift/sample on opposite edges
|
||||
assign ShiftIn = P.SPI_LOOPBACK_TEST ? SPIOut : SPIIn;
|
||||
|
||||
// Receive shift register
|
||||
always_ff @(posedge PCLK)
|
||||
if(~PRESETn) ReceiveShiftReg <= 8'b0;
|
||||
else if (SampleEdge & SCLKenable) begin
|
||||
if (~Active) ReceiveShiftReg <= 8'b0;
|
||||
else if (SampleEdge) begin
|
||||
if (~Transmitting) ReceiveShiftReg <= 8'b0;
|
||||
else ReceiveShiftReg <= {ReceiveShiftReg[6:0], ShiftIn};
|
||||
end
|
||||
|
||||
// Aligns received data and reverses if little-endian
|
||||
assign LeftShiftAmount = 4'h8 - Format[4:1];
|
||||
assign ASR = ReceiveShiftReg << LeftShiftAmount[2:0];
|
||||
assign ReceiveShiftRegEndian = Format[0] ? {ASR[0], ASR[1], ASR[2], ASR[3], ASR[4], ASR[5], ASR[6], ASR[7]} : ASR[7:0];
|
||||
assign ReceiveShiftRegEndian = Format[0] ? {<<{ASR[7:0]}} : ASR[7:0];
|
||||
|
||||
// Interrupt logic: raise interrupt if any enabled interrupts are pending
|
||||
assign SPIIntr = |(InterruptPending & InterruptEnable);
|
||||
|
||||
// Chip select logic
|
||||
assign ChipSelectInternal = InactiveState ? ChipSelectDef : ~ChipSelectDef;
|
||||
always_comb
|
||||
case(ChipSelectID[1:0])
|
||||
2'b00: ChipSelectAuto = {ChipSelectDef[3], ChipSelectDef[2], ChipSelectDef[1], ChipSelectInternal[0]};
|
||||
@ -462,6 +329,6 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
||||
2'b10: ChipSelectAuto = {ChipSelectDef[3],ChipSelectInternal[2], ChipSelectDef[1], ChipSelectDef[0]};
|
||||
2'b11: ChipSelectAuto = {ChipSelectInternal[3],ChipSelectDef[2], ChipSelectDef[1], ChipSelectDef[0]};
|
||||
endcase
|
||||
|
||||
assign SPICS = ChipSelectMode[0] ? ChipSelectDef : ChipSelectAuto;
|
||||
|
||||
endmodule
|
||||
|
@ -28,21 +28,33 @@
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
module spi_controller (
|
||||
input logic PCLK,
|
||||
input logic PRESETn,
|
||||
|
||||
// Start Transmission
|
||||
input logic TransmitStart,
|
||||
input logic ResetSCLKenable,
|
||||
|
||||
// Registers
|
||||
input logic [11:0] SckDiv,
|
||||
input logic [1:0] SckMode,
|
||||
input logic [1:0] CSMode,
|
||||
input logic [15:0] Delay0,
|
||||
input logic [15:0] Delay1,
|
||||
input logic [7:0] txFIFORead,
|
||||
|
||||
// Is the Transmit FIFO Empty?
|
||||
input logic txFIFOReadEmpty,
|
||||
output logic SPICLK,
|
||||
output logic SPIOUT,
|
||||
output logic CS
|
||||
|
||||
// Control signals
|
||||
output logic SCLKenable,
|
||||
output logic ShiftEdge,
|
||||
output logic SampleEdge,
|
||||
output logic EndOfFrame,
|
||||
output logic EndOfFrameDelay,
|
||||
output logic Transmitting,
|
||||
output logic InactiveState,
|
||||
output logic SPICLK
|
||||
);
|
||||
|
||||
// CSMode Stuff
|
||||
@ -55,36 +67,32 @@ module spi_controller (
|
||||
|
||||
// SCLKenable stuff
|
||||
logic [11:0] DivCounter;
|
||||
logic SCLKenable;
|
||||
logic SCLKenableEarly;
|
||||
logic SCLKenableLate;
|
||||
logic EdgeTiming;
|
||||
// logic SCLKenable;
|
||||
// logic SCLKenableEarly;
|
||||
logic ZeroDiv;
|
||||
logic Clock0;
|
||||
logic Clock1;
|
||||
logic SCK; // SUPER IMPORTANT, THIS CAN'T BE THE SAME AS SPICLK!
|
||||
|
||||
|
||||
// Shift and Sample Edges
|
||||
logic PreShiftEdge;
|
||||
logic PreSampleEdge;
|
||||
logic ShiftEdge;
|
||||
logic SampleEdge;
|
||||
// logic ShiftEdge;
|
||||
// logic SampleEdge;
|
||||
|
||||
// Frame stuff
|
||||
logic [2:0] BitNum;
|
||||
logic LastBit;
|
||||
logic EndOfFrame;
|
||||
logic EndOfFrameDelay;
|
||||
//logic EndOfFrame;
|
||||
//logic EndOfFrameDelay;
|
||||
logic PhaseOneOffset;
|
||||
|
||||
// Transmit Stuff
|
||||
logic ContinueTransmit;
|
||||
|
||||
// SPIOUT Stuff
|
||||
logic TransmitLoad;
|
||||
// logic TransmitLoad;
|
||||
logic [7:0] TransmitReg;
|
||||
logic Transmitting;
|
||||
//logic Transmitting;
|
||||
logic EndTransmission;
|
||||
|
||||
logic HoldMode;
|
||||
@ -135,13 +143,9 @@ module spi_controller (
|
||||
// SampleEdge. This makes sure that SPICLK is an output of a register
|
||||
// and it properly synchronizes signals.
|
||||
|
||||
assign SCLKenableLate = DivCounter > SckDiv;
|
||||
assign SCLKenable = DivCounter == SckDiv;
|
||||
assign SCLKenableEarly = (DivCounter + 1'b1) == SckDiv;
|
||||
// assign SCLKenableEarly = (DivCounter + 1'b1) == SckDiv;
|
||||
assign LastBit = BitNum == 3'd7;
|
||||
assign EdgeTiming = SckDiv > 12'b0 ? SCLKenableEarly : SCLKenable;
|
||||
|
||||
//assign SPICLK = Clock0;
|
||||
|
||||
assign ContinueTransmit = ~txFIFOReadEmpty & EndOfFrame;
|
||||
assign EndTransmission = txFIFOReadEmpty & EndOfFrameDelay;
|
||||
@ -196,7 +200,7 @@ module spi_controller (
|
||||
end
|
||||
|
||||
// Reset divider
|
||||
if (SCLKenable | TransmitStart) begin
|
||||
if (SCLKenable | TransmitStart | ResetSCLKenable) begin
|
||||
DivCounter <= 12'b0;
|
||||
end else begin
|
||||
DivCounter = DivCounter + 12'd1;
|
||||
@ -242,8 +246,8 @@ module spi_controller (
|
||||
// typedef enum logic [2:0] {INACTIVE, CSSCK, TRANSMIT, SCKCS, HOLD, INTERCS, INTERXFR} statetype;
|
||||
// statetype CurrState, NextState;
|
||||
|
||||
assign HoldMode = CSMode == 2'b10;
|
||||
assign TransmitLoad = TransmitStart | (EndOfFrameDelay & ~txFIFOReadEmpty);
|
||||
assign HoldMode = CSMode == HOLDMODE;
|
||||
// assign TransmitLoad = TransmitStart | (EndOfFrameDelay & ~txFIFOReadEmpty);
|
||||
|
||||
always_ff @(posedge PCLK) begin
|
||||
if (~PRESETn) begin
|
||||
@ -255,61 +259,43 @@ module spi_controller (
|
||||
|
||||
always_comb begin
|
||||
case (CurrState)
|
||||
INACTIVE: begin // INACTIVE case --------------------------------
|
||||
if (TransmitStart) begin
|
||||
if (~HasCSSCK) begin
|
||||
NextState = TRANSMIT;
|
||||
end else begin
|
||||
NextState = CSSCK;
|
||||
end
|
||||
end else begin
|
||||
NextState = INACTIVE;
|
||||
end
|
||||
end
|
||||
CSSCK: begin // DELAY0 case -------------------------------------
|
||||
if (EndOfCSSCK) begin
|
||||
NextState = TRANSMIT;
|
||||
end
|
||||
end
|
||||
INACTIVE: if (TransmitStart)
|
||||
if (~HasCSSCK) NextState = TRANSMIT;
|
||||
else NextState = CSSCK;
|
||||
else NextState = INACTIVE;
|
||||
CSSCK: if (EndOfCSSCK) NextState = TRANSMIT;
|
||||
else NextState = CSSCK;
|
||||
TRANSMIT: begin // TRANSMIT case --------------------------------
|
||||
case(CSMode)
|
||||
AUTOMODE: begin
|
||||
if (EndTransmission) begin
|
||||
NextState = INACTIVE;
|
||||
end else if (ContinueTransmit) begin
|
||||
NextState = SCKCS;
|
||||
end
|
||||
if (EndTransmission) NextState = INACTIVE;
|
||||
else if (ContinueTransmit) NextState = SCKCS;
|
||||
end
|
||||
HOLDMODE: begin
|
||||
if (EndTransmission) begin
|
||||
NextState = HOLD;
|
||||
end else if (ContinueTransmit) begin
|
||||
if (HasINTERXFR) NextState = INTERXFR;
|
||||
end
|
||||
if (EndTransmission) NextState = HOLD;
|
||||
else if (ContinueTransmit & HasINTERXFR) NextState = INTERXFR;
|
||||
else NextState = TRANSMIT;
|
||||
end
|
||||
OFFMODE: begin
|
||||
|
||||
end
|
||||
|
||||
endcase
|
||||
end
|
||||
SCKCS: begin // SCKCS case --------------------------------------
|
||||
if (EndOfSCKCS) begin
|
||||
if (EndTransmission) begin
|
||||
if (EndOfSCKCS)
|
||||
if (EndTransmission)
|
||||
if (CSMode == AUTOMODE) NextState = INACTIVE;
|
||||
else if (CSMode == HOLDMODE) NextState = HOLD;
|
||||
end else if (ContinueTransmit) begin
|
||||
else if (ContinueTransmit)
|
||||
if (HasINTERCS) NextState = INTERCS;
|
||||
else NextState = TRANSMIT;
|
||||
end
|
||||
end
|
||||
end
|
||||
HOLD: begin // HOLD mode case -----------------------------------
|
||||
if (CSMode == AUTOMODE) begin
|
||||
NextState = INACTIVE;
|
||||
end else if (TransmitStart) begin // If FIFO is written to, start again.
|
||||
NextState = TRANSMIT;
|
||||
end
|
||||
end else NextState = HOLD;
|
||||
end
|
||||
INTERCS: begin // INTERCS case ----------------------------------
|
||||
if (EndOfINTERCS) begin
|
||||
@ -330,19 +316,6 @@ module spi_controller (
|
||||
|
||||
assign Transmitting = CurrState == TRANSMIT;
|
||||
assign DelayIsNext = (NextState == CSSCK | NextState == SCKCS | NextState == INTERCS | NextState == INTERXFR);
|
||||
|
||||
//
|
||||
always_ff @(posedge PCLK) begin
|
||||
if (~PRESETn) begin
|
||||
TransmitReg <= 8'b0;
|
||||
end else if (TransmitLoad) begin
|
||||
TransmitReg <= txFIFORead;
|
||||
end else if (ShiftEdge) begin
|
||||
TransmitReg <= {TransmitReg[6:0], TransmitReg[0]};
|
||||
end
|
||||
end
|
||||
|
||||
assign SPIOUT = TransmitReg[7];
|
||||
assign CS = CurrState == INACTIVE | CurrState == INTERCS;
|
||||
assign InactiveState = CurrState == INACTIVE | CurrState == INTERCS;
|
||||
|
||||
endmodule
|
||||
|
Loading…
Reference in New Issue
Block a user