Removed unused signals and renamed other signals. Removed a bunch of delay counters and simply reuse one counter for all delay types. Tested on FPGA and it also passes regression.

This commit is contained in:
Jacob Pease 2024-11-03 00:35:40 -05:00
parent 674d008f23
commit a9e6962cd4
2 changed files with 101 additions and 152 deletions

View File

@ -85,11 +85,11 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
// SPI Controller signals // SPI Controller signals
logic SCLKenable; logic SCLKenable;
logic EndOfFrame; logic EndOfFrame;
logic EndOfFrameDelay;
logic Transmitting; logic Transmitting;
logic InactiveState; logic InactiveState;
logic [3:0] FrameLength; logic [3:0] FrameLength;
//
logic ResetSCLKenable; logic ResetSCLKenable;
logic TransmitStart; logic TransmitStart;
logic TransmitStartD; logic TransmitStartD;
@ -100,14 +100,16 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
// FIFO FSM signals // FIFO FSM signals
// Watermark signals - TransmitReadMark = ip[0], ReceiveWriteMark = ip[1] // Watermark signals - TransmitReadMark = ip[0], ReceiveWriteMark = ip[1]
logic TransmitWriteMark, TransmitReadMark, RecieveWriteMark, RecieveReadMark; logic TransmitWriteMark, TransmitReadMark, ReceiveWriteMark, ReceiveReadMark;
logic TransmitFIFOWriteFull, TransmitFIFOReadEmpty; logic TransmitFIFOFull, TransmitFIFOEmpty;
logic TransmitFIFOWriteIncrement; logic TransmitFIFOWriteInc;
logic [7:0] TransmitFIFOReadData; logic TransmitFIFOReadInc; // Increments Tx FIFO read ptr 1 cycle after Tx FIFO is read
logic [7:0] TransmitReadData;
//
logic ReceiveFIFOWriteInc; logic ReceiveFIFOWriteInc;
logic ReceiveFIFOReadIncrement; logic ReceiveFIFOReadInc;
logic ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty; logic ReceiveFIFOFull, ReceiveFIFOEmpty;
/* verilator lint_off UNDRIVEN */ /* verilator lint_off UNDRIVEN */
logic [2:0] TransmitWriteWatermarkLevel, ReceiveReadWatermarkLevel; // unused generic FIFO outputs logic [2:0] TransmitWriteWatermarkLevel, ReceiveReadWatermarkLevel; // unused generic FIFO outputs
@ -115,16 +117,16 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
logic [7:0] ReceiveShiftRegEndian; // Reverses ReceiveShiftReg if Format[2] set (little endian transmission) logic [7:0] ReceiveShiftRegEndian; // Reverses ReceiveShiftReg if Format[2] set (little endian transmission)
// Shift reg signals // Shift reg signals
logic ShiftEdge; // Determines which edge of sck to shift from TransmitReg logic ShiftEdge; // Determines which edge of sck to shift from TransmitReg
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] TransmitReg; // Transmit shift register logic [7:0] TransmitReg; // Transmit shift register
logic [7:0] ReceiveShiftReg; // Receive 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 [7:0] TransmitDataEndian; // Reverses TransmitData from txFIFO if littleendian, since TransmitReg always shifts MSB
logic TransmitLoad; // Determines when to load TransmitReg logic TransmitLoad; // Determines when to load TransmitReg
logic TransmitFIFOReadIncrement; // Increments Tx FIFO read ptr 1 cycle after Tx FIFO is read logic TransmitRegLoaded;
// Shift stuff due to Format register? // Shift stuff due to Format register?
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
@ -180,14 +182,14 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
if (Memwrite) if (Memwrite)
case(Entry) case(Entry)
SPI_TXDATA: if (~TransmitFIFOWriteFull) TransmitData[7:0] <= Din[7:0]; SPI_TXDATA: if (~TransmitFIFOFull) TransmitData[7:0] <= Din[7:0];
endcase endcase
/* verilator lint_off CASEINCOMPLETE */ /* verilator lint_off CASEINCOMPLETE */
// According to FU540 spec: Once interrupt is pending, it will remain set until number // According to FU540 spec: Once interrupt is pending, it will remain set until number
// of entries in tx/rx fifo is strictly more/less than tx/rxmark // of entries in tx/rx fifo is strictly more/less than tx/rxmark
InterruptPending[0] <= TransmitReadMark; InterruptPending[0] <= TransmitReadMark;
InterruptPending[1] <= RecieveWriteMark; InterruptPending[1] <= ReceiveWriteMark;
case(Entry) // Flop to sample inputs case(Entry) // Flop to sample inputs
SPI_SCKDIV: Dout <= {20'b0, SckDiv}; SPI_SCKDIV: Dout <= {20'b0, SckDiv};
@ -198,8 +200,8 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
SPI_DELAY0: Dout <= {8'b0, Delay0[15:8], 8'b0, Delay0[7:0]}; SPI_DELAY0: Dout <= {8'b0, Delay0[15:8], 8'b0, Delay0[7:0]};
SPI_DELAY1: Dout <= {8'b0, Delay1[15:8], 8'b0, Delay1[7:0]}; SPI_DELAY1: Dout <= {8'b0, Delay1[15:8], 8'b0, Delay1[7:0]};
SPI_FMT: Dout <= {12'b0, Format[4:1], 13'b0, Format[0], 2'b0}; SPI_FMT: Dout <= {12'b0, Format[4:1], 13'b0, Format[0], 2'b0};
SPI_TXDATA: Dout <= {TransmitFIFOWriteFull, 23'b0, 8'b0}; SPI_TXDATA: Dout <= {TransmitFIFOFull, 23'b0, 8'b0};
SPI_RXDATA: Dout <= {ReceiveFIFOReadEmpty, 23'b0, ReceiveData[7:0]}; SPI_RXDATA: Dout <= {ReceiveFIFOEmpty, 23'b0, ReceiveData[7:0]};
SPI_TXMARK: Dout <= {29'b0, TransmitWatermark}; SPI_TXMARK: Dout <= {29'b0, TransmitWatermark};
SPI_RXMARK: Dout <= {29'b0, ReceiveWatermark}; SPI_RXMARK: Dout <= {29'b0, ReceiveWatermark};
SPI_IE: Dout <= {30'b0, InterruptEnable}; SPI_IE: Dout <= {30'b0, InterruptEnable};
@ -208,11 +210,6 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
endcase endcase
end end
// 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)).
// SPI Controller module ------------------------------------------- // SPI Controller module -------------------------------------------
// This module controls state and timing signals that drive the rest of this module // This module controls state and timing signals that drive the rest of this module
assign ResetSCLKenable = Memwrite & (Entry == SPI_SCKDIV); assign ResetSCLKenable = Memwrite & (Entry == SPI_SCKDIV);
@ -224,38 +221,40 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
// Register Inputs // Register Inputs
SckDiv, SckMode, ChipSelectMode, Delay0, Delay1, FrameLength, SckDiv, SckMode, ChipSelectMode, Delay0, Delay1, FrameLength,
// txFIFO stuff // txFIFO stuff
TransmitFIFOReadEmpty, TransmitFIFOEmpty,
// Timing // Timing
SCLKenable, ShiftEdge, SampleEdge, EndOfFrame, EndOfFrameDelay, SCLKenable, ShiftEdge, SampleEdge, EndOfFrame,
// State stuff // State stuff
Transmitting, InactiveState, Transmitting, InactiveState,
// Outputs // Outputs
SPICLK); SPICLK);
// Transmit FIFO --------------------------------------------------- // Transmit FIFO ---------------------------------------------------
// txFIFO write increment logic
always_ff @(posedge PCLK) always_ff @(posedge PCLK)
if (~PRESETn) begin if (~PRESETn) begin
TransmitFIFOWriteIncrement <= 1'b0; TransmitFIFOWriteInc <= 1'b0;
end else begin end else begin
TransmitFIFOWriteIncrement <= (Memwrite & (Entry == SPI_TXDATA) & ~TransmitFIFOWriteFull); TransmitFIFOWriteInc <= (Memwrite & (Entry == SPI_TXDATA) & ~TransmitFIFOFull);
end end
// txFIFO read increment logic
always_ff @(posedge PCLK) always_ff @(posedge PCLK)
if (~PRESETn) begin if (~PRESETn) begin
TransmitFIFOReadIncrement <= 1'b0; TransmitFIFOReadInc <= 1'b0;
end else if (SCLKenable) begin end else if (SCLKenable) begin
TransmitFIFOReadIncrement <= TransmitStartD | (EndOfFrameDelay & ~TransmitFIFOReadEmpty) ; TransmitFIFOReadInc <= TransmitStartD | (EndOfFrame & ~TransmitFIFOEmpty) ;
end end
// Check whether TransmitReg has been loaded. // Check whether TransmitReg has been loaded.
// We use this signal to prevent returning to the Ready state for TransmitStart // We use this signal to prevent returning to the Ready state for TransmitStart
logic TransmitRegLoaded;
always_ff @(posedge PCLK) begin always_ff @(posedge PCLK) begin
if (~PRESETn) begin if (~PRESETn) begin
TransmitRegLoaded <= 1'b0; TransmitRegLoaded <= 1'b0;
end else if (TransmitLoad) begin end else if (TransmitLoad) begin
TransmitRegLoaded <= 1'b1; TransmitRegLoaded <= 1'b1;
end else if (ShiftEdge | EndOfFrameDelay) begin end else if (ShiftEdge | EndOfFrame) begin
TransmitRegLoaded <= 1'b0; TransmitRegLoaded <= 1'b0;
end end
end end
@ -272,7 +271,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
// State machine for starting transmissions // State machine for starting transmissions
always_comb begin always_comb begin
case (CurrState) case (CurrState)
READY: if (~TransmitFIFOReadEmpty & ~Transmitting) NextState = START; READY: if (~TransmitFIFOEmpty & ~Transmitting) NextState = START;
else NextState = READY; else NextState = READY;
START: NextState = WAIT; START: NextState = WAIT;
WAIT: if (~Transmitting & ~TransmitRegLoaded) NextState = READY; WAIT: if (~Transmitting & ~TransmitRegLoaded) NextState = READY;
@ -288,42 +287,41 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
else if (SCLKenable) TransmitStartD <= 1'b0; else if (SCLKenable) TransmitStartD <= 1'b0;
spi_fifo #(3,8) txFIFO(PCLK, 1'b1, SCLKenable, PRESETn, spi_fifo #(3,8) txFIFO(PCLK, 1'b1, SCLKenable, PRESETn,
TransmitFIFOWriteIncrement, TransmitFIFOReadIncrement, TransmitFIFOWriteInc, TransmitFIFOReadInc,
TransmitData[7:0], TransmitData[7:0],
TransmitWriteWatermarkLevel, TransmitWatermark[2:0], TransmitWriteWatermarkLevel, TransmitWatermark[2:0],
TransmitFIFOReadData[7:0], TransmitReadData[7:0],
TransmitFIFOWriteFull, TransmitFIFOFull,
TransmitFIFOReadEmpty, TransmitFIFOEmpty,
TransmitWriteMark, TransmitReadMark); TransmitWriteMark, TransmitReadMark);
// Receive FIFO ---------------------------------------------------- // Receive FIFO ----------------------------------------------------
always_ff @(posedge PCLK) always_ff @(posedge PCLK)
if (~PRESETn) begin if (~PRESETn) begin
ReceiveFIFOReadIncrement <= 1'b0; ReceiveFIFOReadInc <= 1'b0;
end else begin end else begin
ReceiveFIFOReadIncrement <= ((Entry == SPI_RXDATA) & ~ReceiveFIFOReadEmpty & PSEL & ~ReceiveFIFOReadIncrement); ReceiveFIFOReadInc <= ((Entry == SPI_RXDATA) & ~ReceiveFIFOEmpty & PSEL & ~ReceiveFIFOReadInc);
end end
always_ff @(posedge PCLK) always_ff @(posedge PCLK)
if (~PRESETn) begin if (~PRESETn) begin
ReceiveFIFOWriteInc <= 1'b0; ReceiveFIFOWriteInc <= 1'b0;
end else if (SCLKenable) begin end else if (SCLKenable) begin
ReceiveFIFOWriteInc <= EndOfFrameDelay; ReceiveFIFOWriteInc <= EndOfFrame;
end end
spi_fifo #(3,8) rxFIFO(PCLK, SCLKenable, 1'b1, PRESETn, spi_fifo #(3,8) rxFIFO(PCLK, SCLKenable, 1'b1, PRESETn,
ReceiveFIFOWriteInc, ReceiveFIFOReadIncrement, ReceiveFIFOWriteInc, ReceiveFIFOReadInc,
ReceiveShiftRegEndian, ReceiveWatermark[2:0], ReceiveShiftRegEndian, ReceiveWatermark[2:0],
ReceiveReadWatermarkLevel, ReceiveReadWatermarkLevel,
ReceiveData[7:0], ReceiveData[7:0],
ReceiveFIFOWriteFull, ReceiveFIFOFull,
ReceiveFIFOReadEmpty, ReceiveFIFOEmpty,
RecieveWriteMark, RecieveReadMark); ReceiveWriteMark, ReceiveReadMark);
// Transmit shift register // Transmit shift register
assign TransmitLoad = TransmitStart | (EndOfFrameDelay & ~TransmitFIFOReadEmpty); assign TransmitLoad = TransmitStart | (EndOfFrame & ~TransmitFIFOEmpty);
assign TransmitDataEndian = Format[0] ? {<<{TransmitFIFOReadData[7:0]}} : TransmitFIFOReadData[7:0]; assign TransmitDataEndian = Format[0] ? {<<{TransmitReadData[7:0]}} : TransmitReadData[7:0];
always_ff @(posedge PCLK) always_ff @(posedge PCLK)
if(~PRESETn) TransmitReg <= 8'b0; if(~PRESETn) TransmitReg <= 8'b0;
else if (TransmitLoad) TransmitReg <= TransmitDataEndian; else if (TransmitLoad) TransmitReg <= TransmitDataEndian;

