From b667581ffabd2d73e117f037147c53b915c6e02e Mon Sep 17 00:00:00 2001 From: Jacob Pease Date: Tue, 29 Oct 2024 17:50:36 -0500 Subject: [PATCH 01/15] Refactored SPI peripheral based on SPI controller module. Works in tests/custom/spitest. --- src/uncore/spi_apb.sv | 707 ++++++++++++++--------------------- src/uncore/spi_controller.sv | 123 +++--- 2 files changed, 335 insertions(+), 495 deletions(-) diff --git a/src/uncore/spi_apb.sv b/src/uncore/spi_apb.sv index 54a072ac9..ebe0726c1 100644 --- a/src/uncore/spi_apb.sv +++ b/src/uncore/spi_apb.sv @@ -30,438 +30,305 @@ //////////////////////////////////////////////////////////////////////////////////////////////// module spi_apb import cvw::*; #(parameter cvw_t P) ( - input logic PCLK, PRESETn, - input logic PSEL, - input logic [7:0] PADDR, - input logic [P.XLEN-1:0] PWDATA, - input logic [P.XLEN/8-1:0] PSTRB, - input logic PWRITE, - input logic PENABLE, - output logic PREADY, - output logic [P.XLEN-1:0] PRDATA, - output logic SPIOut, - input logic SPIIn, - output logic [3:0] SPICS, - output logic SPIIntr, - output logic SPICLK + input logic PCLK, PRESETn, + input logic PSEL, + input logic [7:0] PADDR, + input logic [P.XLEN-1:0] PWDATA, + input logic [P.XLEN/8-1:0] PSTRB, + input logic PWRITE, + input logic PENABLE, + output logic PREADY, + output logic [P.XLEN-1:0] PRDATA, + output logic SPIOut, + input logic SPIIn, + output logic [3:0] SPICS, + output logic SPIIntr, + output logic SPICLK ); // register map - localparam SPI_SCKDIV = 8'h00; - localparam SPI_SCKMODE = 8'h04; - localparam SPI_CSID = 8'h10; - localparam SPI_CSDEF = 8'h14; - localparam SPI_CSMODE = 8'h18; - localparam SPI_DELAY0 = 8'h28; - localparam SPI_DELAY1 = 8'h2C; - localparam SPI_FMT = 8'h40; - localparam SPI_TXDATA = 8'h48; - localparam SPI_RXDATA = 8'h4C; - localparam SPI_TXMARK = 8'h50; - localparam SPI_RXMARK = 8'h54; - 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; - logic [1:0] ChipSelectID; - logic [3:0] ChipSelectDef; - logic [1:0] ChipSelectMode; - logic [15:0] Delay0, Delay1; - logic [4:0] Format; - logic [7:0] ReceiveData; - logic [2:0] TransmitWatermark, ReceiveWatermark; - logic [8:0] TransmitData; - 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 - - // FIFO FSM signals - // Watermark signals - TransmitReadMark = ip[0], ReceiveWriteMark = ip[1] - logic TransmitWriteMark, TransmitReadMark, RecieveWriteMark, RecieveReadMark; - logic TransmitFIFOWriteFull, TransmitFIFOReadEmpty; - logic TransmitFIFOWriteIncrement; - 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 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 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 - - // Account for subword read/write circuitry - // -- Note SPI registers are 32 bits no matter what; access them with LW SW. - - assign Din = PWDATA[31:0]; - if (P.XLEN == 64) assign PRDATA = { Dout, Dout}; - else assign PRDATA = Dout; - - // Register access - always_ff@(posedge PCLK) - if (~PRESETn) begin - SckDiv <= 12'd3; - SckMode <= 2'b0; - ChipSelectID <= 2'b0; - ChipSelectDef <= 4'b1111; - ChipSelectMode <= 2'b0; - Delay0 <= {8'b1,8'b1}; - Delay1 <= {8'b0,8'b1}; - Format <= {5'b10000}; - TransmitData <= 9'b0; - TransmitWatermark <= 3'b0; - ReceiveWatermark <= 3'b0; - InterruptEnable <= 2'b0; - InterruptPending <= 2'b0; - end else begin // writes - - - /* verilator lint_off CASEINCOMPLETE */ - if (Memwrite & TransmitInactive) - case(Entry) // flop to sample inputs - SPI_SCKDIV: SckDiv <= Din[11:0]; - SPI_SCKMODE: SckMode <= Din[1:0]; - SPI_CSID: ChipSelectID <= Din[1:0]; - SPI_CSDEF: ChipSelectDef <= Din[3:0]; - SPI_CSMODE: ChipSelectMode <= Din[1:0]; - SPI_DELAY0: Delay0 <= {Din[23:16], Din[7:0]}; - SPI_DELAY1: Delay1 <= {Din[23:16], Din[7:0]}; - SPI_FMT: Format <= {Din[19:16], Din[2]}; - SPI_TXMARK: TransmitWatermark <= Din[2:0]; - SPI_RXMARK: ReceiveWatermark <= Din[2:0]; - SPI_IE: InterruptEnable <= Din[1:0]; - endcase - - if (Memwrite) - case(Entry) - SPI_TXDATA: if (~TransmitFIFOWriteFull) 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; - - case(Entry) // Flop to sample inputs - SPI_SCKDIV: Dout <= {20'b0, SckDiv}; - SPI_SCKMODE: Dout <= {30'b0, SckMode}; - SPI_CSID: Dout <= {30'b0, ChipSelectID}; - SPI_CSDEF: Dout <= {28'b0, ChipSelectDef}; - SPI_CSMODE: Dout <= {30'b0, ChipSelectMode}; - 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_TXMARK: Dout <= {29'b0, TransmitWatermark}; - SPI_RXMARK: Dout <= {29'b0, ReceiveWatermark}; - SPI_IE: Dout <= {30'b0, InterruptEnable}; - SPI_IP: Dout <= {30'b0, InterruptPending}; - default: Dout <= 32'b0; - 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)). 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; - - // 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 - 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; + localparam SPI_SCKDIV = 8'h00; + localparam SPI_SCKMODE = 8'h04; + localparam SPI_CSID = 8'h10; + localparam SPI_CSDEF = 8'h14; + localparam SPI_CSMODE = 8'h18; + localparam SPI_DELAY0 = 8'h28; + localparam SPI_DELAY1 = 8'h2C; + localparam SPI_FMT = 8'h40; + localparam SPI_TXDATA = 8'h48; + localparam SPI_RXDATA = 8'h4C; + localparam SPI_TXMARK = 8'h50; + localparam SPI_RXMARK = 8'h54; + localparam SPI_IE = 8'h70; + localparam SPI_IP = 8'h74; - 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; + // SPI control registers. Refer to SiFive FU540-C000 manual + logic [11:0] SckDiv; + logic [1:0] SckMode; + logic [1:0] ChipSelectID; + logic [3:0] ChipSelectDef; + logic [1:0] ChipSelectMode; + logic [15:0] Delay0, Delay1; + logic [4:0] Format; + logic [7:0] ReceiveData; + 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; + // SPI Controller signals + logic SCLKenable; + logic EndOfFrame; + logic EndOfFrameDelay; + logic Transmitting; + logic InactiveState; + logic ResetSCLKenable; + logic TransmitStart; - // 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; + // 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 [7:0] TransmitFIFOReadData; - always_ff @(posedge PCLK) - if (~PRESETn) begin - state <= CS_INACTIVE; - FrameCount <= 4'b0; - SPICLK <= SckMode[1]; - end else if (SCLKenable) begin + logic ReceiveFIFOWriteInc; + logic ReceiveFIFOReadIncrement; + logic ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty; + + /* 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) + + // 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 [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 + + // 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 + + // 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 + + // 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; + assign PREADY = 1'b1; + + // Account for subword read/write circuitry + // -- Note SPI registers are 32 bits no matter what; access them with LW SW. + + assign Din = PWDATA[31:0]; + if (P.XLEN == 64) assign PRDATA = { Dout, Dout}; + else assign PRDATA = Dout; + + // Register access + always_ff@(posedge PCLK) + if (~PRESETn) begin + SckDiv <= 12'd3; + SckMode <= 2'b0; + ChipSelectID <= 2'b0; + ChipSelectDef <= 4'b1111; + ChipSelectMode <= 2'b0; + Delay0 <= {8'b1,8'b1}; + Delay1 <= {8'b0,8'b1}; + Format <= {5'b10000}; + TransmitData <= 9'b0; + TransmitWatermark <= 3'b0; + ReceiveWatermark <= 3'b0; + InterruptEnable <= 2'b0; + InterruptPending <= 2'b0; + end else begin // writes /* 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]; - 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 - endcase - /* verilator lint_off CASEINCOMPLETE */ - end - - - - 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; - - // 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; + if (Memwrite) + case(Entry) // flop to sample inputs + SPI_SCKDIV: SckDiv <= Din[11:0]; + SPI_SCKMODE: SckMode <= Din[1:0]; + SPI_CSID: ChipSelectID <= Din[1:0]; + SPI_CSDEF: ChipSelectDef <= Din[3:0]; + SPI_CSMODE: ChipSelectMode <= Din[1:0]; + SPI_DELAY0: Delay0 <= {Din[23:16], Din[7:0]}; + SPI_DELAY1: Delay1 <= {Din[23:16], Din[7:0]}; + SPI_FMT: Format <= {Din[19:16], Din[2]}; + SPI_TXMARK: TransmitWatermark <= Din[2:0]; + SPI_RXMARK: ReceiveWatermark <= Din[2:0]; + SPI_IE: InterruptEnable <= Din[1:0]; 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 (TransmitShiftRegLoadSingleCycle) TransmitShiftReg <= TransmitDataEndian; - else if (ShiftEdge & Active) TransmitShiftReg <= {TransmitShiftReg[6:0], TransmitShiftReg[0]}; - - assign SPIOut = TransmitShiftReg[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 - 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 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]; - - // Interrupt logic: raise interrupt if any enabled interrupts are pending - assign SPIIntr = |(InterruptPending & InterruptEnable); - - // Chip select logic - always_comb - case(ChipSelectID[1:0]) - 2'b00: ChipSelectAuto = {ChipSelectDef[3], ChipSelectDef[2], ChipSelectDef[1], ChipSelectInternal[0]}; - 2'b01: ChipSelectAuto = {ChipSelectDef[3],ChipSelectDef[2], ChipSelectInternal[1], ChipSelectDef[0]}; - 2'b10: ChipSelectAuto = {ChipSelectDef[3],ChipSelectInternal[2], ChipSelectDef[1], ChipSelectDef[0]}; - 2'b11: ChipSelectAuto = {ChipSelectInternal[3],ChipSelectDef[2], ChipSelectDef[1], ChipSelectDef[0]}; + if (Memwrite) + case(Entry) + SPI_TXDATA: if (~TransmitFIFOWriteFull) 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; + + case(Entry) // Flop to sample inputs + SPI_SCKDIV: Dout <= {20'b0, SckDiv}; + SPI_SCKMODE: Dout <= {30'b0, SckMode}; + SPI_CSID: Dout <= {30'b0, ChipSelectID}; + SPI_CSDEF: Dout <= {28'b0, ChipSelectDef}; + SPI_CSMODE: Dout <= {30'b0, ChipSelectMode}; + 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_TXMARK: Dout <= {29'b0, TransmitWatermark}; + SPI_RXMARK: Dout <= {29'b0, ReceiveWatermark}; + SPI_IE: Dout <= {30'b0, InterruptEnable}; + SPI_IP: Dout <= {30'b0, InterruptPending}; + default: Dout <= 32'b0; + endcase + end - assign SPICS = ChipSelectMode[0] ? ChipSelectDef : ChipSelectAuto; + // 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); + + 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 + 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 + CurrState <= NextState; + end + 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 + 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); + + + // 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 + + 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 TransmitLoad = TransmitStart | (EndOfFrameDelay & ~TransmitFIFOReadEmpty); + assign TransmitDataEndian = Format[0] ? {<<{TransmitFIFOReadData[7:0]}} : TransmitFIFOReadData[7:0]; + always_ff @(posedge PCLK) + if(~PRESETn) TransmitReg <= 8'b0; + else if (TransmitLoad) TransmitReg <= TransmitDataEndian; + else if (ShiftEdge) TransmitReg <= {TransmitReg[6:0], TransmitReg[0]}; + + 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 + assign ShiftIn = P.SPI_LOOPBACK_TEST ? SPIOut : SPIIn; + + // Receive shift register + always_ff @(posedge PCLK) + if(~PRESETn) 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[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]}; + 2'b01: ChipSelectAuto = {ChipSelectDef[3],ChipSelectDef[2], ChipSelectInternal[1], ChipSelectDef[0]}; + 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 diff --git a/src/uncore/spi_controller.sv b/src/uncore/spi_controller.sv index c4305047e..9692b7588 100644 --- a/src/uncore/spi_controller.sv +++ b/src/uncore/spi_controller.sv @@ -28,21 +28,33 @@ // and limitations under the License. //////////////////////////////////////////////////////////////////////////////////////////////// - -module spi_controller ( +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, + input logic [15:0] Delay0, + input logic [15:0] Delay1, + + // 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 From 4f0723f23618509255922671127d1eba00769c53 Mon Sep 17 00:00:00 2001 From: Jacob Pease Date: Wed, 30 Oct 2024 16:19:46 -0500 Subject: [PATCH 02/15] Fixed enabling of TransmitFIFOReadIncrement and ReceiveFIFOWriteIncrement --- src/uncore/spi_apb.sv | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/uncore/spi_apb.sv b/src/uncore/spi_apb.sv index ebe0726c1..8442cd1b7 100644 --- a/src/uncore/spi_apb.sv +++ b/src/uncore/spi_apb.sv @@ -231,17 +231,22 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( always_ff @(posedge PCLK) if (~PRESETn) begin TransmitFIFOWriteIncrement <= 1'b0; - TransmitFIFOReadIncrement <= 1'b0; end else begin TransmitFIFOWriteIncrement <= (Memwrite & (Entry == SPI_TXDATA) & ~TransmitFIFOWriteFull); - TransmitFIFOReadIncrement <= TransmitLoad; end + always_ff @(posedge PCLK) + if (~PRESETn) begin + TransmitFIFOReadIncrement <= 1'b0; + end else if (SCLKenable) begin + TransmitFIFOReadIncrement <= TransmitLoad; + end + // Setup TransmitStart state machine always_ff @(posedge PCLK) begin if (~PRESETn) begin CurrState <= READY; - end else if (SCLKenable) begin + end else begin CurrState <= NextState; end end @@ -273,9 +278,14 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( always_ff @(posedge PCLK) if (~PRESETn) begin ReceiveFIFOReadIncrement <= 1'b0; - ReceiveFIFOWriteInc <= 1'b0; end else begin ReceiveFIFOReadIncrement <= ((Entry == SPI_RXDATA) & ~ReceiveFIFOReadEmpty & PSEL & ~ReceiveFIFOReadIncrement); + end + + always_ff @(posedge PCLK) + if (~PRESETn) begin + ReceiveFIFOWriteInc <= 1'b0; + end else if (SCLKenable) begin ReceiveFIFOWriteInc <= EndOfFrameDelay; end From 4e7e311b26756d724b4531df619bdedca9f716ac Mon Sep 17 00:00:00 2001 From: Jacob Pease Date: Wed, 30 Oct 2024 18:39:04 -0500 Subject: [PATCH 03/15] Fixed issues relating to SCLKenable and TransmitStart. Works at multiple dividers now, instead of just SckDiv = 0. --- src/uncore/spi_apb.sv | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/uncore/spi_apb.sv b/src/uncore/spi_apb.sv index 8442cd1b7..33978637b 100644 --- a/src/uncore/spi_apb.sv +++ b/src/uncore/spi_apb.sv @@ -89,6 +89,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( logic ResetSCLKenable; logic TransmitStart; + logic TransmitStartD; // Transmit Start State Machine Variables typedef enum logic [1:0] {READY, START, WAIT} txState; @@ -215,7 +216,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( spi_controller controller(PCLK, PRESETn, // Transmit Signals - TransmitStart, ResetSCLKenable, + TransmitStart, TransmitStartD, ResetSCLKenable, // Register Inputs SckDiv, SckMode, ChipSelectMode, Delay0, Delay1, // txFIFO stuff @@ -239,7 +240,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( if (~PRESETn) begin TransmitFIFOReadIncrement <= 1'b0; end else if (SCLKenable) begin - TransmitFIFOReadIncrement <= TransmitLoad; + TransmitFIFOReadIncrement <= TransmitStartD | (EndOfFrameDelay & ~TransmitFIFOReadEmpty) ; end // Setup TransmitStart state machine @@ -254,7 +255,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( // State machine for starting transmissions always_comb begin case (CurrState) - READY: if (~TransmitFIFOReadEmpty) NextState = START; + READY: if (~TransmitFIFOReadEmpty & ~Transmitting) NextState = START; else NextState = READY; START: NextState = WAIT; WAIT: if (TransmitFIFOReadEmpty & ~Transmitting) NextState = READY; @@ -263,6 +264,10 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( end assign TransmitStart = (CurrState == START); + always_ff @(posedge PCLK) + if (~PRESETn) TransmitStartD <= 1'b0; + else if (TransmitStart) TransmitStartD <= 1'b1; + else if (SCLKenable) TransmitStartD <= 1'b0; spi_fifo #(3,8) txFIFO(PCLK, 1'b1, SCLKenable, PRESETn, TransmitFIFOWriteIncrement, TransmitFIFOReadIncrement, From 35c9fe764803e6d3d905b19e2c7e9fc158b88f1c Mon Sep 17 00:00:00 2001 From: Jacob Pease Date: Wed, 30 Oct 2024 18:45:54 -0500 Subject: [PATCH 04/15] Added changed SPI controller module. New signal TransmitStartD that starts the FSM based on SCLKenable. TransmitStart is responsible for resetting SCLKenable and loading the Transmit Shift Register. --- src/uncore/spi_controller.sv | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/uncore/spi_controller.sv b/src/uncore/spi_controller.sv index 9692b7588..d3c800102 100644 --- a/src/uncore/spi_controller.sv +++ b/src/uncore/spi_controller.sv @@ -34,7 +34,8 @@ module spi_controller ( // Start Transmission input logic TransmitStart, - input logic ResetSCLKenable, + input logic TransmitStartD, + input logic ResetSCLKenable, // Registers input logic [11:0] SckDiv, @@ -168,25 +169,25 @@ module spi_controller ( SCK <= ~SCK; end - if ((CurrState == CSSCK) & SCK) begin + if ((CurrState == CSSCK) & SCK & SCLKenable) begin CSSCKCounter <= CSSCKCounter + 8'd1; - end else begin + end else if (SCLKenable) begin CSSCKCounter <= 8'd0; end - if ((CurrState == SCKCS) & SCK) begin + if ((CurrState == SCKCS) & SCK & SCLKenable) begin SCKCSCounter <= SCKCSCounter + 8'd1; - end else begin + end else if (SCLKenable) begin SCKCSCounter <= 8'd0; end - if ((CurrState == INTERCS) & SCK) begin + if ((CurrState == INTERCS) & SCK & SCLKenable) begin INTERCSCounter <= INTERCSCounter + 8'd1; end else begin INTERCSCounter <= 8'd0; end - if ((CurrState == INTERXFR) & SCK) begin + if ((CurrState == INTERXFR) & SCK & SCLKenable) begin INTERXFRCounter <= INTERXFRCounter + 8'd1; end else begin INTERXFRCounter <= 8'd0; @@ -259,7 +260,7 @@ module spi_controller ( always_comb begin case (CurrState) - INACTIVE: if (TransmitStart) + INACTIVE: if (TransmitStartD) if (~HasCSSCK) NextState = TRANSMIT; else NextState = CSSCK; else NextState = INACTIVE; @@ -293,7 +294,7 @@ module spi_controller ( HOLD: begin // HOLD mode case ----------------------------------- if (CSMode == AUTOMODE) begin NextState = INACTIVE; - end else if (TransmitStart) begin // If FIFO is written to, start again. + end else if (TransmitStartD) begin // If FIFO is written to, start again. NextState = TRANSMIT; end else NextState = HOLD; end From 419030bc331483042c8c85b557d5276b2d5fa74c Mon Sep 17 00:00:00 2001 From: Jacob Pease Date: Thu, 31 Oct 2024 10:41:38 -0500 Subject: [PATCH 05/15] Fixed FSM to continue transmitting after delay. --- src/uncore/spi_controller.sv | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/uncore/spi_controller.sv b/src/uncore/spi_controller.sv index d3c800102..10ff511a6 100644 --- a/src/uncore/spi_controller.sv +++ b/src/uncore/spi_controller.sv @@ -148,7 +148,8 @@ module spi_controller ( // assign SCLKenableEarly = (DivCounter + 1'b1) == SckDiv; assign LastBit = BitNum == 3'd7; - assign ContinueTransmit = ~txFIFOReadEmpty & EndOfFrame; + //assign EndOfFrame = SCLKenable & LastBit & Transmitting; + assign ContinueTransmit = ~txFIFOReadEmpty & EndOfFrameDelay; assign EndTransmission = txFIFOReadEmpty & EndOfFrameDelay; always_ff @(posedge PCLK) begin @@ -183,13 +184,13 @@ module spi_controller ( if ((CurrState == INTERCS) & SCK & SCLKenable) begin INTERCSCounter <= INTERCSCounter + 8'd1; - end else begin + end else if (SCLKenable) begin INTERCSCounter <= 8'd0; end if ((CurrState == INTERXFR) & SCK & SCLKenable) begin INTERXFRCounter <= INTERXFRCounter + 8'd1; - end else begin + end else if (SCLKenable) begin INTERXFRCounter <= 8'd0; end @@ -239,7 +240,7 @@ module spi_controller ( end else begin ShiftEdge <= ((SckMode[1] ^ SckMode[0] ^ SPICLK) & SCLKenable & ~LastBit & Transmitting) & PhaseOneOffset; PhaseOneOffset <= PhaseOneOffset == 0 ? Transmitting & SCLKenable : PhaseOneOffset; - SampleEdge <= (SckMode[1] ^ SckMode[0] ^ ~SPICLK) & SCLKenable & Transmitting; + SampleEdge <= (SckMode[1] ^ SckMode[0] ^ ~SPICLK) & SCLKenable & Transmitting & ~DelayIsNext; EndOfFrameDelay <= (SckMode[1] ^ SckMode[0] ^ SPICLK) & SCLKenable & LastBit & Transmitting; end end @@ -284,12 +285,13 @@ module spi_controller ( end SCKCS: begin // SCKCS case -------------------------------------- if (EndOfSCKCS) - if (EndTransmission) + if (txFIFOReadEmpty) begin if (CSMode == AUTOMODE) NextState = INACTIVE; else if (CSMode == HOLDMODE) NextState = HOLD; - else if (ContinueTransmit) + end else if (~txFIFOReadEmpty) begin if (HasINTERCS) NextState = INTERCS; else NextState = TRANSMIT; + end end HOLD: begin // HOLD mode case ----------------------------------- if (CSMode == AUTOMODE) begin From 72a854eb075f90fde3fa9bfb6ba653845c2d54f6 Mon Sep 17 00:00:00 2001 From: Jacob Pease Date: Thu, 31 Oct 2024 13:01:25 -0500 Subject: [PATCH 06/15] Refactored SPI passes regression save for hardware interlock tests. --- src/uncore/spi_apb.sv | 21 ++++++++++++-- src/uncore/spi_controller.sv | 53 +++++++++++++++++++++++++++--------- 2 files changed, 58 insertions(+), 16 deletions(-) diff --git a/src/uncore/spi_apb.sv b/src/uncore/spi_apb.sv index 33978637b..c8084de42 100644 --- a/src/uncore/spi_apb.sv +++ b/src/uncore/spi_apb.sv @@ -86,6 +86,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( logic EndOfFrameDelay; logic Transmitting; logic InactiveState; + logic [3:0] FrameLength; logic ResetSCLKenable; logic TransmitStart; @@ -213,12 +214,13 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( // SPI Controller module ------------------------------------------- // This module controls state and timing signals that drive the rest of this module assign ResetSCLKenable = Memwrite & (Entry == SPI_SCKDIV); + assign FrameLength = Format[4:1]; spi_controller controller(PCLK, PRESETn, // Transmit Signals TransmitStart, TransmitStartD, ResetSCLKenable, // Register Inputs - SckDiv, SckMode, ChipSelectMode, Delay0, Delay1, + SckDiv, SckMode, ChipSelectMode, Delay0, Delay1, FrameLength, // txFIFO stuff TransmitFIFOReadEmpty, // Timing @@ -243,6 +245,19 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( TransmitFIFOReadIncrement <= TransmitStartD | (EndOfFrameDelay & ~TransmitFIFOReadEmpty) ; 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 + TransmitRegLoaded <= 1'b0; + end + end + // Setup TransmitStart state machine always_ff @(posedge PCLK) begin if (~PRESETn) begin @@ -251,14 +266,14 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( CurrState <= NextState; end end - + // State machine for starting transmissions always_comb begin case (CurrState) READY: if (~TransmitFIFOReadEmpty & ~Transmitting) NextState = START; else NextState = READY; START: NextState = WAIT; - WAIT: if (TransmitFIFOReadEmpty & ~Transmitting) NextState = READY; + WAIT: if (TransmitFIFOReadEmpty & ~Transmitting & ~TransmitRegLoaded) NextState = READY; else NextState = WAIT; endcase end diff --git a/src/uncore/spi_controller.sv b/src/uncore/spi_controller.sv index 10ff511a6..2b74e79c9 100644 --- a/src/uncore/spi_controller.sv +++ b/src/uncore/spi_controller.sv @@ -43,6 +43,7 @@ module spi_controller ( input logic [1:0] CSMode, input logic [15:0] Delay0, input logic [15:0] Delay1, + input logic [3:0] FrameLength, // Is the Transmit FIFO Empty? input logic txFIFOReadEmpty, @@ -146,7 +147,7 @@ module spi_controller ( assign SCLKenable = DivCounter == SckDiv; // assign SCLKenableEarly = (DivCounter + 1'b1) == SckDiv; - assign LastBit = BitNum == 3'd7; + assign LastBit = (BitNum == FrameLength - 4'b1); //assign EndOfFrame = SCLKenable & LastBit & Transmitting; assign ContinueTransmit = ~txFIFOReadEmpty & EndOfFrameDelay; @@ -161,6 +162,10 @@ module spi_controller ( PreShiftEdge <= 0; PreSampleEdge <= 0; EndOfFrame <= 0; + CSSCKCounter <= 0; + SCKCSCounter <= 0; + INTERCSCounter <= 0; + INTERXFRCounter <= 0; end else begin // TODO: Consolidate into one delay counter since none of the // delays happen at the same time? @@ -172,25 +177,25 @@ module spi_controller ( if ((CurrState == CSSCK) & SCK & SCLKenable) begin CSSCKCounter <= CSSCKCounter + 8'd1; - end else if (SCLKenable) begin + end else if (SCLKenable & EndOfCSSCK) begin CSSCKCounter <= 8'd0; end if ((CurrState == SCKCS) & SCK & SCLKenable) begin SCKCSCounter <= SCKCSCounter + 8'd1; - end else if (SCLKenable) begin + end else if (SCLKenable & EndOfSCKCS) begin SCKCSCounter <= 8'd0; end if ((CurrState == INTERCS) & SCK & SCLKenable) begin INTERCSCounter <= INTERCSCounter + 8'd1; - end else if (SCLKenable) begin + end else if (SCLKenable & EndOfINTERCS) begin INTERCSCounter <= 8'd0; end if ((CurrState == INTERXFR) & SCK & SCLKenable) begin INTERXFRCounter <= INTERXFRCounter + 8'd1; - end else if (SCLKenable) begin + end else if (SCLKenable & EndOfINTERXFR) begin INTERXFRCounter <= 8'd0; end @@ -239,7 +244,7 @@ module spi_controller ( EndOfFrameDelay <= 0; end else begin ShiftEdge <= ((SckMode[1] ^ SckMode[0] ^ SPICLK) & SCLKenable & ~LastBit & Transmitting) & PhaseOneOffset; - PhaseOneOffset <= PhaseOneOffset == 0 ? Transmitting & SCLKenable : 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; end @@ -251,6 +256,23 @@ module spi_controller ( assign HoldMode = CSMode == HOLDMODE; // assign TransmitLoad = TransmitStart | (EndOfFrameDelay & ~txFIFOReadEmpty); + logic ContinueTransmitD; + logic NextEndDelay; + logic CurrentEndDelay; + + 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; + end else if (NextEndDelay & ~CurrentEndDelay) begin + ContinueTransmitD <= ContinueTransmit; + end else if (EndOfSCKCS & SCLKenable) begin + ContinueTransmitD <= 1'b0; + end + end + always_ff @(posedge PCLK) begin if (~PRESETn) begin CurrState <= INACTIVE; @@ -261,17 +283,19 @@ module spi_controller ( always_comb begin case (CurrState) - INACTIVE: if (TransmitStartD) + INACTIVE: if (TransmitStartD) begin if (~HasCSSCK) NextState = TRANSMIT; else NextState = CSSCK; - else NextState = INACTIVE; + end else begin + NextState = INACTIVE; + end CSSCK: if (EndOfCSSCK) NextState = TRANSMIT; else NextState = CSSCK; TRANSMIT: begin // TRANSMIT case -------------------------------- case(CSMode) AUTOMODE: begin if (EndTransmission) NextState = INACTIVE; - else if (ContinueTransmit) NextState = SCKCS; + else if (EndOfFrameDelay) NextState = SCKCS; end HOLDMODE: begin if (EndTransmission) NextState = HOLD; @@ -279,19 +303,22 @@ module spi_controller ( else NextState = TRANSMIT; end OFFMODE: begin - + if (EndTransmission) NextState = INACTIVE; + else if (ContinueTransmit & HasINTERXFR) NextState = INTERXFR; + else NextState = TRANSMIT; end endcase end SCKCS: begin // SCKCS case -------------------------------------- - if (EndOfSCKCS) - if (txFIFOReadEmpty) begin + if (EndOfSCKCS) begin + if (~ContinueTransmitD) begin if (CSMode == AUTOMODE) NextState = INACTIVE; else if (CSMode == HOLDMODE) NextState = HOLD; - end else if (~txFIFOReadEmpty) begin + end else begin if (HasINTERCS) NextState = INTERCS; else NextState = TRANSMIT; end + end end HOLD: begin // HOLD mode case ----------------------------------- if (CSMode == AUTOMODE) begin From 3ee5fffe02b3276a40c1eb99863db1ae19424d71 Mon Sep 17 00:00:00 2001 From: Jacob Pease Date: Thu, 31 Oct 2024 13:54:56 -0500 Subject: [PATCH 07/15] Fixing latches. --- src/uncore/spi_apb.sv | 1 + src/uncore/spi_controller.sv | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/src/uncore/spi_apb.sv b/src/uncore/spi_apb.sv index c8084de42..911ab3a15 100644 --- a/src/uncore/spi_apb.sv +++ b/src/uncore/spi_apb.sv @@ -275,6 +275,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( START: NextState = WAIT; WAIT: if (TransmitFIFOReadEmpty & ~Transmitting & ~TransmitRegLoaded) NextState = READY; else NextState = WAIT; + default: NextState = READY; endcase end diff --git a/src/uncore/spi_controller.sv b/src/uncore/spi_controller.sv index 2b74e79c9..10ad09f91 100644 --- a/src/uncore/spi_controller.sv +++ b/src/uncore/spi_controller.sv @@ -296,6 +296,7 @@ module spi_controller ( AUTOMODE: begin if (EndTransmission) NextState = INACTIVE; else if (EndOfFrameDelay) NextState = SCKCS; + else NextState = TRANSMIT; end HOLDMODE: begin if (EndTransmission) NextState = HOLD; @@ -307,6 +308,7 @@ module spi_controller ( else if (ContinueTransmit & HasINTERXFR) NextState = INTERXFR; else NextState = TRANSMIT; end + default: NextState = TRANSMIT; endcase end SCKCS: begin // SCKCS case -------------------------------------- @@ -318,6 +320,8 @@ module spi_controller ( if (HasINTERCS) NextState = INTERCS; else NextState = TRANSMIT; end + end else begin + NextState = SCKCS; end end HOLD: begin // HOLD mode case ----------------------------------- @@ -331,11 +335,15 @@ module spi_controller ( if (EndOfINTERCS) begin if (HasCSSCK) NextState = CSSCK; else NextState = TRANSMIT; + end else begin + NextState = INTERCS; end end INTERXFR: begin // INTERXFR case -------------------------------- if (EndOfINTERXFR) begin NextState = TRANSMIT; + end else begin + NextState = INTERXFR; end end default: begin From 56a6ad3376276ece7ca22ae3979346b43d20babf Mon Sep 17 00:00:00 2001 From: Jacob Pease Date: Thu, 31 Oct 2024 15:56:16 -0500 Subject: [PATCH 08/15] Fixed lint issues. --- src/uncore/spi_apb.sv | 5 +++-- src/uncore/spi_controller.sv | 10 +++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/uncore/spi_apb.sv b/src/uncore/spi_apb.sv index 911ab3a15..5d3352154 100644 --- a/src/uncore/spi_apb.sv +++ b/src/uncore/spi_apb.sv @@ -337,8 +337,9 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( // Receive shift register always_ff @(posedge PCLK) - if(~PRESETn) ReceiveShiftReg <= 8'b0; - else if (SampleEdge) begin + if(~PRESETn) begin + ReceiveShiftReg <= 8'b0; + end else if (SampleEdge) begin if (~Transmitting) ReceiveShiftReg <= 8'b0; else ReceiveShiftReg <= {ReceiveShiftReg[6:0], ShiftIn}; end diff --git a/src/uncore/spi_controller.sv b/src/uncore/spi_controller.sv index 10ad09f91..605685b4b 100644 --- a/src/uncore/spi_controller.sv +++ b/src/uncore/spi_controller.sv @@ -82,7 +82,7 @@ module spi_controller ( // logic SampleEdge; // Frame stuff - logic [2:0] BitNum; + logic [3:0] BitNum; logic LastBit; //logic EndOfFrame; //logic EndOfFrameDelay; @@ -158,7 +158,7 @@ module spi_controller ( DivCounter <= 12'b0; SPICLK <= SckMode[1]; SCK <= 0; - BitNum <= 3'h0; + BitNum <= 4'h0; PreShiftEdge <= 0; PreSampleEdge <= 0; EndOfFrame <= 0; @@ -210,7 +210,7 @@ module spi_controller ( if (SCLKenable | TransmitStart | ResetSCLKenable) begin DivCounter <= 12'b0; end else begin - DivCounter = DivCounter + 12'd1; + DivCounter <= DivCounter + 12'd1; end // EndOfFrame controller @@ -226,9 +226,9 @@ module spi_controller ( // Increment BitNum if (ShiftEdge & Transmitting) begin - BitNum <= BitNum + 3'd1; + BitNum <= BitNum + 4'd1; end else if (EndOfFrameDelay) begin - BitNum <= 3'b0; + BitNum <= 4'b0; end end end From eddae8e1a676045cf10144af5238ef62c8c43799 Mon Sep 17 00:00:00 2001 From: Jacob Pease Date: Fri, 1 Nov 2024 13:02:17 -0500 Subject: [PATCH 09/15] Fixed ShiftEdge and SampleEdge to not always include PhaseOneOffset. Before, it worked in simulation, but not on the FPGA. --- src/uncore/spi_controller.sv | 37 ++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/src/uncore/spi_controller.sv b/src/uncore/spi_controller.sv index 605685b4b..576884374 100644 --- a/src/uncore/spi_controller.sv +++ b/src/uncore/spi_controller.sv @@ -243,10 +243,34 @@ module spi_controller ( SampleEdge <= 0; EndOfFrameDelay <= 0; end else begin - 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; + case(SckMode) + 2'b00: begin + ShiftEdge <= SPICLK & SCLKenable & ~LastBit & Transmitting; + SampleEdge <= ~SPICLK & SCLKenable & Transmitting & ~DelayIsNext; + EndOfFrameDelay <= SPICLK & SCLKenable & LastBit & Transmitting; + end + 2'b01: begin + ShiftEdge <= ~SPICLK & SCLKenable & ~LastBit & Transmitting & PhaseOneOffset; + SampleEdge <= SPICLK & SCLKenable & Transmitting & ~DelayIsNext; + EndOfFrameDelay <= ~SPICLK & SCLKenable & LastBit & Transmitting; + PhaseOneOffset <= (PhaseOneOffset == 0) ? Transmitting & SCLKenable : ~EndOfFrameDelay; + end + 2'b10: begin + ShiftEdge <= ~SPICLK & SCLKenable & ~LastBit & Transmitting; + SampleEdge <= SPICLK & SCLKenable & Transmitting & ~DelayIsNext; + EndOfFrameDelay <= ~SPICLK & SCLKenable & LastBit & Transmitting; + end + 2'b11: begin + ShiftEdge <= SPICLK & SCLKenable & ~LastBit & Transmitting & PhaseOneOffset; + SampleEdge <= ~SPICLK & SCLKenable & Transmitting & ~DelayIsNext; + EndOfFrameDelay <= SPICLK & SCLKenable & LastBit & Transmitting; + PhaseOneOffset <= (PhaseOneOffset == 0) ? Transmitting & SCLKenable : ~EndOfFrameDelay; + 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 @@ -314,8 +338,9 @@ module spi_controller ( SCKCS: begin // SCKCS case -------------------------------------- if (EndOfSCKCS) begin if (~ContinueTransmitD) begin - if (CSMode == AUTOMODE) NextState = INACTIVE; - else if (CSMode == HOLDMODE) NextState = HOLD; + // if (CSMode == AUTOMODE) NextState = INACTIVE; + if (CSMode == HOLDMODE) NextState = HOLD; + else NextState = INACTIVE; end else begin if (HasINTERCS) NextState = INTERCS; else NextState = TRANSMIT; From e881bd31203a04a0c6e84b57dafd1461533a0b4f Mon Sep 17 00:00:00 2001 From: Jacob Pease Date: Fri, 1 Nov 2024 17:04:07 -0500 Subject: [PATCH 10/15] Changed the condition for TransmitStart fsm to avoid edge condition. --- src/uncore/spi_apb.sv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uncore/spi_apb.sv b/src/uncore/spi_apb.sv index 5d3352154..a15068f10 100644 --- a/src/uncore/spi_apb.sv +++ b/src/uncore/spi_apb.sv @@ -273,7 +273,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( READY: if (~TransmitFIFOReadEmpty & ~Transmitting) NextState = START; else NextState = READY; START: NextState = WAIT; - WAIT: if (TransmitFIFOReadEmpty & ~Transmitting & ~TransmitRegLoaded) NextState = READY; + WAIT: if (/*TransmitFIFOReadEmpty &*/ ~Transmitting & ~TransmitRegLoaded) NextState = READY; else NextState = WAIT; default: NextState = READY; endcase From c197d4a3c661b702f7be99ce0188836040fc134b Mon Sep 17 00:00:00 2001 From: Jacob Pease Date: Fri, 1 Nov 2024 17:35:55 -0500 Subject: [PATCH 11/15] Cleaned up some code. Still more work to do there. --- src/uncore/spi_apb.sv | 2 +- src/uncore/spi_controller.sv | 40 +++++++++++++++++++++--------------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/src/uncore/spi_apb.sv b/src/uncore/spi_apb.sv index a15068f10..e6bd34b6a 100644 --- a/src/uncore/spi_apb.sv +++ b/src/uncore/spi_apb.sv @@ -273,7 +273,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( READY: if (~TransmitFIFOReadEmpty & ~Transmitting) NextState = START; else NextState = READY; START: NextState = WAIT; - WAIT: if (/*TransmitFIFOReadEmpty &*/ ~Transmitting & ~TransmitRegLoaded) NextState = READY; + WAIT: if (~Transmitting & ~TransmitRegLoaded) NextState = READY; else NextState = WAIT; default: NextState = READY; endcase diff --git a/src/uncore/spi_controller.sv b/src/uncore/spi_controller.sv index 576884374..9e7bd6aeb 100644 --- a/src/uncore/spi_controller.sv +++ b/src/uncore/spi_controller.sv @@ -80,6 +80,9 @@ module spi_controller ( logic PreSampleEdge; // logic ShiftEdge; // logic SampleEdge; + logic ShiftEdgePulse; + logic SampleEdgePulse; + logic EndOfFramePulse; // Frame stuff logic [3:0] BitNum; @@ -220,6 +223,7 @@ module spi_controller ( // 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 @@ -236,35 +240,39 @@ module spi_controller ( // 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; - end else begin - case(SckMode) + end else begin + PhaseOneOffset <= (PhaseOneOffset == 0) ? Transmitting & SCLKenable : ~EndOfFrameDelay; + case(SckMode) 2'b00: begin - ShiftEdge <= SPICLK & SCLKenable & ~LastBit & Transmitting; - SampleEdge <= ~SPICLK & SCLKenable & Transmitting & ~DelayIsNext; - EndOfFrameDelay <= SPICLK & SCLKenable & LastBit & Transmitting; + ShiftEdge <= SPICLK & ShiftEdgePulse; + SampleEdge <= ~SPICLK & SampleEdgePulse; + EndOfFrameDelay <= SPICLK & EndOfFramePulse; end 2'b01: begin - ShiftEdge <= ~SPICLK & SCLKenable & ~LastBit & Transmitting & PhaseOneOffset; - SampleEdge <= SPICLK & SCLKenable & Transmitting & ~DelayIsNext; - EndOfFrameDelay <= ~SPICLK & SCLKenable & LastBit & Transmitting; - PhaseOneOffset <= (PhaseOneOffset == 0) ? Transmitting & SCLKenable : ~EndOfFrameDelay; + ShiftEdge <= ~SPICLK & ShiftEdgePulse & PhaseOneOffset; + SampleEdge <= SPICLK & SampleEdgePulse; + EndOfFrameDelay <= ~SPICLK & EndOfFramePulse; end 2'b10: begin - ShiftEdge <= ~SPICLK & SCLKenable & ~LastBit & Transmitting; - SampleEdge <= SPICLK & SCLKenable & Transmitting & ~DelayIsNext; - EndOfFrameDelay <= ~SPICLK & SCLKenable & LastBit & Transmitting; + ShiftEdge <= ~SPICLK & ShiftEdgePulse; + SampleEdge <= SPICLK & SampleEdgePulse; + EndOfFrameDelay <= ~SPICLK & EndOfFramePulse; end 2'b11: begin - ShiftEdge <= SPICLK & SCLKenable & ~LastBit & Transmitting & PhaseOneOffset; - SampleEdge <= ~SPICLK & SCLKenable & Transmitting & ~DelayIsNext; - EndOfFrameDelay <= SPICLK & SCLKenable & LastBit & Transmitting; - PhaseOneOffset <= (PhaseOneOffset == 0) ? Transmitting & SCLKenable : ~EndOfFrameDelay; + ShiftEdge <= SPICLK & ShiftEdgePulse & PhaseOneOffset; + SampleEdge <= ~SPICLK & SampleEdgePulse; + EndOfFrameDelay <= SPICLK & EndOfFramePulse; end // ShiftEdge <= ((SckMode[1] ^ SckMode[0] ^ SPICLK) & SCLKenable & ~LastBit & Transmitting) & PhaseOneOffset; // PhaseOneOffset <= PhaseOneOffset == 0 ? Transmitting & SCLKenable : ~EndOfFrameDelay; From 2a8e213f209d7bd280f9622c1fa53c4489e9cec1 Mon Sep 17 00:00:00 2001 From: Jacob Pease Date: Sat, 2 Nov 2024 12:33:27 -0500 Subject: [PATCH 12/15] Wrote a script that can take hexadecimal bytes from a file and write them to an output file and an sd card. --- linux/sdcard/write-bytes.sh | 43 +++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100755 linux/sdcard/write-bytes.sh diff --git a/linux/sdcard/write-bytes.sh b/linux/sdcard/write-bytes.sh new file mode 100755 index 000000000..ba847e876 --- /dev/null +++ b/linux/sdcard/write-bytes.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +# This file writes a bunch of bytes to the flash card based on a text +# file input with bytes written in hexadecimal. + +INPUTFILE="" +OUTPUTFILE="" + +ARGS=() +while [ $OPTIND -le "$#" ] ; do + if getopts "hi:o:" arg ; then + case "${arg}" in + h) help + ;; + i) INPUTFILE=${OPTARG} + ;; + o) OUTPUTFILE=${OPTARG} + ;; + esac + else + ARGS+=("${!OPTIND}") + ((OPTIND++)) + fi +done + +SDCARD=${ARGS[0]} + +if [ ! -e $INPUTFILE ] ; then + echo -e "Error: Input file $INPUTFILE does not exist." + exit 1 +fi + +if [ -e $OUTPUTFILE ] ; then + echo -e "Error: Output file $OUTPUTFILE already exists." + exit 1 +fi + +for word in $(cat "$INPUTFILE") +do + echo -en "\x$word" >> $OUTPUTFILE +done + +dd if=$OUTPUTFILE of="$SDCARD" From e33c2f7a8ca03e48d93177dd561dc6563f0be414 Mon Sep 17 00:00:00 2001 From: Jacob Pease Date: Sat, 2 Nov 2024 12:36:45 -0500 Subject: [PATCH 13/15] Added usage and help functions to write-bytes.sh --- linux/sdcard/write-bytes.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/linux/sdcard/write-bytes.sh b/linux/sdcard/write-bytes.sh index ba847e876..83a8481e5 100755 --- a/linux/sdcard/write-bytes.sh +++ b/linux/sdcard/write-bytes.sh @@ -3,6 +3,15 @@ # This file writes a bunch of bytes to the flash card based on a text # file input with bytes written in hexadecimal. +usage() { echo "Usage: $0 [-zh] [-b ] " 1>&2; exit 1; } + +help() { + echo "Usage: $0 [OPTIONS] " + echo " -i Input text file with hex bytes." + echo " -b Output binary file." + exit 0; +} + INPUTFILE="" OUTPUTFILE="" From 9c3937165743200a9bc560ca455fa0adf2dfb0cb Mon Sep 17 00:00:00 2001 From: Jacob Pease Date: Sat, 2 Nov 2024 14:14:31 -0500 Subject: [PATCH 14/15] Reverted bootloader optimizations to second iteration. Working on last optimization. --- fpga/zsbl/boot.c | 74 ++++++++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/fpga/zsbl/boot.c b/fpga/zsbl/boot.c index d9a824a49..7665b2df2 100644 --- a/fpga/zsbl/boot.c +++ b/fpga/zsbl/boot.c @@ -135,45 +135,45 @@ int disk_read(BYTE * buf, LBA_t sector, UINT count) { /* crc = crc16(crc, x); */ /* } while (--n > 0); */ - /* n = 512/8; */ - /* do { */ - /* // Send 8 dummy bytes (fifo should be empty) */ - /* for (j = 0; j < 8; j++) { */ - /* spi_sendbyte(0xff); */ - /* } */ - - /* // Reset counter. Process bytes AS THEY COME IN. */ - /* for (j = 0; j < 8; j++) { */ - /* while (!(read_reg(SPI_IP) & 2)) {} */ - /* uint8_t x = spi_readbyte(); */ - /* *p++ = x; */ - /* // crc = crc16(crc, x); */ - /* crc = ((crc << 8) ^ crctable[x ^ (crc >> 8)]) & 0xffff; */ - /* } */ - /* } while(--n > 0); */ - - n = 512; - // Initially fill the transmit fifo - for (j = 0; j < 8; j++) { - spi_sendbyte(0xff); - } - - - while (n > 0) { - // Wait for bytes to be received - while (!(read_reg(SPI_IP) & 2)) {} - // Read byte - uint8_t x = spi_readbyte(); - // Send another dummy byte - if (n > 8) { + n = 512/8; + do { + // Send 8 dummy bytes (fifo should be empty) + for (j = 0; j < 8; j++) { spi_sendbyte(0xff); } - // Place received byte into memory - *p++ = x; - // Update CRC16 with fast table based method - crc = ((crc << 8) ^ crctable[x ^ (crc >> 8)]) & 0xffff; - n = n - 1; - } + + // Reset counter. Process bytes AS THEY COME IN. + for (j = 0; j < 8; j++) { + while (!(read_reg(SPI_IP) & 2)) {} + uint8_t x = spi_readbyte(); + *p++ = x; + // crc = crc16(crc, x); + crc = ((crc << 8) ^ crctable[x ^ (crc >> 8)]) & 0xffff; + } + } while(--n > 0); + + /* n = 512; */ + /* // Initially fill the transmit fifo */ + /* for (j = 0; j < 8; j++) { */ + /* spi_sendbyte(0xff); */ + /* } */ + + + /* while (n > 0) { */ + /* // Wait for bytes to be received */ + /* while (!(read_reg(SPI_IP) & 2)) {} */ + /* // Read byte */ + /* uint8_t x = spi_readbyte(); */ + /* // Send another dummy byte */ + /* if (n > 8) { */ + /* spi_sendbyte(0xff); */ + /* } */ + /* // Place received byte into memory */ + /* *p++ = x; */ + /* // Update CRC16 with fast table based method */ + /* crc = ((crc << 8) ^ crctable[x ^ (crc >> 8)]) & 0xffff; */ + /* n = n - 1; */ + /* } */ // Read CRC16 and check crc_exp = ((uint16_t)spi_dummy() << 8); From 674d008f23a40445be7f6ffee9405337772c3a78 Mon Sep 17 00:00:00 2001 From: Jacob Pease Date: Sat, 2 Nov 2024 14:31:05 -0500 Subject: [PATCH 15/15] Added headers to files. --- linux/sdcard/flash-sd.sh | 26 ++++++++++++++++++++++++++ linux/sdcard/write-bytes.sh | 28 ++++++++++++++++++++++++++++ src/uncore/spi_apb.sv | 6 ++++-- src/uncore/spi_controller.sv | 5 ++--- 4 files changed, 60 insertions(+), 5 deletions(-) diff --git a/linux/sdcard/flash-sd.sh b/linux/sdcard/flash-sd.sh index 7a2c58d42..31e6ee45f 100755 --- a/linux/sdcard/flash-sd.sh +++ b/linux/sdcard/flash-sd.sh @@ -1,4 +1,30 @@ #!/bin/bash +########################################### +## flash-sd.sh +## +## Written: Jacob Pease jacobpease@protonmail.com +## Created: August 22, 2023 +## +## Purpose: A script to flash an sd card with a bootable linux image. +## +## A component of the CORE-V-WALLY configurable RISC-V project. +## https://github.com/openhwgroup/cvw +## +## Copyright (C) 2021-24 Harvey Mudd College & Oklahoma State University +## +## SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +## +## Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file +## except in compliance with the License, or, at your option, the Apache License version 2.0. You +## may obtain a copy of the License at +## +## https:##solderpad.org/licenses/SHL-2.1/ +## +## Unless required by applicable law or agreed to in writing, any work distributed under the +## License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +## either express or implied. See the License for the specific language governing permissions +## and limitations under the License. +################################################################################################ # Exit on any error (return code != 0) # set -e diff --git a/linux/sdcard/write-bytes.sh b/linux/sdcard/write-bytes.sh index 83a8481e5..b9c312ceb 100755 --- a/linux/sdcard/write-bytes.sh +++ b/linux/sdcard/write-bytes.sh @@ -1,4 +1,32 @@ #!/bin/bash +########################################### +## write-bytes.sh +## +## Written: Jacob Pease jacobpease@protonmail.com +## Created: November 2nd, 2024 +## Modified: +## +## Purpose: Write a sequence of bytes from text file to an output file and a flash card. +## +## A component of the CORE-V-WALLY configurable RISC-V project. +## https://github.com/openhwgroup/cvw +## +## Copyright (C) 2021-24 Harvey Mudd College & Oklahoma State University +## +## SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +## +## Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file +## except in compliance with the License, or, at your option, the Apache License version 2.0. You +## may obtain a copy of the License at +## +## https:##solderpad.org/licenses/SHL-2.1/ +## +## Unless required by applicable law or agreed to in writing, any work distributed under the +## License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +## either express or implied. See the License for the specific language governing permissions +## and limitations under the License. +################################################################################################ + # This file writes a bunch of bytes to the flash card based on a text # file input with bytes written in hexadecimal. diff --git a/src/uncore/spi_apb.sv b/src/uncore/spi_apb.sv index e6bd34b6a..293c2c2b5 100644 --- a/src/uncore/spi_apb.sv +++ b/src/uncore/spi_apb.sv @@ -1,7 +1,9 @@ /////////////////////////////////////////// // spi_apb.sv // -// Written: Naiche Whyte-Aguayo nwhyteaguayo@g.hmc.edu 11/16/2022 +// Written: Naiche Whyte-Aguayo nwhyteaguayo@g.hmc.edu +// Jacob Pease jacobpease@protonmail.com (October 29th, 2024) +// Created: November 16th, 2022 // // Purpose: SPI peripheral // @@ -13,7 +15,7 @@ // // A component of the Wally configurable RISC-V project. // -// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University +// Copyright (C) 2021-24 Harvey Mudd College & Oklahoma State University // // SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 // diff --git a/src/uncore/spi_controller.sv b/src/uncore/spi_controller.sv index 9e7bd6aeb..19b32cab3 100644 --- a/src/uncore/spi_controller.sv +++ b/src/uncore/spi_controller.sv @@ -1,9 +1,8 @@ /////////////////////////////////////////// // spi_controller.sv // -// Written: jacobpease@protonmail.com +// Written: Jacob Pease jacobpease@protonmail.com // Created: October 28th, 2024 -// Modified: // // Purpose: Controller logic for SPI // @@ -12,7 +11,7 @@ // A component of the CORE-V-WALLY configurable RISC-V project. // https://github.com/openhwgroup/cvw // -// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University +// Copyright (C) 2021-24 Harvey Mudd College & Oklahoma State University // // SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 //