mirror of
https://github.com/openhwgroup/cvw
synced 2025-02-11 06:05:49 +00:00
Merge branch 'main' of https://github.com/openhwgroup/cvw into dev
This commit is contained in:
commit
3308550409
@ -2,10 +2,14 @@
|
|||||||
// spi_apb.sv
|
// spi_apb.sv
|
||||||
//
|
//
|
||||||
// Written: Naiche Whyte-Aguayo nwhyteaguayo@g.hmc.edu 11/16/2022
|
// Written: Naiche Whyte-Aguayo nwhyteaguayo@g.hmc.edu 11/16/2022
|
||||||
|
|
||||||
//
|
//
|
||||||
// Purpose: SPI peripheral
|
// Purpose: SPI peripheral
|
||||||
// See FU540-C000-v1.0 for specifications
|
//
|
||||||
|
// SPI module is written to the specifications described in FU540-C000-v1.0. At the top level, it is consists of synchronous 8 byte transmit and recieve FIFOs connected to shift registers.
|
||||||
|
// The FIFOs are connected to WALLY by an apb control register interface, which includes various control registers for modifying the SPI transmission along with registers for writing
|
||||||
|
// to the transmit FIFO and reading from the receive FIFO. The transmissions themselves are then controlled by a finite state machine. The SPI module uses 4 tristate pins for SPI input/output,
|
||||||
|
// along with a 4 bit Chip Select signal, a clock signal, and an interrupt signal to WALLY.
|
||||||
|
// Current limitations: Flash read sequencer mode not implemented, dual and quad mode not supported
|
||||||
//
|
//
|
||||||
// A component of the Wally configurable RISC-V project.
|
// A component of the Wally configurable RISC-V project.
|
||||||
//
|
//
|
||||||
@ -25,19 +29,6 @@
|
|||||||
// and limitations under the License.
|
// and limitations under the License.
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Current limitations: Flash read sequencer mode not implemented, dual and quad modes untestable with current test plan.
|
|
||||||
|
|
||||||
// Attempt to move from >= comparisons by initializing in FSM differently
|
|
||||||
// Parameterize SynchFIFO
|
|
||||||
// look at ReadIncrement/WriteIncrement delay necessity
|
|
||||||
|
|
||||||
/*
|
|
||||||
SPI module is written to the specifications described in FU540-C000-v1.0. At the top level, it is consists of synchronous 8 byte transmit and recieve FIFOs connected to shift registers.
|
|
||||||
The FIFOs are connected to WALLY by an apb control register interface, which includes various control registers for modifying the SPI transmission along with registers for writing
|
|
||||||
to the transmit FIFO and reading from the receive FIFO. The transmissions themselves are then controlled by a finite state machine. The SPI module uses 4 tristate pins for SPI input/output,
|
|
||||||
along with a 4 bit Chip Select signal, a clock signal, and an interrupt signal to WALLY.
|
|
||||||
*/
|
|
||||||
|
|
||||||
module spi_apb import cvw::*; #(parameter cvw_t P) (
|
module spi_apb import cvw::*; #(parameter cvw_t P) (
|
||||||
input logic PCLK, PRESETn,
|
input logic PCLK, PRESETn,
|
||||||
input logic PSEL,
|
input logic PSEL,
|
||||||
@ -83,12 +74,12 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
|||||||
logic ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty;
|
logic ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty;
|
||||||
logic [7:0] TransmitFIFOReadData, ReceiveFIFOWriteData;
|
logic [7:0] TransmitFIFOReadData, ReceiveFIFOWriteData;
|
||||||
logic [2:0] TransmitWriteWatermarkLevel, ReceiveReadWatermarkLevel;
|
logic [2:0] TransmitWriteWatermarkLevel, ReceiveReadWatermarkLevel;
|
||||||
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)
|
||||||
|
|
||||||
// Transmission signals
|
// Transmission signals
|
||||||
logic sck;
|
logic sck;
|
||||||
logic [11:0] DivCounter; //counter for sck
|
logic [11:0] DivCounter; // Counter for sck
|
||||||
logic SCLKenable; //flip flop enable high every sclk edge
|
logic SCLKenable; // Flip flop enable high every sclk edge
|
||||||
|
|
||||||
// Delay signals
|
// Delay signals
|
||||||
logic [8:0] ImplicitDelay1; // Adds implicit delay to cs-sck delay counter based on phase
|
logic [8:0] ImplicitDelay1; // Adds implicit delay to cs-sck delay counter based on phase
|
||||||
@ -97,18 +88,12 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
|||||||
logic [8:0] SCK_CSCount; // Counter for sck-cs delay
|
logic [8:0] SCK_CSCount; // Counter for sck-cs delay
|
||||||
logic [8:0] InterCSCount; // Counter for inter cs delay
|
logic [8:0] InterCSCount; // Counter for inter cs delay
|
||||||
logic [8:0] InterXFRCount; // Counter for inter xfr delay
|
logic [8:0] InterXFRCount; // Counter for inter xfr delay
|
||||||
logic CS_SCKCompare; //Boolean comparison signal, high when CS_SCKCount >= cs-sck delay
|
|
||||||
logic SCK_CSCompare; //Boolean comparison signal, high when SCK_CSCount >= sck-cs delay
|
|
||||||
logic InterCSCompare; //Boolean comparison signal, high when InterCSCount >= inter cs delay
|
|
||||||
logic InterXFRCompare; //Boolean comparison signal, high when InterXFRCount >= inter xfr delay
|
|
||||||
logic ZeroDelayHoldMode; // High when ChipSelectMode is hold and Delay1[15:8] (InterXFR delay) is 0
|
logic ZeroDelayHoldMode; // High when ChipSelectMode is hold and Delay1[15:8] (InterXFR delay) is 0
|
||||||
|
|
||||||
// Frame counting signals
|
// Frame counting signals
|
||||||
logic [3:0] FrameCount; // Counter for number of frames in transmission
|
logic [3:0] FrameCount; // Counter for number of frames in transmission
|
||||||
logic FrameCompare; //Boolean comparison signal, high when FrameCount = Format[7:4]
|
|
||||||
logic [3:0] ReceivePenultimateFrame; //Frame number - 1
|
|
||||||
logic [3:0] ReceivePenultimateFrameCount; // Counter
|
logic [3:0] ReceivePenultimateFrameCount; // Counter
|
||||||
logic ReceivePenultimateFrameBoolean; //High when penultimate frame in transmission has been reached
|
logic ReceivePenultimateFrame; // High when penultimate frame in transmission has been reached
|
||||||
|
|
||||||
// State fsm signals
|
// State fsm signals
|
||||||
logic Active; // High when state is either Active1 or Active0 (during transmission)
|
logic Active; // High when state is either Active1 or Active0 (during transmission)
|
||||||
@ -134,15 +119,14 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
|||||||
|
|
||||||
// Miscellaneous signals delayed/early by 1 PCLK cycle
|
// Miscellaneous signals delayed/early by 1 PCLK cycle
|
||||||
logic ReceiveShiftFullDelay; // Delays ReceiveShiftFull signal by 1 PCLK cycle
|
logic ReceiveShiftFullDelay; // Delays ReceiveShiftFull signal by 1 PCLK cycle
|
||||||
logic TransmitFIFOWriteIncrementDelay; //TransmitFIFOWriteIncrement delayed by 1 PCLK cycle
|
|
||||||
logic ReceiveShiftFullDelayPCLK; // ReceiveShiftFull delayed by 1 PCLK cycle
|
logic ReceiveShiftFullDelayPCLK; // ReceiveShiftFull delayed by 1 PCLK cycle
|
||||||
logic TransmitFIFOReadEmptyDelay;
|
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
|
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
|
// 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 = TransmitInactive; // tie PREADY to transmission for hardware interlock
|
assign PREADY = TransmitInactive; // Tie PREADY to transmission for hardware interlock
|
||||||
|
|
||||||
// Account for subword read/write circuitry
|
// Account for subword read/write circuitry
|
||||||
// -- Note SPI registers are 32 bits no matter what; access them with LW SW.
|
// -- Note SPI registers are 32 bits no matter what; access them with LW SW.
|
||||||
@ -168,8 +152,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
|||||||
InterruptEnable <= #1 2'b0;
|
InterruptEnable <= #1 2'b0;
|
||||||
InterruptPending <= #1 2'b0;
|
InterruptPending <= #1 2'b0;
|
||||||
end else begin // writes
|
end else begin // writes
|
||||||
//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
|
|
||||||
|
|
||||||
/* verilator lint_off CASEINCOMPLETE */
|
/* verilator lint_off CASEINCOMPLETE */
|
||||||
if (Memwrite & TransmitInactive)
|
if (Memwrite & TransmitInactive)
|
||||||
@ -188,18 +171,21 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
|||||||
8'h70: InterruptEnable <= Din[1:0];
|
8'h70: InterruptEnable <= Din[1:0];
|
||||||
endcase
|
endcase
|
||||||
/* verilator lint_off CASEINCOMPLETE */
|
/* verilator lint_off CASEINCOMPLETE */
|
||||||
//interrupt clearance
|
|
||||||
|
// 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[0] <= TransmitReadMark;
|
||||||
InterruptPending[1] <= RecieveWriteMark;
|
InterruptPending[1] <= RecieveWriteMark;
|
||||||
case(Entry) // flop to sample inputs
|
|
||||||
|
case(Entry) // Flop to sample inputs
|
||||||
8'h00: Dout <= #1 {20'b0, SckDiv};
|
8'h00: Dout <= #1 {20'b0, SckDiv};
|
||||||
8'h04: Dout <= #1 {30'b0, SckMode};
|
8'h04: Dout <= #1 {30'b0, SckMode};
|
||||||
8'h10: Dout <= #1 {30'b0, ChipSelectID};
|
8'h10: Dout <= #1 {30'b0, ChipSelectID};
|
||||||
8'h14: Dout <= #1 {28'b0, ChipSelectDef};
|
8'h14: Dout <= #1 {28'b0, ChipSelectDef};
|
||||||
8'h18: Dout <= #1 {30'b0, ChipSelectMode};
|
8'h18: Dout <= #1 {30'b0, ChipSelectMode};
|
||||||
8'h28: Dout <= {8'b0, Delay0[15:8], 8'b0, Delay0[7:0]};
|
8'h28: Dout <= #1 {8'b0, Delay0[15:8], 8'b0, Delay0[7:0]};
|
||||||
8'h2C: Dout <= {8'b0, Delay1[15:8], 8'b0, Delay1[7:0]};
|
8'h2C: Dout <= #1 {8'b0, Delay1[15:8], 8'b0, Delay1[7:0]};
|
||||||
8'h40: Dout <= {12'b0, Format[4:1], 13'b0, Format[0], 2'b0};
|
8'h40: Dout <= #1 {12'b0, Format[4:1], 13'b0, Format[0], 2'b0};
|
||||||
8'h48: Dout <= #1 {23'b0, TransmitFIFOWriteFull, 8'b0};
|
8'h48: Dout <= #1 {23'b0, TransmitFIFOWriteFull, 8'b0};
|
||||||
8'h4C: Dout <= #1 {23'b0, ReceiveFIFOReadEmpty, ReceiveData[7:0]};
|
8'h4C: Dout <= #1 {23'b0, ReceiveFIFOReadEmpty, ReceiveData[7:0]};
|
||||||
8'h50: Dout <= #1 {29'b0, TransmitWatermark};
|
8'h50: Dout <= #1 {29'b0, TransmitWatermark};
|
||||||
@ -211,7 +197,8 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
|||||||
end
|
end
|
||||||
|
|
||||||
// SPI enable generation, where SCLK = PCLK/(2*(SckDiv + 1))
|
// SPI enable generation, where SCLK = PCLK/(2*(SckDiv + 1))
|
||||||
//Generates a high signal at the rising and falling edge of SCLK by counting from 0 to SckDiv
|
// Asserts SCLKenable at the rising and falling edge of SCLK by counting from 0 to SckDiv
|
||||||
|
// Active at 2x SCLK frequency to account for implicit half cycle delays and actions on both clock edges depending on phase
|
||||||
assign SCLKenable = (DivCounter == SckDiv);
|
assign SCLKenable = (DivCounter == SckDiv);
|
||||||
assign SCLKenableEarly = ((DivCounter + 12'b1) == SckDiv);
|
assign SCLKenableEarly = ((DivCounter + 12'b1) == SckDiv);
|
||||||
always_ff @(posedge PCLK, negedge PRESETn)
|
always_ff @(posedge PCLK, negedge PRESETn)
|
||||||
@ -219,44 +206,38 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
|||||||
else if (SCLKenable) DivCounter <= 0;
|
else if (SCLKenable) DivCounter <= 0;
|
||||||
else DivCounter <= DivCounter + 12'b1;
|
else DivCounter <= DivCounter + 12'b1;
|
||||||
|
|
||||||
//Boolean logic that tracks frame progression
|
// Asserts when transmission is one frame before complete
|
||||||
assign FrameCompare = (FrameCount < Format[4:1]);
|
assign ReceivePenultimateFrame = ((FrameCount + 4'b0001) == Format[4:1]);
|
||||||
assign ReceivePenultimateFrameBoolean = ((FrameCount + 4'b0001) == Format[4:1]);
|
|
||||||
|
|
||||||
// Computing delays
|
// Computing delays
|
||||||
// When sckmode.pha = 0, an extra half-period delay is implicit in the cs-sck delay, and vice-versa for sck-cs
|
// 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 ImplicitDelay1 = SckMode[0] ? 9'b0 : 9'b1;
|
||||||
assign ImplicitDelay2 = SckMode[0] ? 9'b1 : 9'b0;
|
assign ImplicitDelay2 = SckMode[0] ? 9'b1 : 9'b0;
|
||||||
|
|
||||||
assign CS_SCKCompare = CS_SCKCount >= (({Delay0[7:0], 1'b0}) + ImplicitDelay1);
|
|
||||||
assign SCK_CSCompare = SCK_CSCount >= (({Delay0[15:8], 1'b0}) + ImplicitDelay2);
|
|
||||||
assign InterCSCompare = (InterCSCount >= ({Delay1[7:0],1'b0}));
|
|
||||||
assign InterXFRCompare = (InterXFRCount >= ({Delay1[15:8], 1'b0}));
|
|
||||||
|
|
||||||
// Calculate when tx/rx shift registers are full/empty
|
// Calculate when tx/rx shift registers are full/empty
|
||||||
TransmitShiftFSM TransmitShiftFSM_1 (PCLK, PRESETn, TransmitFIFOReadEmpty, ReceivePenultimateFrameBoolean, Active0, TransmitShiftEmpty);
|
TransmitShiftFSM TransmitShiftFSM(PCLK, PRESETn, TransmitFIFOReadEmpty, ReceivePenultimateFrame, Active0, TransmitShiftEmpty);
|
||||||
ReceiveShiftFSM ReceiveShiftFSM_1 (PCLK, PRESETn, SCLKenable, ReceivePenultimateFrameBoolean, SampleEdge, SckMode[0], ReceiveShiftFull);
|
ReceiveShiftFSM ReceiveShiftFSM(PCLK, PRESETn, SCLKenable, ReceivePenultimateFrame, SampleEdge, SckMode[0], ReceiveShiftFull);
|
||||||
|
|
||||||
// Calculate tx/rx fifo write and recieve increment signals
|
// Calculate tx/rx fifo write and recieve increment signals
|
||||||
assign TransmitFIFOWriteIncrement = (Memwrite & (Entry == 8'h48) & ~TransmitFIFOWriteFull & TransmitInactive);
|
|
||||||
|
|
||||||
always_ff @(posedge PCLK, negedge PRESETn)
|
always_ff @(posedge PCLK, negedge PRESETn)
|
||||||
if (~PRESETn) TransmitFIFOWriteIncrementDelay <= 0;
|
if (~PRESETn) TransmitFIFOWriteIncrement <= 0;
|
||||||
else TransmitFIFOWriteIncrementDelay <= TransmitFIFOWriteIncrement;
|
else TransmitFIFOWriteIncrement <= (Memwrite & (Entry == 8'h48) & ~TransmitFIFOWriteFull & TransmitInactive);
|
||||||
|
|
||||||
always_ff @(posedge PCLK, negedge PRESETn)
|
always_ff @(posedge PCLK, negedge PRESETn)
|
||||||
if (~PRESETn) ReceiveFIFOReadIncrement <= 0;
|
if (~PRESETn) ReceiveFIFOReadIncrement <= 0;
|
||||||
else ReceiveFIFOReadIncrement <= ((Entry == 8'h4C) & ~ReceiveFIFOReadEmpty & PSEL & ~ReceiveFIFOReadIncrement);
|
else ReceiveFIFOReadIncrement <= ((Entry == 8'h4C) & ~ReceiveFIFOReadEmpty & PSEL & ~ReceiveFIFOReadIncrement);
|
||||||
|
|
||||||
// Tx/Rx FIFOs
|
// Tx/Rx FIFOs
|
||||||
SynchFIFO #(3,8) txFIFO(PCLK, 1'b1, SCLKenable, PRESETn, TransmitFIFOWriteIncrementDelay, TransmitShiftEmpty, TransmitData[7:0], TransmitWriteWatermarkLevel, TransmitWatermark[2:0], TransmitFIFOReadData[7:0], TransmitFIFOWriteFull, TransmitFIFOReadEmpty, TransmitWriteMark, TransmitReadMark);
|
SynchFIFO #(3,8) txFIFO(PCLK, 1'b1, SCLKenable, PRESETn, TransmitFIFOWriteIncrement, TransmitShiftEmpty, TransmitData[7:0], TransmitWriteWatermarkLevel, TransmitWatermark[2:0],
|
||||||
SynchFIFO #(3,8) rxFIFO(PCLK, SCLKenable, 1'b1, PRESETn, ReceiveShiftFullDelay, ReceiveFIFOReadIncrement, ReceiveShiftRegEndian, ReceiveWatermark[2:0], ReceiveReadWatermarkLevel, ReceiveData[7:0], ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty, RecieveWriteMark, RecieveReadMark);
|
TransmitFIFOReadData[7:0], TransmitFIFOWriteFull, TransmitFIFOReadEmpty, TransmitWriteMark, TransmitReadMark);
|
||||||
|
SynchFIFO #(3,8) rxFIFO(PCLK, SCLKenable, 1'b1, PRESETn, ReceiveShiftFullDelay, ReceiveFIFOReadIncrement, ReceiveShiftRegEndian, ReceiveWatermark[2:0], ReceiveReadWatermarkLevel,
|
||||||
|
ReceiveData[7:0], ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty, RecieveWriteMark, RecieveReadMark);
|
||||||
|
|
||||||
always_ff @(posedge PCLK, negedge PRESETn)
|
always_ff @(posedge PCLK, negedge PRESETn)
|
||||||
if (~PRESETn) TransmitFIFOReadEmptyDelay <= 1;
|
if (~PRESETn) TransmitFIFOReadEmptyDelay <= 1;
|
||||||
else if (SCLKenable) TransmitFIFOReadEmptyDelay <= TransmitFIFOReadEmpty;
|
else if (SCLKenable) TransmitFIFOReadEmptyDelay <= TransmitFIFOReadEmpty;
|
||||||
|
|
||||||
|
|
||||||
always_ff @(posedge PCLK, negedge PRESETn)
|
always_ff @(posedge PCLK, negedge PRESETn)
|
||||||
if (~PRESETn) ReceiveShiftFullDelay <= 0;
|
if (~PRESETn) ReceiveShiftFullDelay <= 0;
|
||||||
else if (SCLKenable) ReceiveShiftFullDelay <= ReceiveShiftFull;
|
else if (SCLKenable) ReceiveShiftFullDelay <= ReceiveShiftFull;
|
||||||
@ -271,11 +252,11 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
|||||||
statetype state;
|
statetype state;
|
||||||
|
|
||||||
always_ff @(posedge PCLK, negedge PRESETn)
|
always_ff @(posedge PCLK, negedge PRESETn)
|
||||||
if (~PRESETn) begin state <= CS_INACTIVE;
|
if (~PRESETn) begin
|
||||||
|
state <= CS_INACTIVE;
|
||||||
FrameCount <= 4'b0;
|
FrameCount <= 4'b0;
|
||||||
|
|
||||||
/* verilator lint_off CASEINCOMPLETE */
|
|
||||||
end else if (SCLKenable) begin
|
end else if (SCLKenable) begin
|
||||||
|
/* verilator lint_off CASEINCOMPLETE */
|
||||||
case (state)
|
case (state)
|
||||||
CS_INACTIVE: begin
|
CS_INACTIVE: begin
|
||||||
CS_SCKCount <= 9'b1;
|
CS_SCKCount <= 9'b1;
|
||||||
@ -288,7 +269,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
|||||||
end
|
end
|
||||||
DELAY_0: begin
|
DELAY_0: begin
|
||||||
CS_SCKCount <= CS_SCKCount + 9'b1;
|
CS_SCKCount <= CS_SCKCount + 9'b1;
|
||||||
if (CS_SCKCompare) state <= ACTIVE_0;
|
if (CS_SCKCount >= (({Delay0[7:0], 1'b0}) + ImplicitDelay1)) state <= ACTIVE_0;
|
||||||
end
|
end
|
||||||
ACTIVE_0: begin
|
ACTIVE_0: begin
|
||||||
FrameCount <= FrameCount + 4'b1;
|
FrameCount <= FrameCount + 4'b1;
|
||||||
@ -296,7 +277,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
|||||||
end
|
end
|
||||||
ACTIVE_1: begin
|
ACTIVE_1: begin
|
||||||
InterXFRCount <= 9'b1;
|
InterXFRCount <= 9'b1;
|
||||||
if (FrameCompare) state <= ACTIVE_0;
|
if (FrameCount < Format[4:1]) state <= ACTIVE_0;
|
||||||
else if ((ChipSelectMode[1:0] == 2'b10) & ~|(Delay1[15:8]) & (~TransmitFIFOReadEmpty)) begin
|
else if ((ChipSelectMode[1:0] == 2'b10) & ~|(Delay1[15:8]) & (~TransmitFIFOReadEmpty)) begin
|
||||||
state <= ACTIVE_0;
|
state <= ACTIVE_0;
|
||||||
CS_SCKCount <= 9'b1;
|
CS_SCKCount <= 9'b1;
|
||||||
@ -310,11 +291,11 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
|||||||
end
|
end
|
||||||
DELAY_1: begin
|
DELAY_1: begin
|
||||||
SCK_CSCount <= SCK_CSCount + 9'b1;
|
SCK_CSCount <= SCK_CSCount + 9'b1;
|
||||||
if (SCK_CSCompare) state <= INTER_CS;
|
if (SCK_CSCount >= (({Delay0[15:8], 1'b0}) + ImplicitDelay2)) state <= INTER_CS;
|
||||||
end
|
end
|
||||||
INTER_CS: begin
|
INTER_CS: begin
|
||||||
InterCSCount <= InterCSCount + 9'b1;
|
InterCSCount <= InterCSCount + 9'b1;
|
||||||
if (InterCSCompare ) state <= CS_INACTIVE;
|
if (InterCSCount >= ({Delay1[7:0],1'b0})) state <= CS_INACTIVE;
|
||||||
end
|
end
|
||||||
INTER_XFR: begin
|
INTER_XFR: begin
|
||||||
CS_SCKCount <= 9'b1;
|
CS_SCKCount <= 9'b1;
|
||||||
@ -322,13 +303,14 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
|||||||
FrameCount <= 4'b0;
|
FrameCount <= 4'b0;
|
||||||
InterCSCount <= 9'b10;
|
InterCSCount <= 9'b10;
|
||||||
InterXFRCount <= InterXFRCount + 9'b1;
|
InterXFRCount <= InterXFRCount + 9'b1;
|
||||||
if (InterXFRCompare & ~TransmitFIFOReadEmptyDelay) state <= ACTIVE_0;
|
if ((InterXFRCount >= ({Delay1[15:8], 1'b0})) & ~TransmitFIFOReadEmptyDelay) state <= ACTIVE_0;
|
||||||
else if (~|ChipSelectMode[1:0]) state <= CS_INACTIVE;
|
else if (~|ChipSelectMode[1:0]) state <= CS_INACTIVE;
|
||||||
end
|
end
|
||||||
endcase
|
endcase
|
||||||
|
/* verilator lint_off CASEINCOMPLETE */
|
||||||
end
|
end
|
||||||
|
|
||||||
/* verilator lint_off CASEINCOMPLETE */
|
|
||||||
|
|
||||||
assign DelayMode = SckMode[0] ? (state == DELAY_1) : (state == ACTIVE_1 & ReceiveShiftFull);
|
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 ChipSelectInternal = (state == CS_INACTIVE | state == INTER_CS | DelayMode & ~|(Delay0[15:8])) ? ChipSelectDef : ~ChipSelectDef;
|
||||||
@ -390,7 +372,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
|||||||
assign SPICS = ChipSelectMode[0] ? ChipSelectDef : ChipSelectAuto;
|
assign SPICS = ChipSelectMode[0] ? ChipSelectDef : ChipSelectAuto;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module SynchFIFO #(parameter M =3 , N= 8)(
|
module SynchFIFO #(parameter M=3, N=8)( // 2^M entries of N bits each
|
||||||
input logic PCLK, wen, ren, PRESETn,
|
input logic PCLK, wen, ren, PRESETn,
|
||||||
input logic winc, rinc,
|
input logic winc, rinc,
|
||||||
input logic [N-1:0] wdata,
|
input logic [N-1:0] wdata,
|
||||||
@ -409,8 +391,6 @@ module SynchFIFO #(parameter M =3 , N= 8)(
|
|||||||
logic [N-1:0] mem[2**M];
|
logic [N-1:0] mem[2**M];
|
||||||
logic [M:0] rptr, wptr;
|
logic [M:0] rptr, wptr;
|
||||||
logic [M:0] rptrnext, wptrnext;
|
logic [M:0] rptrnext, wptrnext;
|
||||||
logic rempty_val;
|
|
||||||
logic wfull_val;
|
|
||||||
logic [M-1:0] raddr;
|
logic [M-1:0] raddr;
|
||||||
logic [M-1:0] waddr;
|
logic [M-1:0] waddr;
|
||||||
|
|
||||||
@ -428,53 +408,43 @@ module SynchFIFO #(parameter M =3 , N= 8)(
|
|||||||
end
|
end
|
||||||
else begin
|
else begin
|
||||||
if (wen) begin
|
if (wen) begin
|
||||||
wfull <= wfull_val;
|
wfull <= ({~wptrnext[M], wptrnext[M-1:0]} == rptr);
|
||||||
wptr <= wptrnext;
|
wptr <= wptrnext;
|
||||||
end
|
end
|
||||||
if (ren) begin
|
if (ren) begin
|
||||||
rptr <= rptrnext;
|
rptr <= rptrnext;
|
||||||
rempty <= rempty_val;
|
rempty <= (wptr == rptrnext);
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
assign raddr = rptr[M-1:0];
|
assign raddr = rptr[M-1:0];
|
||||||
assign rptrnext = rptr + {3'b0, (rinc & ~rempty)};
|
assign rptrnext = rptr + {{(M){1'b0}}, (rinc & ~rempty)};
|
||||||
assign rempty_val = (wptr == rptrnext);
|
|
||||||
assign rwatermark = ((waddr - raddr) < rwatermarklevel) & ~wfull;
|
assign rwatermark = ((waddr - raddr) < rwatermarklevel) & ~wfull;
|
||||||
assign waddr = wptr[M-1:0];
|
assign waddr = wptr[M-1:0];
|
||||||
assign wwatermark = ((waddr - raddr) > wwatermarklevel) | wfull;
|
assign wwatermark = ((waddr - raddr) > wwatermarklevel) | wfull;
|
||||||
assign wptrnext = wptr + {3'b0, (winc & ~wfull)};
|
assign wptrnext = wptr + {{(M){1'b0}}, (winc & ~wfull)};
|
||||||
assign wfull_val = ({~wptrnext[M], wptrnext[M-1:0]} == rptr);
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module TransmitShiftFSM(
|
module TransmitShiftFSM(
|
||||||
input logic PCLK, PRESETn,
|
input logic PCLK, PRESETn,
|
||||||
input logic TransmitFIFOReadEmpty, ReceivePenultimateFrameBoolean, Active0,
|
input logic TransmitFIFOReadEmpty, ReceivePenultimateFrame, Active0,
|
||||||
output logic TransmitShiftEmpty);
|
output logic TransmitShiftEmpty);
|
||||||
|
|
||||||
typedef enum logic [1:0] {TransmitShiftEmptyState, TransmitShiftHoldState, TransmitShiftNotEmptyState} statetype;
|
|
||||||
statetype TransmitState, TransmitNextState;
|
|
||||||
always_ff @(posedge PCLK, negedge PRESETn)
|
always_ff @(posedge PCLK, negedge PRESETn)
|
||||||
if (~PRESETn) TransmitState <= TransmitShiftEmptyState;
|
if (~PRESETn) TransmitShiftEmpty <= 1;
|
||||||
else TransmitState <= TransmitNextState;
|
else if (TransmitShiftEmpty) begin
|
||||||
|
if (TransmitFIFOReadEmpty | (~TransmitFIFOReadEmpty & (ReceivePenultimateFrame & Active0))) TransmitShiftEmpty <= 1;
|
||||||
|
else if (~TransmitFIFOReadEmpty) TransmitShiftEmpty <= 0;
|
||||||
|
end else begin
|
||||||
|
if (ReceivePenultimateFrame & Active0) TransmitShiftEmpty <= 1;
|
||||||
|
else TransmitShiftEmpty <= 0;
|
||||||
|
end
|
||||||
|
|
||||||
always_comb
|
|
||||||
case(TransmitState)
|
|
||||||
TransmitShiftEmptyState: begin
|
|
||||||
if (TransmitFIFOReadEmpty | (~TransmitFIFOReadEmpty & (ReceivePenultimateFrameBoolean & Active0))) TransmitNextState = TransmitShiftEmptyState;
|
|
||||||
else if (~TransmitFIFOReadEmpty) TransmitNextState = TransmitShiftNotEmptyState;
|
|
||||||
end
|
|
||||||
TransmitShiftNotEmptyState: begin
|
|
||||||
if (ReceivePenultimateFrameBoolean & Active0) TransmitNextState = TransmitShiftEmptyState;
|
|
||||||
else TransmitNextState = TransmitShiftNotEmptyState;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
assign TransmitShiftEmpty = (TransmitNextState == TransmitShiftEmptyState);
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module ReceiveShiftFSM(
|
module ReceiveShiftFSM(
|
||||||
input logic PCLK, PRESETn, SCLKenable,
|
input logic PCLK, PRESETn, SCLKenable,
|
||||||
input logic ReceivePenultimateFrameBoolean, SampleEdge, SckMode,
|
input logic ReceivePenultimateFrame, SampleEdge, SckMode,
|
||||||
output logic ReceiveShiftFull
|
output logic ReceiveShiftFull
|
||||||
);
|
);
|
||||||
typedef enum logic [1:0] {ReceiveShiftFullState, ReceiveShiftNotFullState, ReceiveShiftDelayState} statetype;
|
typedef enum logic [1:0] {ReceiveShiftFullState, ReceiveShiftNotFullState, ReceiveShiftDelayState} statetype;
|
||||||
@ -484,7 +454,7 @@ module ReceiveShiftFSM(
|
|||||||
else if (SCLKenable) begin
|
else if (SCLKenable) begin
|
||||||
case (ReceiveState)
|
case (ReceiveState)
|
||||||
ReceiveShiftFullState: ReceiveState <= ReceiveShiftNotFullState;
|
ReceiveShiftFullState: ReceiveState <= ReceiveShiftNotFullState;
|
||||||
ReceiveShiftNotFullState: if (ReceivePenultimateFrameBoolean & (SampleEdge)) ReceiveState <= ReceiveShiftDelayState;
|
ReceiveShiftNotFullState: if (ReceivePenultimateFrame & (SampleEdge)) ReceiveState <= ReceiveShiftDelayState;
|
||||||
else ReceiveState <= ReceiveShiftNotFullState;
|
else ReceiveState <= ReceiveShiftNotFullState;
|
||||||
ReceiveShiftDelayState: ReceiveState <= ReceiveShiftFullState;
|
ReceiveShiftDelayState: ReceiveState <= ReceiveShiftFullState;
|
||||||
endcase
|
endcase
|
||||||
@ -493,8 +463,3 @@ module ReceiveShiftFSM(
|
|||||||
assign ReceiveShiftFull = SckMode ? (ReceiveState == ReceiveShiftFullState) : (ReceiveState == ReceiveShiftDelayState);
|
assign ReceiveShiftFull = SckMode ? (ReceiveState == ReceiveShiftFullState) : (ReceiveState == ReceiveShiftDelayState);
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user