View File

@ -52,7 +52,6 @@ module spi_controller (
output logic ShiftEdge, output logic ShiftEdge,
output logic SampleEdge, output logic SampleEdge,
output logic EndOfFrame, output logic EndOfFrame,
output logic EndOfFrameDelay,
output logic Transmitting, output logic Transmitting,
output logic InactiveState, output logic InactiveState,
output logic SPICLK output logic SPICLK
@ -63,43 +62,31 @@ module spi_controller (
localparam AUTOMODE = 2'b00; localparam AUTOMODE = 2'b00;
localparam OFFMODE = 2'b11; localparam OFFMODE = 2'b11;
// FSM States
typedef enum logic [2:0] {INACTIVE, CSSCK, TRANSMIT, SCKCS, HOLD, INTERCS, INTERXFR} statetype; typedef enum logic [2:0] {INACTIVE, CSSCK, TRANSMIT, SCKCS, HOLD, INTERCS, INTERXFR} statetype;
statetype CurrState, NextState; statetype CurrState, NextState;
// SCLKenable stuff // SCLKenable stuff
logic [11:0] DivCounter; logic [11:0] DivCounter;
// logic SCLKenable; logic SCK;
// logic SCLKenableEarly;
logic ZeroDiv;
logic SCK; // SUPER IMPORTANT, THIS CAN'T BE THE SAME AS SPICLK!
// Shift and Sample Edges // Shift and Sample Edges
logic PreShiftEdge; logic EdgePulse;
logic PreSampleEdge;
// logic ShiftEdge;
// logic SampleEdge;
logic ShiftEdgePulse; logic ShiftEdgePulse;
logic SampleEdgePulse; logic SampleEdgePulse;
logic EndOfFramePulse; logic EndOfFramePulse;
logic PhaseOneOffset;
// Frame stuff // Frame stuff
logic [3:0] BitNum; logic [3:0] BitNum;
logic LastBit; logic LastBit;
//logic EndOfFrame;
//logic EndOfFrameDelay;
logic PhaseOneOffset;
// Transmit Stuff // Transmit Stuff
logic ContinueTransmit; logic ContinueTransmit;
// SPIOUT Stuff
// logic TransmitLoad;
logic [7:0] TransmitReg;
//logic Transmitting;
logic EndTransmission; logic EndTransmission;
logic ContinueTransmitD; // TODO: Could be replaced by TransmitRegLoaded?
logic HoldMode; logic NextEndDelay;
logic CurrentEndDelay;
// Delay Stuff // Delay Stuff
logic [7:0] cssck; logic [7:0] cssck;
@ -116,13 +103,12 @@ module spi_controller (
logic EndOfSCKCS; logic EndOfSCKCS;
logic EndOfINTERCS; logic EndOfINTERCS;
logic EndOfINTERXFR; logic EndOfINTERXFR;
logic EndOfDelay;
logic [7:0] CSSCKCounter; logic [7:0] DelayCounter;
logic [7:0] SCKCSCounter;
logic [7:0] INTERCSCounter;
logic [7:0] INTERXFRCounter;
logic DelayIsNext; logic DelayIsNext;
logic DelayState;
// Convenient Delay Reg Names // Convenient Delay Reg Names
assign cssck = Delay0[7:0]; assign cssck = Delay0[7:0];
@ -137,23 +123,25 @@ module spi_controller (
assign HasINTERXFR = interxfr > 8'b0; assign HasINTERXFR = interxfr > 8'b0;
// Have we hit full delay for any of the delays? // Have we hit full delay for any of the delays?
assign EndOfCSSCK = CSSCKCounter == cssck; assign EndOfCSSCK = (DelayCounter == cssck) & (CurrState == CSSCK);
assign EndOfSCKCS = SCKCSCounter == sckcs; assign EndOfSCKCS = (DelayCounter == sckcs) & (CurrState == SCKCS);
assign EndOfINTERCS = INTERCSCounter == intercs; assign EndOfINTERCS = (DelayCounter == intercs) & (CurrState == INTERCS);
assign EndOfINTERXFR = INTERXFRCounter == interxfr; assign EndOfINTERXFR = (DelayCounter == interxfr) & (CurrState == INTERXFR);
assign EndOfDelay = EndOfCSSCK | EndOfSCKCS | EndOfINTERCS | EndOfINTERXFR;
// Clock Signal Stuff ----------------------------------------------- // Clock Signal Stuff -----------------------------------------------
// I'm going to handle all clock stuff here, including ShiftEdge and // I'm going to handle all clock stuff here, including ShiftEdge and
// SampleEdge. This makes sure that SPICLK is an output of a register // SampleEdge. This makes sure that SPICLK is an output of a register
// and it properly synchronizes signals. // and it properly synchronizes signals.
// 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; assign SCLKenable = DivCounter == SckDiv;
// assign SCLKenableEarly = (DivCounter + 1'b1) == SckDiv;
assign LastBit = (BitNum == FrameLength - 4'b1);
//assign EndOfFrame = SCLKenable & LastBit & Transmitting; assign ContinueTransmit = ~txFIFOReadEmpty & EndOfFrame;
assign ContinueTransmit = ~txFIFOReadEmpty & EndOfFrameDelay; assign EndTransmission = txFIFOReadEmpty & EndOfFrame;
assign EndTransmission = txFIFOReadEmpty & EndOfFrameDelay;
always_ff @(posedge PCLK) begin always_ff @(posedge PCLK) begin
if (~PRESETn) begin if (~PRESETn) begin
@ -161,13 +149,7 @@ module spi_controller (
SPICLK <= SckMode[1]; SPICLK <= SckMode[1];
SCK <= 0; SCK <= 0;
BitNum <= 4'h0; BitNum <= 4'h0;
PreShiftEdge <= 0; DelayCounter <= 0;
PreSampleEdge <= 0;
EndOfFrame <= 0;
CSSCKCounter <= 0;
SCKCSCounter <= 0;
INTERCSCounter <= 0;
INTERXFRCounter <= 0;
end else begin end else begin
// TODO: Consolidate into one delay counter since none of the // TODO: Consolidate into one delay counter since none of the
// delays happen at the same time? // delays happen at the same time?
@ -177,28 +159,11 @@ module spi_controller (
SCK <= ~SCK; SCK <= ~SCK;
end end
if ((CurrState == CSSCK) & SCK & SCLKenable) begin // Counter for all four delay types
CSSCKCounter <= CSSCKCounter + 8'd1; if (DelayState & SCK & SCLKenable) begin
end else if (SCLKenable & EndOfCSSCK) begin DelayCounter <= DelayCounter + 8'd1;
CSSCKCounter <= 8'd0; end else if (SCLKenable & EndOfDelay) begin
end DelayCounter <= 8'd0;
if ((CurrState == SCKCS) & SCK & SCLKenable) begin
SCKCSCounter <= SCKCSCounter + 8'd1;
end else if (SCLKenable & EndOfSCKCS) begin
SCKCSCounter <= 8'd0;
end
if ((CurrState == INTERCS) & SCK & SCLKenable) begin
INTERCSCounter <= INTERCSCounter + 8'd1;
end else if (SCLKenable & EndOfINTERCS) begin
INTERCSCounter <= 8'd0;
end
if ((CurrState == INTERXFR) & SCK & SCLKenable) begin
INTERXFRCounter <= INTERXFRCounter + 8'd1;
end else if (SCLKenable & EndOfINTERXFR) begin
INTERXFRCounter <= 8'd0;
end end
// SPICLK Logic // SPICLK Logic
@ -215,85 +180,70 @@ module spi_controller (
DivCounter <= DivCounter + 12'd1; DivCounter <= DivCounter + 12'd1;
end end
// EndOfFrame controller
// if (SckDiv > 0 ? SCLKenableEarly & LastBit & SPICLK : LastBit & ~SPICLK) begin
// EndOfFrame <= 1'b1;
// end else begin
// EndOfFrame <= 1'b0;
// end
// TODO: Rename EndOfFrameDelay to EndOfFrame and remove this logic
if (~TransmitStart) begin
EndOfFrame <= (SckMode[1] ^ SckMode[0] ^ SPICLK) & SCLKenable & LastBit & Transmitting;
end
// Increment BitNum // Increment BitNum
if (ShiftEdge & Transmitting) begin if (ShiftEdge & Transmitting) begin
BitNum <= BitNum + 4'd1; BitNum <= BitNum + 4'd1;
end else if (EndOfFrameDelay) begin end else if (EndOfFrame) begin
BitNum <= 4'b0; BitNum <= 4'b0;
end end
end end
end end
// The very last bit in a frame of any length.
assign LastBit = (BitNum == FrameLength - 4'b1);
// Any SCLKenable pulse aligns with leading or trailing edge during
// Transmission. We can use this signal as the basis for ShiftEdge
// and SampleEdge.
assign EdgePulse = SCLKenable & Transmitting;
// Possible pulses for all edge types. Combined with SPICLK to get
// edges for different phase and polarity modes.
assign ShiftEdgePulse = EdgePulse & ~LastBit;
assign SampleEdgePulse = EdgePulse & ~DelayIsNext;
assign EndOfFramePulse = EdgePulse & LastBit;
// Delay ShiftEdge and SampleEdge by a half PCLK period // Delay ShiftEdge and SampleEdge by a half PCLK period
// Aligned EXACTLY ON THE MIDDLE of the leading and trailing edges. // Aligned EXACTLY ON THE MIDDLE of the leading and trailing edges.
// Sweeeeeeeeeet... // Sweeeeeeeeeet...
assign ShiftEdgePulse = SCLKenable & ~LastBit & Transmitting;
assign SampleEdgePulse = SCLKenable & Transmitting & ~DelayIsNext;
assign EndOfFramePulse = SCLKenable & LastBit & Transmitting;
always_ff @(posedge ~PCLK) begin always_ff @(posedge ~PCLK) begin
if (~PRESETn | TransmitStart) begin if (~PRESETn | TransmitStart) begin
ShiftEdge <= 0; ShiftEdge <= 0;
PhaseOneOffset <= 0; PhaseOneOffset <= 0;
SampleEdge <= 0; SampleEdge <= 0;
EndOfFrameDelay <= 0; EndOfFrame <= 0;
end else begin end else begin
PhaseOneOffset <= (PhaseOneOffset == 0) ? Transmitting & SCLKenable : ~EndOfFrameDelay; PhaseOneOffset <= (PhaseOneOffset == 0) ? Transmitting & SCLKenable : ~EndOfFrame;
case(SckMode) case(SckMode)
2'b00: begin 2'b00: begin
ShiftEdge <= SPICLK & ShiftEdgePulse; ShiftEdge <= SPICLK & ShiftEdgePulse;
SampleEdge <= ~SPICLK & SampleEdgePulse; SampleEdge <= ~SPICLK & SampleEdgePulse;
EndOfFrameDelay <= SPICLK & EndOfFramePulse; EndOfFrame <= SPICLK & EndOfFramePulse;
end end
2'b01: begin 2'b01: begin
ShiftEdge <= ~SPICLK & ShiftEdgePulse & PhaseOneOffset; ShiftEdge <= ~SPICLK & ShiftEdgePulse & PhaseOneOffset;
SampleEdge <= SPICLK & SampleEdgePulse; SampleEdge <= SPICLK & SampleEdgePulse;
EndOfFrameDelay <= ~SPICLK & EndOfFramePulse; EndOfFrame <= ~SPICLK & EndOfFramePulse;
end end
2'b10: begin 2'b10: begin
ShiftEdge <= ~SPICLK & ShiftEdgePulse; ShiftEdge <= ~SPICLK & ShiftEdgePulse;
SampleEdge <= SPICLK & SampleEdgePulse; SampleEdge <= SPICLK & SampleEdgePulse;
EndOfFrameDelay <= ~SPICLK & EndOfFramePulse; EndOfFrame <= ~SPICLK & EndOfFramePulse;
end end
2'b11: begin 2'b11: begin
ShiftEdge <= SPICLK & ShiftEdgePulse & PhaseOneOffset; ShiftEdge <= SPICLK & ShiftEdgePulse & PhaseOneOffset;
SampleEdge <= ~SPICLK & SampleEdgePulse; SampleEdge <= ~SPICLK & SampleEdgePulse;
EndOfFrameDelay <= SPICLK & EndOfFramePulse; EndOfFrame <= SPICLK & EndOfFramePulse;
end end
// ShiftEdge <= ((SckMode[1] ^ SckMode[0] ^ SPICLK) & SCLKenable & ~LastBit & Transmitting) & PhaseOneOffset;
// PhaseOneOffset <= PhaseOneOffset == 0 ? Transmitting & SCLKenable : ~EndOfFrameDelay;
// SampleEdge <= (SckMode[1] ^ SckMode[0] ^ ~SPICLK) & SCLKenable & Transmitting & ~DelayIsNext;
// EndOfFrameDelay <= (SckMode[1] ^ SckMode[0] ^ SPICLK) & SCLKenable & LastBit & Transmitting;
endcase endcase
end end
end end
// typedef enum logic [2:0] {INACTIVE, CSSCK, TRANSMIT, SCKCS, HOLD, INTERCS, INTERXFR} statetype; // Logic for continuing to transmit through Delay states after end of frame
// statetype CurrState, NextState;
assign HoldMode = CSMode == HOLDMODE;
// assign TransmitLoad = TransmitStart | (EndOfFrameDelay & ~txFIFOReadEmpty);
logic ContinueTransmitD;
logic NextEndDelay;
logic CurrentEndDelay;
assign NextEndDelay = NextState == SCKCS | NextState == INTERCS | NextState == INTERXFR; assign NextEndDelay = NextState == SCKCS | NextState == INTERCS | NextState == INTERXFR;
assign CurrentEndDelay = CurrState == SCKCS | CurrState == INTERCS | CurrState == INTERXFR; assign CurrentEndDelay = CurrState == SCKCS | CurrState == INTERCS | CurrState == INTERXFR;
//
always_ff @(posedge PCLK) begin always_ff @(posedge PCLK) begin
if (~PRESETn) begin if (~PRESETn) begin
ContinueTransmitD <= 1'b0; ContinueTransmitD <= 1'b0;
@ -326,7 +276,7 @@ module spi_controller (
case(CSMode) case(CSMode)
AUTOMODE: begin AUTOMODE: begin
if (EndTransmission) NextState = INACTIVE; if (EndTransmission) NextState = INACTIVE;
else if (EndOfFrameDelay) NextState = SCKCS; else if (EndOfFrame) NextState = SCKCS;
else NextState = TRANSMIT; else NextState = TRANSMIT;
end end
HOLDMODE: begin HOLDMODE: begin
@ -386,6 +336,7 @@ module spi_controller (
assign Transmitting = CurrState == TRANSMIT; assign Transmitting = CurrState == TRANSMIT;
assign DelayIsNext = (NextState == CSSCK | NextState == SCKCS | NextState == INTERCS | NextState == INTERXFR); assign DelayIsNext = (NextState == CSSCK | NextState == SCKCS | NextState == INTERCS | NextState == INTERXFR);
assign DelayState = (CurrState == CSSCK | CurrState == SCKCS | CurrState == INTERCS | CurrState == INTERXFR);
assign InactiveState = CurrState == INACTIVE | CurrState == INTERCS; assign InactiveState = CurrState == INACTIVE | CurrState == INTERCS;
endmodule endmodule