From a9e6962cd4de508d8d0e60366f4981784f24b89e Mon Sep 17 00:00:00 2001 From: Jacob Pease Date: Sun, 3 Nov 2024 00:35:40 -0500 Subject: [PATCH] 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. --- src/uncore/spi_apb.sv | 90 ++++++++++--------- src/uncore/spi_controller.sv | 163 ++++++++++++----------------------- 2 files changed, 101 insertions(+), 152 deletions(-) diff --git a/src/uncore/spi_apb.sv b/src/uncore/spi_apb.sv index 293c2c2b5..38fa07f42 100644 --- a/src/uncore/spi_apb.sv +++ b/src/uncore/spi_apb.sv @@ -85,11 +85,11 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( // SPI Controller signals logic SCLKenable; logic EndOfFrame; - logic EndOfFrameDelay; logic Transmitting; logic InactiveState; logic [3:0] FrameLength; + // logic ResetSCLKenable; logic TransmitStart; logic TransmitStartD; @@ -100,14 +100,16 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( // FIFO FSM signals // Watermark signals - TransmitReadMark = ip[0], ReceiveWriteMark = ip[1] - logic TransmitWriteMark, TransmitReadMark, RecieveWriteMark, RecieveReadMark; - logic TransmitFIFOWriteFull, TransmitFIFOReadEmpty; - logic TransmitFIFOWriteIncrement; - logic [7:0] TransmitFIFOReadData; + logic TransmitWriteMark, TransmitReadMark, ReceiveWriteMark, ReceiveReadMark; + logic TransmitFIFOFull, TransmitFIFOEmpty; + logic TransmitFIFOWriteInc; + logic TransmitFIFOReadInc; // Increments Tx FIFO read ptr 1 cycle after Tx FIFO is read + logic [7:0] TransmitReadData; + // logic ReceiveFIFOWriteInc; - logic ReceiveFIFOReadIncrement; - logic ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty; + logic ReceiveFIFOReadInc; + logic ReceiveFIFOFull, ReceiveFIFOEmpty; /* verilator lint_off UNDRIVEN */ 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) // Shift reg signals - 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 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 TransmitLoad; // Determines when to load TransmitReg - logic TransmitFIFOReadIncrement; // Increments Tx FIFO read ptr 1 cycle after Tx FIFO is read + logic TransmitLoad; // Determines when to load TransmitReg + logic TransmitRegLoaded; // 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 [7:0] ASR; // AlignedReceiveShiftReg @@ -180,14 +182,14 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( if (Memwrite) case(Entry) - SPI_TXDATA: if (~TransmitFIFOWriteFull) TransmitData[7:0] <= Din[7:0]; + SPI_TXDATA: if (~TransmitFIFOFull) TransmitData[7:0] <= Din[7:0]; endcase /* verilator lint_off CASEINCOMPLETE */ // 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 InterruptPending[0] <= TransmitReadMark; - InterruptPending[1] <= RecieveWriteMark; + InterruptPending[1] <= ReceiveWriteMark; case(Entry) // Flop to sample inputs 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_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_TXDATA: Dout <= {TransmitFIFOWriteFull, 23'b0, 8'b0}; - SPI_RXDATA: Dout <= {ReceiveFIFOReadEmpty, 23'b0, ReceiveData[7:0]}; + SPI_TXDATA: Dout <= {TransmitFIFOFull, 23'b0, 8'b0}; + SPI_RXDATA: Dout <= {ReceiveFIFOEmpty, 23'b0, ReceiveData[7:0]}; SPI_TXMARK: Dout <= {29'b0, TransmitWatermark}; SPI_RXMARK: Dout <= {29'b0, ReceiveWatermark}; SPI_IE: Dout <= {30'b0, InterruptEnable}; @@ -208,11 +210,6 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( endcase 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 ------------------------------------------- // This module controls state and timing signals that drive the rest of this module assign ResetSCLKenable = Memwrite & (Entry == SPI_SCKDIV); @@ -224,38 +221,40 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( // Register Inputs SckDiv, SckMode, ChipSelectMode, Delay0, Delay1, FrameLength, // txFIFO stuff - TransmitFIFOReadEmpty, + TransmitFIFOEmpty, // Timing - SCLKenable, ShiftEdge, SampleEdge, EndOfFrame, EndOfFrameDelay, + SCLKenable, ShiftEdge, SampleEdge, EndOfFrame, // State stuff Transmitting, InactiveState, // Outputs SPICLK); // Transmit FIFO --------------------------------------------------- + + // txFIFO write increment logic always_ff @(posedge PCLK) if (~PRESETn) begin - TransmitFIFOWriteIncrement <= 1'b0; + TransmitFIFOWriteInc <= 1'b0; end else begin - TransmitFIFOWriteIncrement <= (Memwrite & (Entry == SPI_TXDATA) & ~TransmitFIFOWriteFull); + TransmitFIFOWriteInc <= (Memwrite & (Entry == SPI_TXDATA) & ~TransmitFIFOFull); end + // txFIFO read increment logic always_ff @(posedge PCLK) if (~PRESETn) begin - TransmitFIFOReadIncrement <= 1'b0; + TransmitFIFOReadInc <= 1'b0; end else if (SCLKenable) begin - TransmitFIFOReadIncrement <= TransmitStartD | (EndOfFrameDelay & ~TransmitFIFOReadEmpty) ; + TransmitFIFOReadInc <= TransmitStartD | (EndOfFrame & ~TransmitFIFOEmpty) ; end // Check whether TransmitReg has been loaded. // We use this signal to prevent returning to the Ready state for TransmitStart - logic TransmitRegLoaded; always_ff @(posedge PCLK) begin if (~PRESETn) begin TransmitRegLoaded <= 1'b0; end else if (TransmitLoad) begin TransmitRegLoaded <= 1'b1; - end else if (ShiftEdge | EndOfFrameDelay) begin + end else if (ShiftEdge | EndOfFrame) begin TransmitRegLoaded <= 1'b0; end end @@ -272,7 +271,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( // State machine for starting transmissions always_comb begin case (CurrState) - READY: if (~TransmitFIFOReadEmpty & ~Transmitting) NextState = START; + READY: if (~TransmitFIFOEmpty & ~Transmitting) NextState = START; else NextState = READY; START: NextState = WAIT; 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; spi_fifo #(3,8) txFIFO(PCLK, 1'b1, SCLKenable, PRESETn, - TransmitFIFOWriteIncrement, TransmitFIFOReadIncrement, + TransmitFIFOWriteInc, TransmitFIFOReadInc, TransmitData[7:0], TransmitWriteWatermarkLevel, TransmitWatermark[2:0], - TransmitFIFOReadData[7:0], - TransmitFIFOWriteFull, - TransmitFIFOReadEmpty, + TransmitReadData[7:0], + TransmitFIFOFull, + TransmitFIFOEmpty, TransmitWriteMark, TransmitReadMark); - // Receive FIFO ---------------------------------------------------- always_ff @(posedge PCLK) if (~PRESETn) begin - ReceiveFIFOReadIncrement <= 1'b0; + ReceiveFIFOReadInc <= 1'b0; end else begin - ReceiveFIFOReadIncrement <= ((Entry == SPI_RXDATA) & ~ReceiveFIFOReadEmpty & PSEL & ~ReceiveFIFOReadIncrement); + ReceiveFIFOReadInc <= ((Entry == SPI_RXDATA) & ~ReceiveFIFOEmpty & PSEL & ~ReceiveFIFOReadInc); end always_ff @(posedge PCLK) if (~PRESETn) begin ReceiveFIFOWriteInc <= 1'b0; end else if (SCLKenable) begin - ReceiveFIFOWriteInc <= EndOfFrameDelay; + ReceiveFIFOWriteInc <= EndOfFrame; end - + spi_fifo #(3,8) rxFIFO(PCLK, SCLKenable, 1'b1, PRESETn, - ReceiveFIFOWriteInc, ReceiveFIFOReadIncrement, + ReceiveFIFOWriteInc, ReceiveFIFOReadInc, ReceiveShiftRegEndian, ReceiveWatermark[2:0], ReceiveReadWatermarkLevel, ReceiveData[7:0], - ReceiveFIFOWriteFull, - ReceiveFIFOReadEmpty, - RecieveWriteMark, RecieveReadMark); + ReceiveFIFOFull, + ReceiveFIFOEmpty, + ReceiveWriteMark, ReceiveReadMark); // Transmit shift register - assign TransmitLoad = TransmitStart | (EndOfFrameDelay & ~TransmitFIFOReadEmpty); - assign TransmitDataEndian = Format[0] ? {<<{TransmitFIFOReadData[7:0]}} : TransmitFIFOReadData[7:0]; + assign TransmitLoad = TransmitStart | (EndOfFrame & ~TransmitFIFOEmpty); + assign TransmitDataEndian = Format[0] ? {<<{TransmitReadData[7:0]}} : TransmitReadData[7:0]; always_ff @(posedge PCLK) if(~PRESETn) TransmitReg <= 8'b0; else if (TransmitLoad) TransmitReg <= TransmitDataEndian; diff --git a/src/uncore/spi_controller.sv b/src/uncore/spi_controller.sv index 19b32cab3..0400d2956 100644 --- a/src/uncore/spi_controller.sv +++ b/src/uncore/spi_controller.sv @@ -51,8 +51,7 @@ module spi_controller ( output logic SCLKenable, output logic ShiftEdge, output logic SampleEdge, - output logic EndOfFrame, - output logic EndOfFrameDelay, + output logic EndOfFrame, output logic Transmitting, output logic InactiveState, output logic SPICLK @@ -63,43 +62,31 @@ module spi_controller ( localparam AUTOMODE = 2'b00; localparam OFFMODE = 2'b11; + // FSM States typedef enum logic [2:0] {INACTIVE, CSSCK, TRANSMIT, SCKCS, HOLD, INTERCS, INTERXFR} statetype; statetype CurrState, NextState; // SCLKenable stuff logic [11:0] DivCounter; - // logic SCLKenable; - // logic SCLKenableEarly; - logic ZeroDiv; - logic SCK; // SUPER IMPORTANT, THIS CAN'T BE THE SAME AS SPICLK! - + logic SCK; // Shift and Sample Edges - logic PreShiftEdge; - logic PreSampleEdge; - // logic ShiftEdge; - // logic SampleEdge; + logic EdgePulse; logic ShiftEdgePulse; logic SampleEdgePulse; logic EndOfFramePulse; + logic PhaseOneOffset; // Frame stuff logic [3:0] BitNum; logic LastBit; - //logic EndOfFrame; - //logic EndOfFrameDelay; - logic PhaseOneOffset; // Transmit Stuff logic ContinueTransmit; - - // SPIOUT Stuff - // logic TransmitLoad; - logic [7:0] TransmitReg; - //logic Transmitting; logic EndTransmission; - - logic HoldMode; + logic ContinueTransmitD; // TODO: Could be replaced by TransmitRegLoaded? + logic NextEndDelay; + logic CurrentEndDelay; // Delay Stuff logic [7:0] cssck; @@ -116,13 +103,12 @@ module spi_controller ( logic EndOfSCKCS; logic EndOfINTERCS; logic EndOfINTERXFR; + logic EndOfDelay; - logic [7:0] CSSCKCounter; - logic [7:0] SCKCSCounter; - logic [7:0] INTERCSCounter; - logic [7:0] INTERXFRCounter; + logic [7:0] DelayCounter; logic DelayIsNext; + logic DelayState; // Convenient Delay Reg Names assign cssck = Delay0[7:0]; @@ -137,23 +123,25 @@ module spi_controller ( assign HasINTERXFR = interxfr > 8'b0; // Have we hit full delay for any of the delays? - assign EndOfCSSCK = CSSCKCounter == cssck; - assign EndOfSCKCS = SCKCSCounter == sckcs; - assign EndOfINTERCS = INTERCSCounter == intercs; - assign EndOfINTERXFR = INTERXFRCounter == interxfr; + assign EndOfCSSCK = (DelayCounter == cssck) & (CurrState == CSSCK); + assign EndOfSCKCS = (DelayCounter == sckcs) & (CurrState == SCKCS); + assign EndOfINTERCS = (DelayCounter == intercs) & (CurrState == INTERCS); + assign EndOfINTERXFR = (DelayCounter == interxfr) & (CurrState == INTERXFR); + + assign EndOfDelay = EndOfCSSCK | EndOfSCKCS | EndOfINTERCS | EndOfINTERXFR; // Clock Signal Stuff ----------------------------------------------- // I'm going to handle all clock stuff here, including ShiftEdge and // SampleEdge. This makes sure that SPICLK is an output of a register // and it properly synchronizes signals. - - assign SCLKenable = DivCounter == SckDiv; - // assign SCLKenableEarly = (DivCounter + 1'b1) == SckDiv; - assign LastBit = (BitNum == FrameLength - 4'b1); - //assign EndOfFrame = SCLKenable & LastBit & Transmitting; - assign ContinueTransmit = ~txFIFOReadEmpty & EndOfFrameDelay; - assign EndTransmission = txFIFOReadEmpty & EndOfFrameDelay; + // 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 ContinueTransmit = ~txFIFOReadEmpty & EndOfFrame; + assign EndTransmission = txFIFOReadEmpty & EndOfFrame; always_ff @(posedge PCLK) begin if (~PRESETn) begin @@ -161,13 +149,7 @@ module spi_controller ( SPICLK <= SckMode[1]; SCK <= 0; BitNum <= 4'h0; - PreShiftEdge <= 0; - PreSampleEdge <= 0; - EndOfFrame <= 0; - CSSCKCounter <= 0; - SCKCSCounter <= 0; - INTERCSCounter <= 0; - INTERXFRCounter <= 0; + DelayCounter <= 0; end else begin // TODO: Consolidate into one delay counter since none of the // delays happen at the same time? @@ -176,29 +158,12 @@ module spi_controller ( end else if (SCLKenable) begin SCK <= ~SCK; end - - if ((CurrState == CSSCK) & SCK & SCLKenable) begin - CSSCKCounter <= CSSCKCounter + 8'd1; - end else if (SCLKenable & EndOfCSSCK) begin - CSSCKCounter <= 8'd0; - end - - 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; + + // Counter for all four delay types + if (DelayState & SCK & SCLKenable) begin + DelayCounter <= DelayCounter + 8'd1; + end else if (SCLKenable & EndOfDelay) begin + DelayCounter <= 8'd0; end // SPICLK Logic @@ -215,85 +180,70 @@ module spi_controller ( DivCounter <= DivCounter + 12'd1; 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 if (ShiftEdge & Transmitting) begin BitNum <= BitNum + 4'd1; - end else if (EndOfFrameDelay) begin + end else if (EndOfFrame) begin BitNum <= 4'b0; 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 // Aligned EXACTLY ON THE MIDDLE of the leading and trailing edges. // Sweeeeeeeeeet... - - assign ShiftEdgePulse = SCLKenable & ~LastBit & Transmitting; - assign SampleEdgePulse = SCLKenable & Transmitting & ~DelayIsNext; - assign EndOfFramePulse = SCLKenable & LastBit & Transmitting; - always_ff @(posedge ~PCLK) begin if (~PRESETn | TransmitStart) begin ShiftEdge <= 0; PhaseOneOffset <= 0; SampleEdge <= 0; - EndOfFrameDelay <= 0; + EndOfFrame <= 0; end else begin - PhaseOneOffset <= (PhaseOneOffset == 0) ? Transmitting & SCLKenable : ~EndOfFrameDelay; + PhaseOneOffset <= (PhaseOneOffset == 0) ? Transmitting & SCLKenable : ~EndOfFrame; case(SckMode) 2'b00: begin ShiftEdge <= SPICLK & ShiftEdgePulse; SampleEdge <= ~SPICLK & SampleEdgePulse; - EndOfFrameDelay <= SPICLK & EndOfFramePulse; + EndOfFrame <= SPICLK & EndOfFramePulse; end 2'b01: begin ShiftEdge <= ~SPICLK & ShiftEdgePulse & PhaseOneOffset; SampleEdge <= SPICLK & SampleEdgePulse; - EndOfFrameDelay <= ~SPICLK & EndOfFramePulse; + EndOfFrame <= ~SPICLK & EndOfFramePulse; end 2'b10: begin ShiftEdge <= ~SPICLK & ShiftEdgePulse; SampleEdge <= SPICLK & SampleEdgePulse; - EndOfFrameDelay <= ~SPICLK & EndOfFramePulse; + EndOfFrame <= ~SPICLK & EndOfFramePulse; end 2'b11: begin ShiftEdge <= SPICLK & ShiftEdgePulse & PhaseOneOffset; SampleEdge <= ~SPICLK & SampleEdgePulse; - EndOfFrameDelay <= SPICLK & EndOfFramePulse; + EndOfFrame <= SPICLK & EndOfFramePulse; 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 end end - // typedef enum logic [2:0] {INACTIVE, CSSCK, TRANSMIT, SCKCS, HOLD, INTERCS, INTERXFR} statetype; - // statetype CurrState, NextState; - - assign HoldMode = CSMode == HOLDMODE; - // assign TransmitLoad = TransmitStart | (EndOfFrameDelay & ~txFIFOReadEmpty); - - logic ContinueTransmitD; - logic NextEndDelay; - logic CurrentEndDelay; - + // Logic for continuing to transmit through Delay states after end of frame assign NextEndDelay = NextState == SCKCS | NextState == INTERCS | NextState == INTERXFR; assign CurrentEndDelay = CurrState == SCKCS | CurrState == INTERCS | CurrState == INTERXFR; - + + // always_ff @(posedge PCLK) begin if (~PRESETn) begin ContinueTransmitD <= 1'b0; @@ -326,7 +276,7 @@ module spi_controller ( case(CSMode) AUTOMODE: begin if (EndTransmission) NextState = INACTIVE; - else if (EndOfFrameDelay) NextState = SCKCS; + else if (EndOfFrame) NextState = SCKCS; else NextState = TRANSMIT; end HOLDMODE: begin @@ -386,6 +336,7 @@ module spi_controller ( assign Transmitting = CurrState == TRANSMIT; 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; endmodule