mirror of
				https://github.com/openhwgroup/cvw
				synced 2025-02-11 06:05:49 +00:00 
			
		
		
		
	
						commit
						866ad88e97
					
				@ -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;  
 | 
			
		||||
 | 
			
		||||
  // Starting Transmission and restarting SCLKenable
 | 
			
		||||
  logic        ResetSCLKenable;
 | 
			
		||||
  logic        TransmitStart;
 | 
			
		||||
  logic        TransmitStartD;
 | 
			
		||||
@ -98,16 +98,19 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
 | 
			
		||||
  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;
 | 
			
		||||
  // FIFO Watermark signals - TransmitReadMark = ip[0], ReceiveWriteMark = ip[1]
 | 
			
		||||
  logic        TransmitWriteMark, TransmitReadMark, ReceiveWriteMark, ReceiveReadMark;
 | 
			
		||||
 | 
			
		||||
  // Transmit FIFO Signals
 | 
			
		||||
  logic        TransmitFIFOFull, TransmitFIFOEmpty;
 | 
			
		||||
  logic        TransmitFIFOWriteInc;
 | 
			
		||||
  logic        TransmitFIFOReadInc;                // Increments Tx FIFO read ptr 1 cycle after Tx FIFO is read
 | 
			
		||||
  logic [7:0]  TransmitReadData;
 | 
			
		||||
 | 
			
		||||
  // ReceiveFIFO Signals
 | 
			
		||||
  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
 | 
			
		||||
@ -121,7 +124,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
 | 
			
		||||
  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        TransmitRegLoaded;
 | 
			
		||||
 | 
			
		||||
  // Shift stuff due to Format register?
 | 
			
		||||
  logic        ShiftIn;                            // Determines whether to shift from SPIIn or SPIOut (if SPI_LOOPBACK_TEST)  
 | 
			
		||||
@ -135,7 +138,6 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
 | 
			
		||||
  // 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
 | 
			
		||||
@ -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);
 | 
			
		||||
@ -220,59 +217,51 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
 | 
			
		||||
  
 | 
			
		||||
  spi_controller controller(PCLK, PRESETn,
 | 
			
		||||
                            // Transmit Signals
 | 
			
		||||
                            TransmitStart, TransmitStartD, ResetSCLKenable,
 | 
			
		||||
                            TransmitStart, TransmitRegLoaded, ResetSCLKenable,
 | 
			
		||||
                            // 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 ---------------------------------------------------
 | 
			
		||||
  always_ff @(posedge PCLK)
 | 
			
		||||
    if (~PRESETn) begin
 | 
			
		||||
      TransmitFIFOWriteIncrement <= 1'b0;
 | 
			
		||||
    end else begin
 | 
			
		||||
      TransmitFIFOWriteIncrement <= (Memwrite & (Entry == SPI_TXDATA) & ~TransmitFIFOWriteFull);
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
  always_ff @(posedge PCLK)
 | 
			
		||||
    if (~PRESETn) begin
 | 
			
		||||
      TransmitFIFOReadIncrement <= 1'b0;
 | 
			
		||||
    end else if (SCLKenable) begin
 | 
			
		||||
      TransmitFIFOReadIncrement <= TransmitStartD | (EndOfFrameDelay & ~TransmitFIFOReadEmpty) ;
 | 
			
		||||
  end
 | 
			
		||||
  // txFIFO write increment logic
 | 
			
		||||
  flopr #(1) txwincreg(PCLK, ~PRESETn,
 | 
			
		||||
                       (Memwrite & (Entry == SPI_TXDATA) & ~TransmitFIFOFull),
 | 
			
		||||
                       TransmitFIFOWriteInc);
 | 
			
		||||
 | 
			
		||||
  // txFIFO read increment logic
 | 
			
		||||
  flopenr #(1) txrincreg(PCLK, ~PRESETn, SCLKenable,
 | 
			
		||||
                         TransmitStartD | (EndOfFrame & ~TransmitFIFOEmpty),                  
 | 
			
		||||
                         TransmitFIFOReadInc);
 | 
			
		||||
  
 | 
			
		||||
  // 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
 | 
			
		||||
  
 | 
			
		||||
  // Setup TransmitStart state machine
 | 
			
		||||
  always_ff @(posedge PCLK) begin
 | 
			
		||||
    if (~PRESETn) begin
 | 
			
		||||
      CurrState <= READY;
 | 
			
		||||
    end else begin
 | 
			
		||||
      CurrState <= NextState;
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
  always_ff @(posedge PCLK)
 | 
			
		||||
    if (~PRESETn) CurrState <= READY;
 | 
			
		||||
    else          CurrState <= NextState;
 | 
			
		||||
  
 | 
			
		||||
  // 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;
 | 
			
		||||
