mirror of
https://github.com/openhwgroup/cvw
synced 2025-02-11 06:05:49 +00:00
commit
866ad88e97
@ -48,7 +48,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
|||||||
output logic SPICLK
|
output logic SPICLK
|
||||||
);
|
);
|
||||||
|
|
||||||
// register map
|
// register map
|
||||||
localparam SPI_SCKDIV = 8'h00;
|
localparam SPI_SCKDIV = 8'h00;
|
||||||
localparam SPI_SCKMODE = 8'h04;
|
localparam SPI_SCKMODE = 8'h04;
|
||||||
localparam SPI_CSID = 8'h10;
|
localparam SPI_CSID = 8'h10;
|
||||||
@ -85,11 +85,11 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
|||||||
// SPI Controller signals
|
// SPI Controller signals
|
||||||
logic SCLKenable;
|
logic SCLKenable;
|
||||||
logic EndOfFrame;
|
logic EndOfFrame;
|
||||||
logic EndOfFrameDelay;
|
|
||||||
logic Transmitting;
|
logic Transmitting;
|
||||||
logic InactiveState;
|
logic InactiveState;
|
||||||
logic [3:0] FrameLength;
|
logic [3:0] FrameLength;
|
||||||
|
|
||||||
|
// Starting Transmission and restarting SCLKenable
|
||||||
logic ResetSCLKenable;
|
logic ResetSCLKenable;
|
||||||
logic TransmitStart;
|
logic TransmitStart;
|
||||||
logic TransmitStartD;
|
logic TransmitStartD;
|
||||||
@ -98,16 +98,19 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
|||||||
typedef enum logic [1:0] {READY, START, WAIT} txState;
|
typedef enum logic [1:0] {READY, START, WAIT} txState;
|
||||||
txState CurrState, NextState;
|
txState CurrState, NextState;
|
||||||
|
|
||||||
// FIFO FSM signals
|
// FIFO Watermark signals - TransmitReadMark = ip[0], ReceiveWriteMark = ip[1]
|
||||||
// Watermark signals - TransmitReadMark = ip[0], ReceiveWriteMark = ip[1]
|
logic TransmitWriteMark, TransmitReadMark, ReceiveWriteMark, ReceiveReadMark;
|
||||||
logic TransmitWriteMark, TransmitReadMark, RecieveWriteMark, RecieveReadMark;
|
|
||||||
logic TransmitFIFOWriteFull, TransmitFIFOReadEmpty;
|
|
||||||
logic TransmitFIFOWriteIncrement;
|
|
||||||
logic [7:0] TransmitFIFOReadData;
|
|
||||||
|
|
||||||
|
// 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 ReceiveFIFOWriteInc;
|
||||||
logic ReceiveFIFOReadIncrement;
|
logic ReceiveFIFOReadInc;
|
||||||
logic ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty;
|
logic ReceiveFIFOFull, ReceiveFIFOEmpty;
|
||||||
|
|
||||||
/* verilator lint_off UNDRIVEN */
|
/* verilator lint_off UNDRIVEN */
|
||||||
logic [2:0] TransmitWriteWatermarkLevel, ReceiveReadWatermarkLevel; // unused generic FIFO outputs
|
logic [2:0] TransmitWriteWatermarkLevel, ReceiveReadWatermarkLevel; // unused generic FIFO outputs
|
||||||
@ -115,16 +118,16 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
|||||||
logic [7:0] ReceiveShiftRegEndian; // Reverses ReceiveShiftReg if Format[2] set (little endian transmission)
|
logic [7:0] ReceiveShiftRegEndian; // Reverses ReceiveShiftReg if Format[2] set (little endian transmission)
|
||||||
|
|
||||||
// Shift reg signals
|
// Shift reg signals
|
||||||
logic ShiftEdge; // Determines which edge of sck to shift from TransmitReg
|
logic ShiftEdge; // Determines which edge of sck to shift from TransmitReg
|
||||||
logic SampleEdge; // Determines which edge of sck to sample from ReceiveShiftReg
|
logic SampleEdge; // Determines which edge of sck to sample from ReceiveShiftReg
|
||||||
logic [7:0] TransmitReg; // Transmit shift register
|
logic [7:0] TransmitReg; // Transmit shift register
|
||||||
logic [7:0] ReceiveShiftReg; // Receive shift register
|
logic [7:0] ReceiveShiftReg; // Receive shift register
|
||||||
logic [7:0] TransmitDataEndian; // Reverses TransmitData from txFIFO if littleendian, since TransmitReg always shifts MSB
|
logic [7:0] TransmitDataEndian; // Reverses TransmitData from txFIFO if littleendian, since TransmitReg always shifts MSB
|
||||||
logic TransmitLoad; // Determines when to load TransmitReg
|
logic TransmitLoad; // Determines when to load TransmitReg
|
||||||
logic TransmitFIFOReadIncrement; // Increments Tx FIFO read ptr 1 cycle after Tx FIFO is read
|
logic TransmitRegLoaded;
|
||||||
|
|
||||||
// Shift stuff due to Format register?
|
// Shift stuff due to Format register?
|
||||||
logic ShiftIn; // Determines whether to shift from SPIIn or SPIOut (if SPI_LOOPBACK_TEST)
|
logic ShiftIn; // Determines whether to shift from SPIIn or SPIOut (if SPI_LOOPBACK_TEST)
|
||||||
logic [3:0] LeftShiftAmount; // Determines left shift amount to left-align data when little endian
|
logic [3:0] LeftShiftAmount; // Determines left shift amount to left-align data when little endian
|
||||||
logic [7:0] ASR; // AlignedReceiveShiftReg
|
logic [7:0] ASR; // AlignedReceiveShiftReg
|
||||||
|
|
||||||
@ -135,7 +138,6 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
|||||||
// APB access
|
// APB access
|
||||||
assign Entry = {PADDR[7:2],2'b00}; // 32-bit word-aligned accesses
|
assign Entry = {PADDR[7:2],2'b00}; // 32-bit word-aligned accesses
|
||||||
assign Memwrite = PWRITE & PENABLE & PSEL; // Only write in access phase
|
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;
|
assign PREADY = 1'b1;
|
||||||
|
|
||||||
// Account for subword read/write circuitry
|
// Account for subword read/write circuitry
|
||||||
@ -162,7 +164,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
|||||||
InterruptEnable <= 2'b0;
|
InterruptEnable <= 2'b0;
|
||||||
InterruptPending <= 2'b0;
|
InterruptPending <= 2'b0;
|
||||||
end else begin // writes
|
end else begin // writes
|
||||||
/* verilator lint_off CASEINCOMPLETE */
|
/* verilator lint_off CASEINCOMPLETE */
|
||||||
if (Memwrite)
|
if (Memwrite)
|
||||||
case(Entry) // flop to sample inputs
|
case(Entry) // flop to sample inputs
|
||||||
SPI_SCKDIV: SckDiv <= Din[11:0];
|
SPI_SCKDIV: SckDiv <= Din[11:0];
|
||||||
@ -180,14 +182,14 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
|||||||
|
|
||||||
if (Memwrite)
|
if (Memwrite)
|
||||||
case(Entry)
|
case(Entry)
|
||||||
SPI_TXDATA: if (~TransmitFIFOWriteFull) TransmitData[7:0] <= Din[7:0];
|
SPI_TXDATA: if (~TransmitFIFOFull) TransmitData[7:0] <= Din[7:0];
|
||||||
endcase
|
endcase
|
||||||
/* verilator lint_off CASEINCOMPLETE */
|
/* verilator lint_off CASEINCOMPLETE */
|
||||||
|
|
||||||
// According to FU540 spec: Once interrupt is pending, it will remain set until number
|
// According to FU540 spec: Once interrupt is pending, it will remain set until number
|
||||||
// of entries in tx/rx fifo is strictly more/less than tx/rxmark
|
// of entries in tx/rx fifo is strictly more/less than tx/rxmark
|
||||||
InterruptPending[0] <= TransmitReadMark;
|
InterruptPending[0] <= TransmitReadMark;
|
||||||
InterruptPending[1] <= RecieveWriteMark;
|
InterruptPending[1] <= ReceiveWriteMark;
|
||||||
|
|
||||||
case(Entry) // Flop to sample inputs
|
case(Entry) // Flop to sample inputs
|
||||||
SPI_SCKDIV: Dout <= {20'b0, SckDiv};
|
SPI_SCKDIV: Dout <= {20'b0, SckDiv};
|
||||||
@ -198,8 +200,8 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
|||||||
SPI_DELAY0: Dout <= {8'b0, Delay0[15:8], 8'b0, Delay0[7:0]};
|
SPI_DELAY0: Dout <= {8'b0, Delay0[15:8], 8'b0, Delay0[7:0]};
|
||||||
SPI_DELAY1: Dout <= {8'b0, Delay1[15:8], 8'b0, Delay1[7:0]};
|
SPI_DELAY1: Dout <= {8'b0, Delay1[15:8], 8'b0, Delay1[7:0]};
|
||||||
SPI_FMT: Dout <= {12'b0, Format[4:1], 13'b0, Format[0], 2'b0};
|
SPI_FMT: Dout <= {12'b0, Format[4:1], 13'b0, Format[0], 2'b0};
|
||||||
SPI_TXDATA: Dout <= {TransmitFIFOWriteFull, 23'b0, 8'b0};
|
SPI_TXDATA: Dout <= {TransmitFIFOFull, 23'b0, 8'b0};
|
||||||
SPI_RXDATA: Dout <= {ReceiveFIFOReadEmpty, 23'b0, ReceiveData[7:0]};
|
SPI_RXDATA: Dout <= {ReceiveFIFOEmpty, 23'b0, ReceiveData[7:0]};
|
||||||
SPI_TXMARK: Dout <= {29'b0, TransmitWatermark};
|
SPI_TXMARK: Dout <= {29'b0, TransmitWatermark};
|
||||||
SPI_RXMARK: Dout <= {29'b0, ReceiveWatermark};
|
SPI_RXMARK: Dout <= {29'b0, ReceiveWatermark};
|
||||||
SPI_IE: Dout <= {30'b0, InterruptEnable};
|
SPI_IE: Dout <= {30'b0, InterruptEnable};
|
||||||
@ -208,11 +210,6 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
|||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
|
|
||||||
// SPI enable generation, where SCLK = PCLK/(2*(SckDiv + 1))
|
|
||||||
// Asserts SCLKenable at the rising and falling edge of SCLK by counting from 0 to SckDiv
|
|
||||||
// Active at 2x SCLK frequency to account for implicit half cycle delays and actions on both clock edges depending on phase
|
|
||||||
// When SckDiv is 0, count doesn't work and SCLKenable is simply PCLK *** dh 10/26/24: this logic is seriously broken. SCLK is not scaled to PCLK/(2*(SckDiv + 1)).
|
|
||||||
|
|
||||||
// SPI Controller module -------------------------------------------
|
// SPI Controller module -------------------------------------------
|
||||||
// This module controls state and timing signals that drive the rest of this module
|
// This module controls state and timing signals that drive the rest of this module
|
||||||
assign ResetSCLKenable = Memwrite & (Entry == SPI_SCKDIV);
|
assign ResetSCLKenable = Memwrite & (Entry == SPI_SCKDIV);
|
||||||
@ -220,59 +217,51 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
|||||||
|
|
||||||
spi_controller controller(PCLK, PRESETn,
|
spi_controller controller(PCLK, PRESETn,
|
||||||
// Transmit Signals
|
// Transmit Signals
|
||||||
TransmitStart, TransmitStartD, ResetSCLKenable,
|
TransmitStart, TransmitRegLoaded, ResetSCLKenable,
|
||||||
// Register Inputs
|
// Register Inputs
|
||||||
SckDiv, SckMode, ChipSelectMode, Delay0, Delay1, FrameLength,
|
SckDiv, SckMode, ChipSelectMode, Delay0, Delay1, FrameLength,
|
||||||
// txFIFO stuff
|
// txFIFO stuff
|
||||||
TransmitFIFOReadEmpty,
|
TransmitFIFOEmpty,
|
||||||
// Timing
|
// Timing
|
||||||
SCLKenable, ShiftEdge, SampleEdge, EndOfFrame, EndOfFrameDelay,
|
SCLKenable, ShiftEdge, SampleEdge, EndOfFrame,
|
||||||
// State stuff
|
// State stuff
|
||||||
Transmitting, InactiveState,
|
Transmitting, InactiveState,
|
||||||
// Outputs
|
// Outputs
|
||||||
SPICLK);
|
SPICLK);
|
||||||
|
|
||||||
// Transmit FIFO ---------------------------------------------------
|
// Transmit FIFO ---------------------------------------------------
|
||||||
always_ff @(posedge PCLK)
|
|
||||||
if (~PRESETn) begin
|
|
||||||
TransmitFIFOWriteIncrement <= 1'b0;
|
|
||||||
end else begin
|
|
||||||
TransmitFIFOWriteIncrement <= (Memwrite & (Entry == SPI_TXDATA) & ~TransmitFIFOWriteFull);
|
|
||||||
end
|
|
||||||
|
|
||||||
always_ff @(posedge PCLK)
|
// txFIFO write increment logic
|
||||||
if (~PRESETn) begin
|
flopr #(1) txwincreg(PCLK, ~PRESETn,
|
||||||
TransmitFIFOReadIncrement <= 1'b0;
|
(Memwrite & (Entry == SPI_TXDATA) & ~TransmitFIFOFull),
|
||||||
end else if (SCLKenable) begin
|
TransmitFIFOWriteInc);
|
||||||
TransmitFIFOReadIncrement <= TransmitStartD | (EndOfFrameDelay & ~TransmitFIFOReadEmpty) ;
|
|
||||||
end
|
|
||||||
|
|
||||||
|
// txFIFO read increment logic
|
||||||
|
flopenr #(1) txrincreg(PCLK, ~PRESETn, SCLKenable,
|
||||||
|
TransmitStartD | (EndOfFrame & ~TransmitFIFOEmpty),
|
||||||
|
TransmitFIFOReadInc);
|
||||||
|
|
||||||
// Check whether TransmitReg has been loaded.
|
// Check whether TransmitReg has been loaded.
|
||||||
// We use this signal to prevent returning to the Ready state for TransmitStart
|
// We use this signal to prevent returning to the Ready state for TransmitStart
|
||||||
logic TransmitRegLoaded;
|
|
||||||
always_ff @(posedge PCLK) begin
|
always_ff @(posedge PCLK) begin
|
||||||
if (~PRESETn) begin
|
if (~PRESETn) begin
|
||||||
TransmitRegLoaded <= 1'b0;
|
TransmitRegLoaded <= 1'b0;
|
||||||
end else if (TransmitLoad) begin
|
end else if (TransmitLoad) begin
|
||||||
TransmitRegLoaded <= 1'b1;
|
TransmitRegLoaded <= 1'b1;
|
||||||
end else if (ShiftEdge | EndOfFrameDelay) begin
|
end else if (ShiftEdge | EndOfFrame) begin
|
||||||
TransmitRegLoaded <= 1'b0;
|
TransmitRegLoaded <= 1'b0;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
// Setup TransmitStart state machine
|
// Setup TransmitStart state machine
|
||||||
always_ff @(posedge PCLK) begin
|
always_ff @(posedge PCLK)
|
||||||
if (~PRESETn) begin
|
if (~PRESETn) CurrState <= READY;
|
||||||
CurrState <= READY;
|
else CurrState <= NextState;
|
||||||
end else begin
|
|
||||||
CurrState <= NextState;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// State machine for starting transmissions
|
// State machine for starting transmissions
|
||||||
always_comb begin
|
always_comb begin
|
||||||
case (CurrState)
|
case (CurrState)
|
||||||
READY: if (~TransmitFIFOReadEmpty & ~Transmitting) NextState = START;
|
READY: if (~TransmitFIFOEmpty & ~Transmitting) NextState = START;
|
||||||
else NextState = READY;
|
else NextState = READY;
|
||||||
START: NextState = WAIT;
|
START: NextState = WAIT;
|
||||||
WAIT: if (~Transmitting & ~TransmitRegLoaded) NextState = READY;
|
WAIT: if (~Transmitting & ~TransmitRegLoaded) NextState = READY;
|
||||||
@ -281,49 +270,48 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
|||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
|
|
||||||
|
// Delayed TransmitStart signal for incrementing tx read point.
|
||||||
assign TransmitStart = (CurrState == START);
|
assign TransmitStart = (CurrState == START);
|
||||||
always_ff @(posedge PCLK)
|
always_ff @(posedge PCLK)
|
||||||
if (~PRESETn) TransmitStartD <= 1'b0;
|
if (~PRESETn) TransmitStartD <= 1'b0;
|
||||||
else if (TransmitStart) TransmitStartD <= 1'b1;
|
else if (TransmitStart) TransmitStartD <= 1'b1;
|
||||||
else if (SCLKenable) TransmitStartD <= 1'b0;
|
else if (SCLKenable) TransmitStartD <= 1'b0;
|
||||||
|
|
||||||
|
// Transmit FIFO
|
||||||
spi_fifo #(3,8) txFIFO(PCLK, 1'b1, SCLKenable, PRESETn,
|
spi_fifo #(3,8) txFIFO(PCLK, 1'b1, SCLKenable, PRESETn,
|
||||||
TransmitFIFOWriteIncrement, TransmitFIFOReadIncrement,
|
TransmitFIFOWriteInc, TransmitFIFOReadInc,
|
||||||
TransmitData[7:0],
|
TransmitData[7:0],
|
||||||
TransmitWriteWatermarkLevel, TransmitWatermark[2:0],
|
TransmitWriteWatermarkLevel, TransmitWatermark[2:0],
|
||||||
TransmitFIFOReadData[7:0],
|
TransmitReadData[7:0],
|
||||||
TransmitFIFOWriteFull,
|
TransmitFIFOFull,
|
||||||
TransmitFIFOReadEmpty,
|
TransmitFIFOEmpty,
|
||||||
TransmitWriteMark, TransmitReadMark);
|
TransmitWriteMark, TransmitReadMark);
|
||||||
|
|
||||||
|
|
||||||
// Receive FIFO ----------------------------------------------------
|
// Receive FIFO ----------------------------------------------------
|
||||||
always_ff @(posedge PCLK)
|
|
||||||
if (~PRESETn) begin
|
|
||||||
ReceiveFIFOReadIncrement <= 1'b0;
|
|
||||||
end else begin
|
|
||||||
ReceiveFIFOReadIncrement <= ((Entry == SPI_RXDATA) & ~ReceiveFIFOReadEmpty & PSEL & ~ReceiveFIFOReadIncrement);
|
|
||||||
end
|
|
||||||
|
|
||||||
always_ff @(posedge PCLK)
|
// Receive FIFO Read Increment register
|
||||||
if (~PRESETn) begin
|
flopr #(1) rxfiforincreg(PCLK, ~PRESETn,
|
||||||
ReceiveFIFOWriteInc <= 1'b0;
|
((Entry == SPI_RXDATA) & ~ReceiveFIFOEmpty & PSEL & ~ReceiveFIFOReadInc),
|
||||||
end else if (SCLKenable) begin
|
ReceiveFIFOReadInc);
|
||||||
ReceiveFIFOWriteInc <= EndOfFrameDelay;
|
|
||||||
end
|
|
||||||
|
|
||||||
|
// 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,
|
spi_fifo #(3,8) rxFIFO(PCLK, SCLKenable, 1'b1, PRESETn,
|
||||||
ReceiveFIFOWriteInc, ReceiveFIFOReadIncrement,
|
ReceiveFIFOWriteInc, ReceiveFIFOReadInc,
|
||||||
ReceiveShiftRegEndian, ReceiveWatermark[2:0],
|
ReceiveShiftRegEndian, ReceiveWatermark[2:0],
|
||||||
ReceiveReadWatermarkLevel,
|
ReceiveReadWatermarkLevel,
|
||||||
ReceiveData[7:0],
|
ReceiveData[7:0],
|
||||||
ReceiveFIFOWriteFull,
|
ReceiveFIFOFull,
|
||||||
ReceiveFIFOReadEmpty,
|
ReceiveFIFOEmpty,
|
||||||
RecieveWriteMark, RecieveReadMark);
|
ReceiveWriteMark, ReceiveReadMark);
|
||||||
|
|
||||||
|
// Shift Registers --------------------------------------------------
|
||||||
// Transmit shift register
|
// Transmit shift register
|
||||||
assign TransmitLoad = TransmitStart | (EndOfFrameDelay & ~TransmitFIFOReadEmpty);
|
assign TransmitLoad = TransmitStart | (EndOfFrame & ~TransmitFIFOEmpty);
|
||||||
assign TransmitDataEndian = Format[0] ? {<<{TransmitFIFOReadData[7:0]}} : TransmitFIFOReadData[7:0];
|
assign TransmitDataEndian = Format[0] ? {<<{TransmitReadData[7:0]}} : TransmitReadData[7:0];
|
||||||
always_ff @(posedge PCLK)
|
always_ff @(posedge PCLK)
|
||||||
if(~PRESETn) TransmitReg <= 8'b0;
|
if(~PRESETn) TransmitReg <= 8'b0;
|
||||||
else if (TransmitLoad) TransmitReg <= TransmitDataEndian;
|
else if (TransmitLoad) TransmitReg <= TransmitDataEndian;
|
||||||
@ -342,12 +330,11 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
|||||||
if(~PRESETn) begin
|
if(~PRESETn) begin
|
||||||
ReceiveShiftReg <= 8'b0;
|
ReceiveShiftReg <= 8'b0;
|
||||||
end else if (SampleEdge) begin
|
end else if (SampleEdge) begin
|
||||||
if (~Transmitting) ReceiveShiftReg <= 8'b0;
|
ReceiveShiftReg <= {ReceiveShiftReg[6:0], ShiftIn};
|
||||||
else ReceiveShiftReg <= {ReceiveShiftReg[6:0], ShiftIn};
|
|
||||||
end
|
end
|
||||||
|
|
||||||
// Aligns received data and reverses if little-endian
|
// 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 ASR = ReceiveShiftReg << LeftShiftAmount[2:0];
|
||||||
assign ReceiveShiftRegEndian = Format[0] ? {<<{ASR[7:0]}} : ASR[7:0];
|
assign ReceiveShiftRegEndian = Format[0] ? {<<{ASR[7:0]}} : ASR[7:0];
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ module spi_controller (
|
|||||||
|
|
||||||
// Start Transmission
|
// Start Transmission
|
||||||
input logic TransmitStart,
|
input logic TransmitStart,
|
||||||
input logic TransmitStartD,
|
input logic TransmitRegLoaded,
|
||||||
input logic ResetSCLKenable,
|
input logic ResetSCLKenable,
|
||||||
|
|
||||||
// Registers
|
// Registers
|
||||||
@ -45,14 +45,13 @@ module spi_controller (
|
|||||||
input logic [3:0] FrameLength,
|
input logic [3:0] FrameLength,
|
||||||
|
|
||||||
// Is the Transmit FIFO Empty?
|
// Is the Transmit FIFO Empty?
|
||||||
input logic txFIFOReadEmpty,
|
input logic TransmitFIFOEmpty,
|
||||||
|
|
||||||
// Control signals
|
// Control signals
|
||||||
output logic SCLKenable,
|
output logic SCLKenable,
|
||||||
output logic ShiftEdge,
|
output logic ShiftEdge,
|
||||||
output logic SampleEdge,
|
output logic SampleEdge,
|
||||||
output logic EndOfFrame,
|
output logic EndOfFrame,
|
||||||
output logic EndOfFrameDelay,
|
|
||||||
output logic Transmitting,
|
output logic Transmitting,
|
||||||
output logic InactiveState,
|
output logic InactiveState,
|
||||||
output logic SPICLK
|
output logic SPICLK
|
||||||
@ -63,43 +62,31 @@ module spi_controller (
|
|||||||
localparam AUTOMODE = 2'b00;
|
localparam AUTOMODE = 2'b00;
|
||||||
localparam OFFMODE = 2'b11;
|
localparam OFFMODE = 2'b11;
|
||||||
|
|
||||||
|
// FSM States
|
||||||
typedef enum logic [2:0] {INACTIVE, CSSCK, TRANSMIT, SCKCS, HOLD, INTERCS, INTERXFR} statetype;
|
typedef enum logic [2:0] {INACTIVE, CSSCK, TRANSMIT, SCKCS, HOLD, INTERCS, INTERXFR} statetype;
|
||||||
statetype CurrState, NextState;
|
statetype CurrState, NextState;
|
||||||
|
|
||||||
// SCLKenable stuff
|
// SCLKenable stuff
|
||||||
logic [11:0] DivCounter;
|
logic [11:0] DivCounter;
|
||||||
// logic SCLKenable;
|
logic SCK;
|
||||||
// logic SCLKenableEarly;
|
|
||||||
logic ZeroDiv;
|
|
||||||
logic SCK; // SUPER IMPORTANT, THIS CAN'T BE THE SAME AS SPICLK!
|
|
||||||
|
|
||||||
|
|
||||||
// Shift and Sample Edges
|
// Shift and Sample Edges
|
||||||
logic PreShiftEdge;
|
logic EdgePulse;
|
||||||
logic PreSampleEdge;
|
|
||||||
// logic ShiftEdge;
|
|
||||||
// logic SampleEdge;
|
|
||||||
logic ShiftEdgePulse;
|
logic ShiftEdgePulse;
|
||||||
logic SampleEdgePulse;
|
logic SampleEdgePulse;
|
||||||
logic EndOfFramePulse;
|
logic EndOfFramePulse;
|
||||||
|
logic PhaseOneOffset;
|
||||||
|
|
||||||
// Frame stuff
|
// Frame stuff
|
||||||
logic [3:0] BitNum;
|
logic [3:0] BitNum;
|
||||||
logic LastBit;
|
logic LastBit;
|
||||||
//logic EndOfFrame;
|
|
||||||
//logic EndOfFrameDelay;
|
|
||||||
logic PhaseOneOffset;
|
|
||||||
|
|
||||||
// Transmit Stuff
|
// Transmit Stuff
|
||||||
logic ContinueTransmit;
|
logic ContinueTransmit;
|
||||||
|
|
||||||
// SPIOUT Stuff
|
|
||||||
// logic TransmitLoad;
|
|
||||||
logic [7:0] TransmitReg;
|
|
||||||
//logic Transmitting;
|
|
||||||
logic EndTransmission;
|
logic EndTransmission;
|
||||||
|
// logic TransmitRegLoaded; // TODO: Could be replaced by TransmitRegLoaded?
|
||||||
logic HoldMode;
|
logic NextEndDelay;
|
||||||
|
logic CurrentEndDelay;
|
||||||
|
|
||||||
// Delay Stuff
|
// Delay Stuff
|
||||||
logic [7:0] cssck;
|
logic [7:0] cssck;
|
||||||
@ -116,13 +103,12 @@ module spi_controller (
|
|||||||
logic EndOfSCKCS;
|
logic EndOfSCKCS;
|
||||||
logic EndOfINTERCS;
|
logic EndOfINTERCS;
|
||||||
logic EndOfINTERXFR;
|
logic EndOfINTERXFR;
|
||||||
|
logic EndOfDelay;
|
||||||
|
|
||||||
logic [7:0] CSSCKCounter;
|
logic [7:0] DelayCounter;
|
||||||
logic [7:0] SCKCSCounter;
|
|
||||||
logic [7:0] INTERCSCounter;
|
|
||||||
logic [7:0] INTERXFRCounter;
|
|
||||||
|
|
||||||
logic DelayIsNext;
|
logic DelayIsNext;
|
||||||
|
logic DelayState;
|
||||||
|
|
||||||
// Convenient Delay Reg Names
|
// Convenient Delay Reg Names
|
||||||
assign cssck = Delay0[7:0];
|
assign cssck = Delay0[7:0];
|
||||||
@ -137,23 +123,25 @@ module spi_controller (
|
|||||||
assign HasINTERXFR = interxfr > 8'b0;
|
assign HasINTERXFR = interxfr > 8'b0;
|
||||||
|
|
||||||
// Have we hit full delay for any of the delays?
|
// Have we hit full delay for any of the delays?
|
||||||
assign EndOfCSSCK = CSSCKCounter == cssck;
|
assign EndOfCSSCK = (DelayCounter == cssck) & (CurrState == CSSCK);
|
||||||
assign EndOfSCKCS = SCKCSCounter == sckcs;
|
assign EndOfSCKCS = (DelayCounter == sckcs) & (CurrState == SCKCS);
|
||||||
assign EndOfINTERCS = INTERCSCounter == intercs;
|
assign EndOfINTERCS = (DelayCounter == intercs) & (CurrState == INTERCS);
|
||||||
assign EndOfINTERXFR = INTERXFRCounter == interxfr;
|
assign EndOfINTERXFR = (DelayCounter == interxfr) & (CurrState == INTERXFR);
|
||||||
|
|
||||||
|
assign EndOfDelay = EndOfCSSCK | EndOfSCKCS | EndOfINTERCS | EndOfINTERXFR;
|
||||||
|
|
||||||
// Clock Signal Stuff -----------------------------------------------
|
// Clock Signal Stuff -----------------------------------------------
|
||||||
// I'm going to handle all clock stuff here, including ShiftEdge and
|
// I'm going to handle all clock stuff here, including ShiftEdge and
|
||||||
// SampleEdge. This makes sure that SPICLK is an output of a register
|
// SampleEdge. This makes sure that SPICLK is an output of a register
|
||||||
// and it properly synchronizes signals.
|
// and it properly synchronizes signals.
|
||||||
|
|
||||||
assign SCLKenable = DivCounter == SckDiv;
|
|
||||||
// assign SCLKenableEarly = (DivCounter + 1'b1) == SckDiv;
|
|
||||||
assign LastBit = (BitNum == FrameLength - 4'b1);
|
|
||||||
|
|
||||||
//assign EndOfFrame = SCLKenable & LastBit & Transmitting;
|
// SPI enable generation, where SCLK = PCLK/(2*(SckDiv + 1))
|
||||||
assign ContinueTransmit = ~txFIFOReadEmpty & EndOfFrameDelay;
|
// Asserts SCLKenable at the rising and falling edge of SCLK by counting from 0 to SckDiv
|
||||||
assign EndTransmission = txFIFOReadEmpty & EndOfFrameDelay;
|
// Active at 2x SCLK frequency to account for implicit half cycle delays and actions on both clock edges depending on phase
|
||||||
|
assign SCLKenable = DivCounter == SckDiv;
|
||||||
|
|
||||||
|
assign ContinueTransmit = ~TransmitFIFOEmpty & EndOfFrame;
|
||||||
|
assign EndTransmission = TransmitFIFOEmpty & EndOfFrame;
|
||||||
|
|
||||||
always_ff @(posedge PCLK) begin
|
always_ff @(posedge PCLK) begin
|
||||||
if (~PRESETn) begin
|
if (~PRESETn) begin
|
||||||
@ -161,44 +149,20 @@ module spi_controller (
|
|||||||
SPICLK <= SckMode[1];
|
SPICLK <= SckMode[1];
|
||||||
SCK <= 0;
|
SCK <= 0;
|
||||||
BitNum <= 4'h0;
|
BitNum <= 4'h0;
|
||||||
PreShiftEdge <= 0;
|
DelayCounter <= 0;
|
||||||
PreSampleEdge <= 0;
|
|
||||||
EndOfFrame <= 0;
|
|
||||||
CSSCKCounter <= 0;
|
|
||||||
SCKCSCounter <= 0;
|
|
||||||
INTERCSCounter <= 0;
|
|
||||||
INTERXFRCounter <= 0;
|
|
||||||
end else begin
|
end else begin
|
||||||
// TODO: Consolidate into one delay counter since none of the
|
// SCK logic for delay times
|
||||||
// delays happen at the same time?
|
|
||||||
if (TransmitStart) begin
|
if (TransmitStart) begin
|
||||||
SCK <= 0;
|
SCK <= 0;
|
||||||
end else if (SCLKenable) begin
|
end else if (SCLKenable) begin
|
||||||
SCK <= ~SCK;
|
SCK <= ~SCK;
|
||||||
end
|
end
|
||||||
|
|
||||||
if ((CurrState == CSSCK) & SCK & SCLKenable) begin
|
// Counter for all four delay types
|
||||||
CSSCKCounter <= CSSCKCounter + 8'd1;
|
if (DelayState & SCK & SCLKenable) begin
|
||||||
end else if (SCLKenable & EndOfCSSCK) begin
|
DelayCounter <= DelayCounter + 8'd1;
|
||||||
CSSCKCounter <= 8'd0;
|
end else if (SCLKenable & EndOfDelay) begin
|
||||||
end
|
DelayCounter <= 8'd0;
|
||||||
|
|
||||||
if ((CurrState == SCKCS) & SCK & SCLKenable) begin
|
|
||||||
SCKCSCounter <= SCKCSCounter + 8'd1;
|
|
||||||
end else if (SCLKenable & EndOfSCKCS) begin
|
|
||||||
SCKCSCounter <= 8'd0;
|
|
||||||
end
|
|
||||||
|
|
||||||
if ((CurrState == INTERCS) & SCK & SCLKenable) begin
|
|
||||||
INTERCSCounter <= INTERCSCounter + 8'd1;
|
|
||||||
end else if (SCLKenable & EndOfINTERCS) begin
|
|
||||||
INTERCSCounter <= 8'd0;
|
|
||||||
end
|
|
||||||
|
|
||||||
if ((CurrState == INTERXFR) & SCK & SCLKenable) begin
|
|
||||||
INTERXFRCounter <= INTERXFRCounter + 8'd1;
|
|
||||||
end else if (SCLKenable & EndOfINTERXFR) begin
|
|
||||||
INTERXFRCounter <= 8'd0;
|
|
||||||
end
|
end
|
||||||
|
|
||||||
// SPICLK Logic
|
// SPICLK Logic
|
||||||
@ -215,95 +179,69 @@ module spi_controller (
|
|||||||
DivCounter <= DivCounter + 12'd1;
|
DivCounter <= DivCounter + 12'd1;
|
||||||
end
|
end
|
||||||
|
|
||||||
// EndOfFrame controller
|
|
||||||
// if (SckDiv > 0 ? SCLKenableEarly & LastBit & SPICLK : LastBit & ~SPICLK) begin
|
|
||||||
// EndOfFrame <= 1'b1;
|
|
||||||
// end else begin
|
|
||||||
// EndOfFrame <= 1'b0;
|
|
||||||
// end
|
|
||||||
|
|
||||||
// TODO: Rename EndOfFrameDelay to EndOfFrame and remove this logic
|
|
||||||
if (~TransmitStart) begin
|
|
||||||
EndOfFrame <= (SckMode[1] ^ SckMode[0] ^ SPICLK) & SCLKenable & LastBit & Transmitting;
|
|
||||||
end
|
|
||||||
|
|
||||||
// Increment BitNum
|
// Increment BitNum
|
||||||
if (ShiftEdge & Transmitting) begin
|
if (ShiftEdge & Transmitting) begin
|
||||||
BitNum <= BitNum + 4'd1;
|
BitNum <= BitNum + 4'd1;
|
||||||
end else if (EndOfFrameDelay) begin
|
end else if (EndOfFrame) begin
|
||||||
BitNum <= 4'b0;
|
BitNum <= 4'b0;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
// The very last bit in a frame of any length.
|
||||||
|
assign LastBit = (BitNum == FrameLength - 4'b1);
|
||||||
|
|
||||||
|
// Any SCLKenable pulse aligns with leading or trailing edge during
|
||||||
|
// Transmission. We can use this signal as the basis for ShiftEdge
|
||||||
|
// and SampleEdge.
|
||||||
|
assign EdgePulse = SCLKenable & Transmitting;
|
||||||
|
|
||||||
|
// Possible pulses for all edge types. Combined with SPICLK to get
|
||||||
|
// edges for different phase and polarity modes.
|
||||||
|
assign ShiftEdgePulse = EdgePulse & ~LastBit;
|
||||||
|
assign SampleEdgePulse = EdgePulse & ~DelayIsNext;
|
||||||
|
assign EndOfFramePulse = EdgePulse & LastBit;
|
||||||
|
|
||||||
// Delay ShiftEdge and SampleEdge by a half PCLK period
|
// Delay ShiftEdge and SampleEdge by a half PCLK period
|
||||||
// Aligned EXACTLY ON THE MIDDLE of the leading and trailing edges.
|
// Aligned EXACTLY ON THE MIDDLE of the leading and trailing edges.
|
||||||
// Sweeeeeeeeeet...
|
// Sweeeeeeeeeet...
|
||||||
|
|
||||||
assign ShiftEdgePulse = SCLKenable & ~LastBit & Transmitting;
|
|
||||||
assign SampleEdgePulse = SCLKenable & Transmitting & ~DelayIsNext;
|
|
||||||
assign EndOfFramePulse = SCLKenable & LastBit & Transmitting;
|
|
||||||
|
|
||||||
always_ff @(posedge ~PCLK) begin
|
always_ff @(posedge ~PCLK) begin
|
||||||
if (~PRESETn | TransmitStart) begin
|
if (~PRESETn | TransmitStart) begin
|
||||||
ShiftEdge <= 0;
|
ShiftEdge <= 0;
|
||||||
PhaseOneOffset <= 0;
|
PhaseOneOffset <= 0;
|
||||||
SampleEdge <= 0;
|
SampleEdge <= 0;
|
||||||
EndOfFrameDelay <= 0;
|
EndOfFrame <= 0;
|
||||||
end else begin
|
end else begin
|
||||||
PhaseOneOffset <= (PhaseOneOffset == 0) ? Transmitting & SCLKenable : ~EndOfFrameDelay;
|
PhaseOneOffset <= (PhaseOneOffset == 0) ? Transmitting & SCLKenable : ~EndOfFrame;
|
||||||
case(SckMode)
|
case(SckMode)
|
||||||
2'b00: begin
|
2'b00: begin
|
||||||
ShiftEdge <= SPICLK & ShiftEdgePulse;
|
ShiftEdge <= SPICLK & ShiftEdgePulse;
|
||||||
SampleEdge <= ~SPICLK & SampleEdgePulse;
|
SampleEdge <= ~SPICLK & SampleEdgePulse;
|
||||||
EndOfFrameDelay <= SPICLK & EndOfFramePulse;
|
EndOfFrame <= SPICLK & EndOfFramePulse;
|
||||||
end
|
end
|
||||||
2'b01: begin
|
2'b01: begin
|
||||||
ShiftEdge <= ~SPICLK & ShiftEdgePulse & PhaseOneOffset;
|
ShiftEdge <= ~SPICLK & ShiftEdgePulse & PhaseOneOffset;
|
||||||
SampleEdge <= SPICLK & SampleEdgePulse;
|
SampleEdge <= SPICLK & SampleEdgePulse;
|
||||||
EndOfFrameDelay <= ~SPICLK & EndOfFramePulse;
|
EndOfFrame <= ~SPICLK & EndOfFramePulse;
|
||||||
end
|
end
|
||||||
2'b10: begin
|
2'b10: begin
|
||||||
ShiftEdge <= ~SPICLK & ShiftEdgePulse;
|
ShiftEdge <= ~SPICLK & ShiftEdgePulse;
|
||||||
SampleEdge <= SPICLK & SampleEdgePulse;
|
SampleEdge <= SPICLK & SampleEdgePulse;
|
||||||
EndOfFrameDelay <= ~SPICLK & EndOfFramePulse;
|
EndOfFrame <= ~SPICLK & EndOfFramePulse;
|
||||||
end
|
end
|
||||||
2'b11: begin
|
2'b11: begin
|
||||||
ShiftEdge <= SPICLK & ShiftEdgePulse & PhaseOneOffset;
|
ShiftEdge <= SPICLK & ShiftEdgePulse & PhaseOneOffset;
|
||||||
SampleEdge <= ~SPICLK & SampleEdgePulse;
|
SampleEdge <= ~SPICLK & SampleEdgePulse;
|
||||||
EndOfFrameDelay <= SPICLK & EndOfFramePulse;
|
EndOfFrame <= SPICLK & EndOfFramePulse;
|
||||||
end
|
end
|
||||||
// ShiftEdge <= ((SckMode[1] ^ SckMode[0] ^ SPICLK) & SCLKenable & ~LastBit & Transmitting) & PhaseOneOffset;
|
|
||||||
// PhaseOneOffset <= PhaseOneOffset == 0 ? Transmitting & SCLKenable : ~EndOfFrameDelay;
|
|
||||||
// SampleEdge <= (SckMode[1] ^ SckMode[0] ^ ~SPICLK) & SCLKenable & Transmitting & ~DelayIsNext;
|
|
||||||
// EndOfFrameDelay <= (SckMode[1] ^ SckMode[0] ^ SPICLK) & SCLKenable & LastBit & Transmitting;
|
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
// typedef enum logic [2:0] {INACTIVE, CSSCK, TRANSMIT, SCKCS, HOLD, INTERCS, INTERXFR} statetype;
|
// Logic for continuing to transmit through Delay states after end of frame
|
||||||
// statetype CurrState, NextState;
|
|
||||||
|
|
||||||
assign HoldMode = CSMode == HOLDMODE;
|
|
||||||
// assign TransmitLoad = TransmitStart | (EndOfFrameDelay & ~txFIFOReadEmpty);
|
|
||||||
|
|
||||||
logic ContinueTransmitD;
|
|
||||||
logic NextEndDelay;
|
|
||||||
logic CurrentEndDelay;
|
|
||||||
|
|
||||||
assign NextEndDelay = NextState == SCKCS | NextState == INTERCS | NextState == INTERXFR;
|
assign NextEndDelay = NextState == SCKCS | NextState == INTERCS | NextState == INTERXFR;
|
||||||
assign CurrentEndDelay = CurrState == SCKCS | CurrState == INTERCS | CurrState == INTERXFR;
|
assign CurrentEndDelay = CurrState == SCKCS | CurrState == INTERCS | CurrState == INTERXFR;
|
||||||
|
|
||||||
always_ff @(posedge PCLK) begin
|
|
||||||
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
|
always_ff @(posedge PCLK) begin
|
||||||
if (~PRESETn) begin
|
if (~PRESETn) begin
|
||||||
CurrState <= INACTIVE;
|
CurrState <= INACTIVE;
|
||||||
@ -314,7 +252,7 @@ module spi_controller (
|
|||||||
|
|
||||||
always_comb begin
|
always_comb begin
|
||||||
case (CurrState)
|
case (CurrState)
|
||||||
INACTIVE: if (TransmitStartD) begin
|
INACTIVE: if (TransmitRegLoaded) begin
|
||||||
if (~HasCSSCK) NextState = TRANSMIT;
|
if (~HasCSSCK) NextState = TRANSMIT;
|
||||||
else NextState = CSSCK;
|
else NextState = CSSCK;
|
||||||
end else begin
|
end else begin
|
||||||
@ -326,7 +264,7 @@ module spi_controller (
|
|||||||
case(CSMode)
|
case(CSMode)
|
||||||
AUTOMODE: begin
|
AUTOMODE: begin
|
||||||
if (EndTransmission) NextState = INACTIVE;
|
if (EndTransmission) NextState = INACTIVE;
|
||||||
else if (EndOfFrameDelay) NextState = SCKCS;
|
else if (EndOfFrame) NextState = SCKCS;
|
||||||
else NextState = TRANSMIT;
|
else NextState = TRANSMIT;
|
||||||
end
|
end
|
||||||
HOLDMODE: begin
|
HOLDMODE: begin
|
||||||
@ -344,7 +282,7 @@ module spi_controller (
|
|||||||
end
|
end
|
||||||
SCKCS: begin // SCKCS case --------------------------------------
|
SCKCS: begin // SCKCS case --------------------------------------
|
||||||
if (EndOfSCKCS) begin
|
if (EndOfSCKCS) begin
|
||||||
if (~ContinueTransmitD) begin
|
if (~TransmitRegLoaded) begin
|
||||||
// if (CSMode == AUTOMODE) NextState = INACTIVE;
|
// if (CSMode == AUTOMODE) NextState = INACTIVE;
|
||||||
if (CSMode == HOLDMODE) NextState = HOLD;
|
if (CSMode == HOLDMODE) NextState = HOLD;
|
||||||
else NextState = INACTIVE;
|
else NextState = INACTIVE;
|
||||||
@ -359,7 +297,7 @@ module spi_controller (
|
|||||||
HOLD: begin // HOLD mode case -----------------------------------
|
HOLD: begin // HOLD mode case -----------------------------------
|
||||||
if (CSMode == AUTOMODE) begin
|
if (CSMode == AUTOMODE) begin
|
||||||
NextState = INACTIVE;
|
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;
|
NextState = TRANSMIT;
|
||||||
end else NextState = HOLD;
|
end else NextState = HOLD;
|
||||||
end
|
end
|
||||||
@ -386,6 +324,7 @@ module spi_controller (
|
|||||||
|
|
||||||
assign Transmitting = CurrState == TRANSMIT;
|
assign Transmitting = CurrState == TRANSMIT;
|
||||||
assign DelayIsNext = (NextState == CSSCK | NextState == SCKCS | NextState == INTERCS | NextState == INTERXFR);
|
assign DelayIsNext = (NextState == CSSCK | NextState == SCKCS | NextState == INTERCS | NextState == INTERXFR);
|
||||||
|
assign DelayState = (CurrState == CSSCK | CurrState == SCKCS | CurrState == INTERCS | CurrState == INTERXFR);
|
||||||
assign InactiveState = CurrState == INACTIVE | CurrState == INTERCS;
|
assign InactiveState = CurrState == INACTIVE | CurrState == INTERCS;
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
@ -19,6 +19,10 @@ module spi_fifo #(parameter M=3, N=8)( // 2^M entries of N bits
|
|||||||
logic [M:0] rptrnext, wptrnext;
|
logic [M:0] rptrnext, wptrnext;
|
||||||
logic [M-1:0] raddr;
|
logic [M-1:0] raddr;
|
||||||
logic [M-1:0] waddr;
|
logic [M-1:0] waddr;
|
||||||
|
|
||||||
|
logic [M-1:0] numVals;
|
||||||
|
|
||||||
|
assign numVals = waddr - raddr;
|
||||||
|
|
||||||
assign rdata = mem[raddr];
|
assign rdata = mem[raddr];
|
||||||
always_ff @(posedge PCLK)
|
always_ff @(posedge PCLK)
|
||||||
|
Loading…
Reference in New Issue
Block a user