@ -281,49 +270,48 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
 | 
			
		||||
    endcase
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  // Delayed TransmitStart signal for incrementing tx read point.
 | 
			
		||||
  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;
 | 
			
		||||
 | 
			
		||||
  // Transmit FIFO
 | 
			
		||||
  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;
 | 
			
		||||
    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
 | 
			
		||||
  // Receive FIFO Read Increment register
 | 
			
		||||
  flopr #(1) rxfiforincreg(PCLK, ~PRESETn,
 | 
			
		||||
                           ((Entry == SPI_RXDATA) & ~ReceiveFIFOEmpty & PSEL & ~ReceiveFIFOReadInc),
 | 
			
		||||
                           ReceiveFIFOReadInc);
 | 
			
		||||
 | 
			
		||||
  // Receive FIFO Write Increment register
 | 
			
		||||
  flopenr #(1) rxfifowincreg(PCLK, ~PRESETn, SCLKenable,
 | 
			
		||||
                             EndOfFrame, ReceiveFIFOWriteInc);
 | 
			
		||||
 | 
			
		||||
  // Receive FIFO
 | 
			
		||||
  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);
 | 
			
		||||
 | 
			
		||||
  // Shift Registers --------------------------------------------------
 | 
			
		||||
  // 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;
 | 
			
		||||
@ -342,12 +330,11 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
 | 
			
		||||
    if(~PRESETn) begin
 | 
			
		||||
      ReceiveShiftReg <= 8'b0;
 | 
			
		||||
    end else if (SampleEdge) begin
 | 
			
		||||
      if (~Transmitting) ReceiveShiftReg <= 8'b0;
 | 
			
		||||
      else               ReceiveShiftReg <= {ReceiveShiftReg[6:0], ShiftIn};
 | 
			
		||||
      ReceiveShiftReg <= {ReceiveShiftReg[6:0], ShiftIn};
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
  // Aligns received data and reverses if little-endian
 | 
			
		||||
  assign LeftShiftAmount = 4'h8 - Format[4:1];
 | 
			
		||||
  assign LeftShiftAmount = 4'h8 - FrameLength;
 | 
			
		||||
  assign ASR = ReceiveShiftReg << LeftShiftAmount[2:0];
 | 
			
		||||
  assign ReceiveShiftRegEndian = Format[0] ? {<<{ASR[7:0]}} : ASR[7:0];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -33,7 +33,7 @@ module spi_controller (
 | 
			
		||||
 | 
			
		||||
  // Start Transmission
 | 
			
		||||
  input logic        TransmitStart,
 | 
			
		||||
  input logic        TransmitStartD,
 | 
			
		||||
  input logic        TransmitRegLoaded,
 | 
			
		||||
  input logic        ResetSCLKenable, 
 | 
			
		||||
 | 
			
		||||
  // Registers
 | 
			
		||||
@ -45,14 +45,13 @@ module spi_controller (
 | 
			
		||||
  input logic [3:0]  FrameLength,
 | 
			
		||||
 | 
			
		||||
  // Is the Transmit FIFO Empty?
 | 
			
		||||
  input logic        txFIFOReadEmpty,
 | 
			
		||||
  input logic        TransmitFIFOEmpty,
 | 
			
		||||
 | 
			
		||||
  // 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
 | 
			
		||||
@ -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       TransmitRegLoaded; // 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.
 | 
			
		||||
 | 
			
		||||
  // 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 SCLKenableEarly = (DivCounter + 1'b1) == SckDiv;
 | 
			
		||||
  assign LastBit = (BitNum == FrameLength - 4'b1);
 | 
			
		||||
 | 
			
		||||
  //assign EndOfFrame = SCLKenable & LastBit & Transmitting;
 | 
			
		||||
  assign ContinueTransmit = ~txFIFOReadEmpty & EndOfFrameDelay;
 | 
			
		||||
  assign EndTransmission = txFIFOReadEmpty & EndOfFrameDelay;
 | 
			
		||||
  assign ContinueTransmit = ~TransmitFIFOEmpty & EndOfFrame;
 | 
			
		||||
  assign EndTransmission = TransmitFIFOEmpty & EndOfFrame;
 | 
			
		||||
  
 | 
			
		||||
  always_ff @(posedge PCLK) begin
 | 
			
		||||
    if (~PRESETn) begin
 | 
			
		||||
@ -161,44 +149,20 @@ 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?
 | 
			
		||||
      // SCK logic for delay times  
 | 
			
		||||
      if (TransmitStart) begin
 | 
			
		||||
        SCK <= 0;
 | 
			
		||||
      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,95 +179,69 @@ 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;
 | 
			
		||||
    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;
 | 
			
		||||
@ -314,7 +252,7 @@ module spi_controller (
 | 
			
		||||
  
 | 
			
		||||
  always_comb begin
 | 
			
		||||
    case (CurrState)  
 | 
			
		||||
      INACTIVE: if (TransmitStartD) begin
 | 
			
		||||
      INACTIVE: if (TransmitRegLoaded) begin
 | 
			
		||||
                  if (~HasCSSCK) NextState = TRANSMIT;
 | 
			
		||||
                  else NextState = CSSCK;
 | 
			
		||||
                end else begin
 | 
			
		||||
@ -326,7 +264,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  
 | 
			
		||||
@ -344,7 +282,7 @@ module spi_controller (
 | 
			
		||||
      end
 | 
			
		||||
      SCKCS: begin // SCKCS case --------------------------------------
 | 
			
		||||
        if (EndOfSCKCS) begin
 | 
			
		||||
          if (~ContinueTransmitD) begin
 | 
			
		||||
          if (~TransmitRegLoaded) begin
 | 
			
		||||
            // if (CSMode == AUTOMODE) NextState = INACTIVE;
 | 
			
		||||
            if (CSMode == HOLDMODE) NextState = HOLD;
 | 
			
		||||
            else NextState = INACTIVE;
 | 
			
		||||
@ -359,7 +297,7 @@ module spi_controller (
 | 
			
		||||
      HOLD: begin // HOLD mode case -----------------------------------
 | 
			
		||||
        if (CSMode == AUTOMODE) begin
 | 
			
		||||
          NextState = INACTIVE;
 | 
			
		||||
        end else if (TransmitStartD) begin // If FIFO is written to, start again.
 | 
			
		||||
        end else if (TransmitRegLoaded) begin // If FIFO is written to, start again.
 | 
			
		||||
          NextState = TRANSMIT;
 | 
			
		||||
        end else NextState = HOLD;
 | 
			
		||||
      end
 | 
			
		||||
@ -386,6 +324,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
 | 
			
		||||
 | 
			
		||||
@ -20,6 +20,10 @@ module spi_fifo #(parameter M=3, N=8)(                 // 2^M entries of N bits
 | 
			
		||||
    logic [M-1:0] raddr;
 | 
			
		||||
    logic [M-1:0] waddr;
 | 
			
		||||
 | 
			
		||||
  logic [M-1:0] numVals;
 | 
			
		||||
  
 | 
			
		||||
  assign numVals = waddr - raddr;
 | 
			
		||||
 
 | 
			
		||||
    assign rdata = mem[raddr];
 | 
			
		||||
    always_ff @(posedge PCLK)
 | 
			
		||||
        if (winc & ~wfull) mem[waddr] <= wdata;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user