2023-10-12 20:36:57 +00:00
///////////////////////////////////////////
// spi_apb.sv
//
// Written: Naiche Whyte-Aguayo nwhyteaguayo@g.hmc.edu 11/16/2022
//
// Purpose: SPI peripheral
// See FU540-C000-v1.0 for specifications
//
// A component of the Wally configurable RISC-V project.
//
// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University
//
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
//
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
// may obtain a copy of the License at
//
// https://solderpad.org/licenses/SHL-2.1/
//
// Unless required by applicable law or agreed to in writing, any work distributed under the
// License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions
// and limitations under the License.
////////////////////////////////////////////////////////////////////////////////////////////////
// Current limitations: Flash read sequencer mode not implemented, dual and quad modes untestable with current test plan.
2023-10-31 19:27:41 +00:00
// Hardware interlock change to busy signal
2023-11-01 08:26:34 +00:00
// write tests for fifo full and empty watermark edge cases
// HoldModeDeassert verilater lint, relook in general
// Comment on FIFOs: watermark calculations
2023-10-31 19:27:41 +00:00
/ * high level explanation of architecture
2023-11-01 08:26:34 +00:00
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 bus 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 .
2023-10-31 19:27:41 +00:00
*/
2023-10-31 00:00:20 +00:00
2023-10-12 20:36:57 +00:00
module spi_apb import cvw : : * ; # ( parameter cvw_t P ) (
input logic PCLK , PRESETn ,
input logic PSEL ,
input logic [ 7 : 0 ] PADDR ,
input logic [ P . XLEN - 1 : 0 ] PWDATA ,
input logic [ P . XLEN / 8 - 1 : 0 ] PSTRB ,
input logic PWRITE ,
input logic PENABLE ,
output logic PREADY ,
output logic [ P . XLEN - 1 : 0 ] PRDATA ,
output logic [ 3 : 0 ] SPIOut ,
input logic [ 3 : 0 ] SPIIn ,
output logic [ 3 : 0 ] SPICS ,
output logic SPIIntr
) ;
//SPI registers
2023-11-01 08:26:34 +00:00
logic [ 11 : 0 ] SckDiv ;
logic [ 1 : 0 ] SckMode ;
logic [ 1 : 0 ] ChipSelectID ;
logic [ 3 : 0 ] ChipSelectDef ;
logic [ 1 : 0 ] ChipSelectMode ;
logic [ 15 : 0 ] Delay0 , Delay1 ;
logic [ 7 : 0 ] Format ;
2023-10-12 20:36:57 +00:00
logic [ 8 : 0 ] ReceiveData ;
logic [ 8 : 0 ] ReceiveDataPlaceholder ;
2023-11-01 08:26:34 +00:00
logic [ 2 : 0 ] TransmitWatermark , ReceiveWatermark ;
2023-10-12 20:36:57 +00:00
logic [ 8 : 0 ] TransmitData ;
2023-11-01 08:26:34 +00:00
logic [ 1 : 0 ] InterruptEnable , InterruptPending ;
2023-10-12 20:36:57 +00:00
//bus interface signals
logic [ 7 : 0 ] Entry ;
logic Memwrite ;
logic [ 31 : 0 ] Din , Dout ;
//FIFO FSM signals
logic TransmitWriteMark , TransmitReadMark , RecieveWriteMark , RecieveReadMark ;
logic TransmitFIFOWriteFull , TransmitFIFOReadEmpty ;
logic TransmitFIFOWriteIncrement , TransmitFIFOReadIncrement ;
logic ReceiveFIFOWriteIncrement , ReceiveFIFOReadIncrement ;
logic ReceiveFIFOWriteFull , ReceiveFIFOReadEmpty ;
logic [ 7 : 0 ] TransmitFIFOReadData , ReceiveFIFOWriteData ;
logic [ 2 : 0 ] TransmitWriteWatermarkLevel , ReceiveReadWatermarkLevel ;
logic TransmitFIFOReadEmptyDelay ;
logic [ 7 : 0 ] ReceiveShiftRegEndian ;
//transmission signals
logic sck ;
logic [ 12 : 0 ] DivCounter ;
2023-10-31 00:00:20 +00:00
logic SCLKenable ;
2023-10-12 20:36:57 +00:00
logic [ 8 : 0 ] Delay0Count ;
logic [ 8 : 0 ] Delay1Count ;
logic Delay0Compare ;
logic Delay1Compare ;
logic InterCSCompare ;
logic [ 8 : 0 ] InterCSCount ;
logic InterXFRCompare ;
logic [ 8 : 0 ] InterXFRCount ;
logic [ 3 : 0 ] ChipSelectInternal ;
logic [ 4 : 0 ] FrameCount ;
logic [ 4 : 0 ] FrameCompare ;
logic FrameCompareBoolean ;
logic [ 4 : 0 ] FrameCountShifted ;
logic [ 4 : 0 ] ReceivePenultimateFrame ;
logic [ 4 : 0 ] ReceivePenultimateFrameCount ;
logic ReceivePenultimateFrameBoolean ;
logic [ 4 : 0 ] FrameCompareProtocol ;
logic ReceiveShiftFull ;
logic TransmitShiftEmpty ;
logic HoldModeDeassert ;
//state fsm signals
logic Active ;
logic Active0 ;
logic Inactive ;
//shift reg signals
logic TransmitFIFOWriteIncrementDelay ;
logic sckPhaseSelect ;
logic [ 7 : 0 ] TransmitShiftReg ;
logic [ 7 : 0 ] ReceiveShiftReg ;
logic SampleEdge ;
logic [ 7 : 0 ] TransmitDataEndian ;
logic TransmitShiftRegLoad ;
//CS signals
logic [ 3 : 0 ] ChipSelectAuto , ChipSelectHold , CSoff ;
logic ChipSelectHoldSingle ;
logic ReceiveShiftFullDelay ;
2023-10-31 00:00:20 +00:00
logic SCLKenableDelay ;
logic [ 3 : 0 ] shiftin ;
logic [ 7 : 0 ] ReceiveShiftRegInvert ;
logic ZeroDelayHoldMode ;
logic TransmitInactive ;
logic SCLKenableEarly ;
logic ReceiveShiftFullDelayPCLK ;
2023-10-31 19:27:41 +00:00
logic [ 2 : 0 ] LeftShiftAmount ;
logic [ 7 : 0 ] ASR ; // AlignedReceiveShiftReg
2023-11-01 08:26:34 +00:00
logic DelayMode ;
2023-10-12 20:36:57 +00:00
2023-11-01 08:26:34 +00:00
// apb
2023-10-12 20:36:57 +00:00
assign Entry = { PADDR [ 7 : 2 ] , 2 'b00 } ; // 32-bit word-aligned accesses
assign Memwrite = PWRITE & PENABLE & PSEL ; // only write in access phase
2023-11-01 08:26:34 +00:00
//assign PREADY = 1'b1; // tie high if hardware interlock solution doesn't involve bus
assign PREADY = TransmitInactive ; // tie PREADY to transmission for hardware interlock
2023-10-31 00:00:20 +00:00
2023-10-12 20:36:57 +00:00
// account for subword read/write circuitry
// -- Note GPIO registers are 32 bits no matter what; access them with LW SW.
// (At least that's what I think when FE310 spec says "only naturally aligned 32-bit accesses are supported")
if ( P . XLEN = = 64 ) begin
assign Din = Entry [ 2 ] ? PWDATA [ 63 : 32 ] : PWDATA [ 31 : 0 ] ;
assign PRDATA = Entry [ 2 ] ? { Dout , 32 'b0 } : { 32 'b0 , Dout } ;
end else begin // 32-bit
assign Din = PWDATA [ 31 : 0 ] ;
assign PRDATA = Dout ;
end
// register access
always_ff @ ( posedge PCLK , negedge PRESETn )
if ( ~ PRESETn ) begin
SckDiv < = # 1 12 'd3 ;
SckMode < = # 1 2 'b0 ;
ChipSelectID < = # 1 2 'b0 ;
ChipSelectDef < = # 1 4 'b1111 ;
ChipSelectMode < = # 1 0 ;
Delay0 < = # 1 { 8 'b1 , 8 'b1 } ;
Delay1 < = # 1 { 8 'b0 , 8 'b1 } ;
Format < = # 1 { 8 'b10000000 } ;
TransmitData < = # 1 9 'b0 ;
//ReceiveData <= #1 9'b100000000;
TransmitWatermark < = # 1 3 'b0 ;
ReceiveWatermark < = # 1 3 'b0 ;
InterruptEnable < = # 1 2 'b0 ;
InterruptPending < = # 1 2 'b0 ;
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
//From spec. "Hardware interlocks ensure that the current transfer completes before mode transitions and control register updates take effect"
// Interpreting 'current transfer' as one frame
/* verilator lint_off CASEINCOMPLETE */
if ( Memwrite )
case ( Entry ) //flop to sample inputs
2023-11-01 08:26:34 +00:00
8 'h00 : SckDiv < = Din [ 11 : 0 ] ;
8 'h04 : SckMode < = Din [ 1 : 0 ] ;
8 'h10 : ChipSelectID < = Din [ 1 : 0 ] ;
8 'h14 : ChipSelectDef < = Din [ 3 : 0 ] ;
8 'h18 : ChipSelectMode < = Din [ 1 : 0 ] ;
8 'h28 : Delay0 < = { Din [ 23 : 16 ] , Din [ 7 : 0 ] } ;
8 'h2C : Delay1 < = { Din [ 23 : 16 ] , Din [ 7 : 0 ] } ;
8 'h40 : Format < = { Din [ 19 : 16 ] , Din [ 3 : 0 ] } ;
2023-10-12 20:36:57 +00:00
8 'h48 : if ( ~ TransmitFIFOWriteFull ) TransmitData [ 7 : 0 ] < = Din [ 7 : 0 ] ;
2023-11-01 08:26:34 +00:00
8 'h50 : TransmitWatermark < = Din [ 2 : 0 ] ;
8 'h54 : ReceiveWatermark < = Din [ 2 : 0 ] ;
8 'h70 : InterruptEnable < = Din [ 1 : 0 ] ;
2023-10-12 20:36:57 +00:00
endcase
/* verilator lint_off CASEINCOMPLETE */
//interrupt clearance
InterruptPending [ 0 ] < = TransmitReadMark ;
InterruptPending [ 1 ] < = RecieveWriteMark ;
case ( Entry ) // flop to sample inputs
2023-10-13 21:22:32 +00:00
8 'h00 : Dout < = # 1 { 20 'b0 , SckDiv } ;
8 'h04 : Dout < = # 1 { 30 'b0 , SckMode } ;
8 'h10 : Dout < = # 1 { 30 'b0 , ChipSelectID } ;
8 'h14 : Dout < = # 1 { 28 'b0 , ChipSelectDef } ;
8 'h18 : Dout < = # 1 { 30 'b0 , ChipSelectMode } ;
8 'h28 : Dout < = { 8 'b0 , Delay0 [ 15 : 8 ] , 8 'b0 , Delay0 [ 7 : 0 ] } ;
8 'h2C : Dout < = { 8 'b0 , Delay1 [ 15 : 8 ] , 8 'b0 , Delay1 [ 7 : 0 ] } ;
8 'h40 : Dout < = { 12 'b0 , Format [ 7 : 4 ] , 12 'b0 , Format [ 3 : 0 ] } ;
8 'h48 : Dout < = # 1 { 23 'b0 , TransmitFIFOWriteFull , 8 'b0 } ;
8 'h4C : Dout < = # 1 { 23 'b0 , ReceiveFIFOReadEmpty , ReceiveData [ 7 : 0 ] } ;
8 'h50 : Dout < = # 1 { 29 'b0 , TransmitWatermark } ;
8 'h54 : Dout < = # 1 { 29 'b0 , ReceiveWatermark } ;
8 'h70 : Dout < = # 1 { 30 'b0 , InterruptEnable } ;
8 'h74 : Dout < = # 1 { 30 'b0 , InterruptPending } ;
2023-10-12 20:36:57 +00:00
default : Dout < = # 1 32 'b0 ;
endcase
end
2023-10-31 00:00:20 +00:00
2023-11-01 08:26:34 +00:00
// 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
assign SCLKenable = ( DivCounter = = { 1 'b0 , SckDiv } ) ;
assign SCLKenableEarly = ( ( DivCounter + 13 'b1 ) = = { 1 'b0 , SckDiv } ) ;
2023-10-31 00:00:20 +00:00
always_ff @ ( posedge PCLK , negedge PRESETn )
if ( ~ PRESETn ) DivCounter < = # 1 0 ;
else if ( SCLKenable ) DivCounter < = 0 ;
else DivCounter < = DivCounter + 13 'b1 ;
always_ff @ ( posedge PCLK , negedge PRESETn )
if ( ~ PRESETn ) SCLKenableDelay < = 0 ;
else SCLKenableDelay < = SCLKenable ;
2023-11-01 08:26:34 +00:00
//Boolean logic that tracks frame progression
2023-10-12 20:36:57 +00:00
//multiplies frame count by 2 or 4 if in dual or quad mode
always_comb
case ( Format [ 1 : 0 ] )
2 'b00 : FrameCountShifted = FrameCount ;
2 'b01 : FrameCountShifted = { FrameCount [ 3 : 0 ] , 1 'b0 } ;
2 'b10 : FrameCountShifted = { FrameCount [ 2 : 0 ] , 2 'b0 } ;
default : FrameCountShifted = FrameCount ;
endcase
//Calculates penultimate frame
2023-11-01 08:26:34 +00:00
//Frame compare doubles number of frames in dual or quad mode to account for half-duplex communication
2023-10-12 20:36:57 +00:00
//FrameCompareProtocol further adjusts comparison according to dual or quad mode
always_comb
case ( Format [ 1 : 0 ] )
2 'b00 : begin
ReceivePenultimateFrame = 5 'b00001 ;
FrameCompareProtocol = FrameCompare ;
end
2 'b01 : begin
ReceivePenultimateFrame = 5 'b00010 ;
//add 1 to count if # of bits is odd so doubled # will be correct
// for ex. 5 bits needs 3 frames, 5*2 = 10 which will be reached in 5 frames not 3*2.
FrameCompareProtocol = Format [ 4 ] ? FrameCompare + 5 'b1 : FrameCompare ;
end
2 'b10 : begin
ReceivePenultimateFrame = 5 'b00100 ;
//if frame len =< 4, need 2 frames (one to send 1-4 bits, one to recieve)
//else, 4 < frame len =<8 8, which by same logic needs 4 frames
if ( Format [ 7 : 4 ] > 4 'b0100 ) FrameCompareProtocol = 5 'b10000 ;
else FrameCompareProtocol = 5 'b01000 ;
end
default : begin
ReceivePenultimateFrame = 5 'b00001 ;
FrameCompareProtocol = FrameCompare ;
end
endcase
assign FrameCompareBoolean = ( FrameCountShifted < FrameCompareProtocol ) ;
assign ReceivePenultimateFrameCount = FrameCountShifted + ReceivePenultimateFrame ;
assign ReceivePenultimateFrameBoolean = ( ReceivePenultimateFrameCount > = FrameCompareProtocol ) ;
// Computing delays
// When sckmode.pha = 0, an extra half-period delay is implicit in the cs-sck delay, and vice-versa for sck-cs
assign Delay0Compare = SckMode [ 0 ] ? ( Delay0Count > = ( { Delay0 [ 7 : 0 ] , 1 'b0 } ) ) : ( Delay0Count > = ( { Delay0 [ 7 : 0 ] , 1 'b0 } + 9 'b1 ) ) ;
assign Delay1Compare = SckMode [ 0 ] ? ( Delay1Count > = ( ( { Delay0 [ 15 : 8 ] , 1 'b0 } ) + 9 'b1 ) ) : ( Delay1Count > = ( { Delay0 [ 15 : 8 ] , 1 'b0 } ) ) ;
assign InterCSCompare = ( InterCSCount > = ( { Delay1 [ 7 : 0 ] , 1 'b0 } ) ) ;
assign InterXFRCompare = ( InterXFRCount > = ( { Delay1 [ 15 : 8 ] , 1 'b0 } ) ) ;
// double number of frames in dual or quad mode because we must wait for peripheral to send back
assign FrameCompare = ( Format [ 0 ] | Format [ 1 ] ) ? ( { Format [ 7 : 4 ] , 1 'b0 } ) : { 1 'b0 , Format [ 7 : 4 ] } ;
2023-10-31 00:00:20 +00:00
// Transmit and Receive FIFOs
//calculate when tx/rx shift registers are full/empty
TransmitShiftFSM TransmitShiftFSM_1 ( PCLK , PRESETn , TransmitFIFOReadEmpty , ReceivePenultimateFrameBoolean , Active0 , TransmitShiftEmpty ) ;
ReceiveShiftFSM ReceiveShiftFSM_1 ( PCLK , PRESETn , SCLKenable , ReceivePenultimateFrameBoolean , SampleEdge , SckMode [ 0 ] , ReceiveShiftFull ) ;
//calculate tx/rx fifo write and recieve increment signals
assign TransmitFIFOWriteIncrement = ( Memwrite & ( Entry = = 8 'h48 ) & ~ TransmitFIFOWriteFull ) ;
2023-10-12 20:36:57 +00:00
2023-10-31 00:00:20 +00:00
always_ff @ ( posedge PCLK , negedge PRESETn )
if ( ~ PRESETn ) TransmitFIFOWriteIncrementDelay < = 0 ;
else TransmitFIFOWriteIncrementDelay < = TransmitFIFOWriteIncrement ;
2023-10-12 20:36:57 +00:00
2023-10-31 00:00:20 +00:00
assign TransmitFIFOReadIncrement = TransmitShiftEmpty ;
assign ReceiveFIFOWriteIncrement = ReceiveShiftFullDelay ;
2023-10-12 20:36:57 +00:00
always_ff @ ( posedge PCLK , negedge PRESETn )
2023-10-31 00:00:20 +00:00
if ( ~ PRESETn ) ReceiveFIFOReadIncrement < = 0 ;
else if ( ~ ReceiveFIFOReadIncrement ) ReceiveFIFOReadIncrement < = ( ( Entry = = 8 'h4C ) & ~ ReceiveFIFOReadEmpty & PSEL ) ;
else ReceiveFIFOReadIncrement < = 0 ;
2023-11-01 08:26:34 +00:00
TransmitSynchFIFO # ( 3 , 8 ) txFIFO ( PCLK , SCLKenable , PRESETn , TransmitFIFOWriteIncrementDelay , TransmitFIFOReadIncrement , TransmitData [ 7 : 0 ] , TransmitWriteWatermarkLevel , TransmitWatermark [ 2 : 0 ] , TransmitFIFOReadData [ 7 : 0 ] , TransmitFIFOWriteFull , TransmitFIFOReadEmpty , TransmitWriteMark , TransmitReadMark ) ;
2023-10-31 00:00:20 +00:00
ReceiveSynchFIFO # ( 3 , 8 ) rxFIFO ( PCLK , SCLKenable , PRESETn , ReceiveFIFOWriteIncrement , ReceiveFIFOReadIncrement , ReceiveShiftRegEndian , ReceiveWatermark [ 2 : 0 ] , ReceiveReadWatermarkLevel , ReceiveData [ 7 : 0 ] , ReceiveFIFOWriteFull , ReceiveFIFOReadEmpty , RecieveWriteMark , RecieveReadMark ) ;
always_ff @ ( posedge PCLK , negedge PRESETn )
if ( ~ PRESETn ) TransmitFIFOReadEmptyDelay < = 1 ;
else if ( SCLKenable ) TransmitFIFOReadEmptyDelay < = TransmitFIFOReadEmpty ;
always_ff @ ( posedge PCLK , negedge PRESETn )
if ( ~ PRESETn ) ReceiveShiftFullDelay < = 0 ;
else if ( SCLKenable ) ReceiveShiftFullDelay < = ReceiveShiftFull ;
always_ff @ ( posedge PCLK , negedge PRESETn )
if ( ~ PRESETn ) ReceiveShiftFullDelayPCLK < = 0 ;
else if ( SCLKenableEarly ) ReceiveShiftFullDelayPCLK < = ReceiveShiftFull ;
assign TransmitShiftRegLoad = ~ TransmitShiftEmpty & ~ Active | ( ( ( ChipSelectMode = = 2 'b10 ) & ~ | ( Delay1 [ 15 : 8 ] ) ) & ( ( ReceiveShiftFullDelay | ReceiveShiftFull ) & ~ SampleEdge & ~ TransmitFIFOReadEmpty ) ) ;
2023-10-12 20:36:57 +00:00
//Main FSM which controls SPI transmission
typedef enum logic [ 2 : 0 ] { CS_INACTIVE , DELAY_0 , ACTIVE_0 , ACTIVE_1 , DELAY_1 , INTER_CS , INTER_XFR } statetype ;
statetype state ;
always_ff @ ( posedge PCLK , negedge PRESETn )
if ( ~ PRESETn ) begin state < = CS_INACTIVE ;
FrameCount < = 5 'b0 ;
/* verilator lint_off CASEINCOMPLETE */
2023-10-31 00:00:20 +00:00
end else if ( SCLKenable ) begin
2023-10-12 20:36:57 +00:00
case ( state )
CS_INACTIVE: begin
Delay0Count < = 9 'b1 ;
Delay1Count < = 9 'b10 ;
FrameCount < = 5 'b0 ;
InterCSCount < = 9 'b10 ;
InterXFRCount < = 9 'b1 ;
if ( ( ~ TransmitFIFOReadEmpty | ~ TransmitShiftEmpty ) & ( ( | ( Delay0 [ 7 : 0 ] ) ) | ~ SckMode [ 0 ] ) ) state < = DELAY_0 ;
else if ( ( ~ TransmitFIFOReadEmpty | ~ TransmitShiftEmpty ) ) state < = ACTIVE_0 ;
end
DELAY_0: begin
Delay0Count < = Delay0Count + 9 'b1 ;
if ( Delay0Compare ) state < = ACTIVE_0 ;
end
ACTIVE_0: begin
FrameCount < = FrameCount + 5 'b1 ;
state < = ACTIVE_1 ;
end
ACTIVE_1: begin
InterXFRCount < = 9 'b1 ;
if ( FrameCompareBoolean ) state < = ACTIVE_0 ;
else if ( HoldModeDeassert ) state < = CS_INACTIVE ;
else if ( ( ChipSelectMode [ 1 : 0 ] = = 2 'b10 ) & ~ | ( Delay1 [ 15 : 8 ] ) & ( ~ TransmitFIFOReadEmpty ) ) begin
state < = ACTIVE_0 ;
Delay0Count < = 9 'b1 ;
Delay1Count < = 9 'b10 ;
FrameCount < = 5 'b0 ;
InterCSCount < = 9 'b10 ;
end
else if ( ChipSelectMode [ 1 : 0 ] = = 2 'b10 ) state < = INTER_XFR ;
else if ( ~ | ( Delay0 [ 15 : 8 ] ) & ( ~ SckMode [ 0 ] ) ) state < = INTER_CS ;
else state < = DELAY_1 ;
end
DELAY_1: begin
Delay1Count < = Delay1Count + 9 'b1 ;
if ( Delay1Compare ) state < = INTER_CS ;
end
INTER_CS: begin
InterCSCount < = InterCSCount + 9 'b1 ;
if ( InterCSCompare ) state < = CS_INACTIVE ;
end
INTER_XFR: begin
Delay0Count < = 9 'b1 ;
Delay1Count < = 9 'b10 ;
FrameCount < = 5 'b0 ;
InterCSCount < = 9 'b10 ;
InterXFRCount < = InterXFRCount + 9 'b1 ;
if ( HoldModeDeassert ) state < = CS_INACTIVE ;
else if ( InterXFRCompare & ~ TransmitFIFOReadEmptyDelay ) state < = ACTIVE_0 ;
else if ( ~ | ChipSelectMode [ 1 : 0 ] ) state < = CS_INACTIVE ;
end
endcase
end
2023-10-31 00:00:20 +00:00
2023-10-12 20:36:57 +00:00
/* verilator lint_off CASEINCOMPLETE */
2023-11-01 08:26:34 +00:00
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 ;
2023-10-12 20:36:57 +00:00
assign sck = ( state = = ACTIVE_0 ) ? ~ SckMode [ 1 ] : SckMode [ 1 ] ;
assign Active = ( state = = ACTIVE_0 | state = = ACTIVE_1 ) ;
2023-10-31 00:00:20 +00:00
assign SampleEdge = SckMode [ 0 ] ? ( state = = ACTIVE_1 ) : ( state = = ACTIVE_0 ) ;
assign ZeroDelayHoldMode = ( ( ChipSelectMode = = 2 'b10 ) & ( ~ | ( Delay1 [ 7 : 4 ] ) ) ) ;
assign TransmitInactive = ( ( state = = INTER_CS ) | ( state = = CS_INACTIVE ) | ( state = = INTER_XFR ) | ( ReceiveShiftFullDelayPCLK & ZeroDelayHoldMode ) ) ;
2023-10-12 20:36:57 +00:00
assign Active0 = ( state = = ACTIVE_0 ) ;
assign Inactive = ( state = = CS_INACTIVE ) ;
2023-11-01 08:26:34 +00:00
// Ensures that when ChipSelectMode = hold, CS pin is deasserted only when a different value is written to csmode or csid or a write to csdeg changes the state
// of the selected pin
2023-10-12 20:36:57 +00:00
always_ff @ ( posedge PCLK , negedge PRESETn )
if ( ~ PRESETn ) HoldModeDeassert < = 0 ;
else if ( Inactive ) HoldModeDeassert < = 0 ;
/* verilator lint_off WIDTH */
else if ( ( ( ChipSelectMode [ 1 : 0 ] = = 2 'b10 ) & ( Entry = = ( 8 'h18 | 8 'h10 ) | ( ( Entry = = 8 'h14 ) & ( ( PWDATA [ ChipSelectID ] ) ! = ChipSelectDef [ ChipSelectID ] ) ) ) ) & Memwrite ) HoldModeDeassert < = 1 ;
/* verilator lint_on WIDTH */
2023-11-01 08:26:34 +00:00
// Signal tracks which edge of sck to shift data
2023-10-12 20:36:57 +00:00
always_comb
case ( SckMode [ 1 : 0 ] )
2023-10-31 00:00:20 +00:00
2 'b00 : sckPhaseSelect = ~ sck & SCLKenable ;
2 'b01 : sckPhaseSelect = ( sck & | ( FrameCount ) & SCLKenable ) ;
2 'b10 : sckPhaseSelect = sck & SCLKenable ;
2 'b11 : sckPhaseSelect = ( ~ sck & | ( FrameCount ) & SCLKenable ) ;
default : sckPhaseSelect = sck & SCLKenable ;
2023-10-12 20:36:57 +00:00
endcase
2023-11-01 08:26:34 +00:00
//Transmit shift register
assign TransmitDataEndian = Format [ 2 ] ? { TransmitFIFOReadData [ 0 ] , TransmitFIFOReadData [ 1 ] , TransmitFIFOReadData [ 2 ] , TransmitFIFOReadData [ 3 ] , TransmitFIFOReadData [ 4 ] , TransmitFIFOReadData [ 5 ] , TransmitFIFOReadData [ 6 ] , TransmitFIFOReadData [ 7 ] } : TransmitFIFOReadData [ 7 : 0 ] ;
2023-10-12 20:36:57 +00:00
always_ff @ ( posedge PCLK , negedge PRESETn )
if ( ~ PRESETn ) begin
TransmitShiftReg < = 8 'b0 ;
end
2023-11-01 08:26:34 +00:00
else if ( TransmitShiftRegLoad ) TransmitShiftReg < = TransmitDataEndian ;
2023-10-12 20:36:57 +00:00
else if ( sckPhaseSelect ) begin
//if ((ChipSelectMode[1:0] == 2'b10) & ~|(Delay1[15:8]) & (~TransmitFIFOReadEmpty) & TransmitShiftEmpty) TransmitShiftReg <= TransmitFIFOReadData;
if ( Active ) begin
case ( Format [ 1 : 0 ] )
2 'b00 : TransmitShiftReg < = { TransmitShiftReg [ 6 : 0 ] , 1 'b0 } ;
2 'b01 : TransmitShiftReg < = { TransmitShiftReg [ 5 : 0 ] , 2 'b0 } ;
2 'b10 : TransmitShiftReg < = { TransmitShiftReg [ 3 : 0 ] , 4 'b0 } ;
default : TransmitShiftReg < = { TransmitShiftReg [ 6 : 0 ] , 1 'b0 } ;
endcase
end
end
always_comb
2023-10-31 19:27:41 +00:00
2023-11-01 08:26:34 +00:00
//Output pin control based on single, dual, or quad mode
2023-10-12 20:36:57 +00:00
if ( Active | Delay0Compare | ~ TransmitShiftEmpty ) begin
case ( Format [ 1 : 0 ] )
2 'b00 : SPIOut = { 3 'b0 , TransmitShiftReg [ 7 ] } ;
2 'b01 : SPIOut = { 2 'b0 , TransmitShiftReg [ 6 ] , TransmitShiftReg [ 7 ] } ;
// assuming SPIOut[0] is first bit transmitted etc
2 'b10 : SPIOut = { TransmitShiftReg [ 3 ] , TransmitShiftReg [ 2 ] , TransmitShiftReg [ 1 ] , TransmitShiftReg [ 0 ] } ;
default : SPIOut = { 3 'b0 , TransmitShiftReg [ 7 ] } ;
endcase
end else SPIOut = 4 'b0 ;
2023-10-31 00:00:20 +00:00
2023-11-01 08:26:34 +00:00
//If in loopback mode, receive shift register is connected directly to module's output pins. Else, connected to SPIIn
//There are no setup/hold time issues because transmit shift register and receive shift register always shift/sample on opposite edges
2023-10-12 20:36:57 +00:00
assign shiftin = P . SPI_LOOPBACK_TEST ? SPIOut : SPIIn ;
2023-10-31 19:27:41 +00:00
// Receive shift register
2023-10-12 20:36:57 +00:00
always_ff @ ( posedge PCLK , negedge PRESETn )
if ( ~ PRESETn ) ReceiveShiftReg < = 8 'b0 ;
2023-10-31 00:00:20 +00:00
else if ( SampleEdge & SCLKenable ) begin
2023-10-12 20:36:57 +00:00
if ( ~ Active ) ReceiveShiftReg < = 8 'b0 ;
else if ( ~ Format [ 3 ] ) begin
case ( Format [ 1 : 0 ] )
2 'b00 : ReceiveShiftReg < = { ReceiveShiftReg [ 6 : 0 ] , shiftin [ 0 ] } ;
2 'b01 : ReceiveShiftReg < = { ReceiveShiftReg [ 5 : 0 ] , shiftin [ 0 ] , shiftin [ 1 ] } ;
2 'b10 : ReceiveShiftReg < = { ReceiveShiftReg [ 3 : 0 ] , shiftin [ 0 ] , shiftin [ 1 ] , shiftin [ 2 ] , shiftin [ 3 ] } ;
default : ReceiveShiftReg < = { ReceiveShiftReg [ 6 : 0 ] , shiftin [ 0 ] } ;
endcase
end
end
2023-10-31 19:27:41 +00:00
// Aligns received data and reverses if little-endian
assign LeftShiftAmount = 8 - Format [ 7 : 4 ] ;
assign ASR = ReceiveShiftReg < < LeftShiftAmount ;
assign ReceiveShiftRegEndian = Format [ 2 ] ? { ASR [ 0 ] , ASR [ 1 ] , ASR [ 2 ] , ASR [ 3 ] , ASR [ 4 ] , ASR [ 5 ] , ASR [ 6 ] , ASR [ 7 ] } : ASR [ 7 : 0 ] ;
2023-10-12 20:36:57 +00:00
2023-10-31 19:27:41 +00:00
// Interrupt logic: raise interrupt if any enabled interrupts are pending
2023-10-12 20:36:57 +00:00
assign SPIIntr = | ( InterruptPending & InterruptEnable ) ;
2023-10-31 19:27:41 +00:00
// Chip select logic
2023-10-12 20:36:57 +00:00
always_comb
case ( ChipSelectID [ 1 : 0 ] )
2 'b00 : ChipSelectAuto = { ChipSelectDef [ 3 ] , ChipSelectDef [ 2 ] , ChipSelectDef [ 1 ] , ChipSelectInternal [ 0 ] } ;
2 'b01 : ChipSelectAuto = { ChipSelectDef [ 3 ] , ChipSelectDef [ 2 ] , ChipSelectInternal [ 1 ] , ChipSelectDef [ 0 ] } ;
2 'b10 : ChipSelectAuto = { ChipSelectDef [ 3 ] , ChipSelectInternal [ 2 ] , ChipSelectDef [ 1 ] , ChipSelectDef [ 0 ] } ;
2 'b11 : ChipSelectAuto = { ChipSelectInternal [ 3 ] , ChipSelectDef [ 2 ] , ChipSelectDef [ 1 ] , ChipSelectDef [ 0 ] } ;
endcase
assign SPICS = ChipSelectMode [ 0 ] ? ChipSelectDef : ChipSelectAuto ;
endmodule
2023-10-17 05:57:02 +00:00
module TransmitSynchFIFO # ( parameter M = 3 , N = 8 ) (
2023-11-01 08:26:34 +00:00
input logic PCLK , sclken , PRESETn ,
2023-10-12 20:36:57 +00:00
input logic winc , rinc ,
input logic [ N - 1 : 0 ] wdata ,
input logic [ M - 1 : 0 ] wwatermarklevel , rwatermarklevel ,
output logic [ N - 1 : 0 ] rdata ,
output logic wfull , rempty ,
output logic wwatermark , rwatermark ) ;
2023-10-13 21:22:32 +00:00
logic [ N - 1 : 0 ] mem [ 2 * * M ] ;
logic [ M: 0 ] rptr , wptr ;
2023-10-17 05:57:02 +00:00
logic [ M: 0 ] rptrnext , wptrnext ;
2023-10-13 21:22:32 +00:00
logic rempty_val ;
logic wfull_val ;
logic [ M - 1 : 0 ] raddr ;
logic [ M - 1 : 0 ] waddr ;
assign rdata = mem [ raddr ] ;
2023-10-17 05:57:02 +00:00
always_ff @ ( posedge PCLK )
if ( winc & ~ wfull ) mem [ waddr ] < = wdata ;
2023-10-13 21:22:32 +00:00
2023-11-01 08:26:34 +00:00
// read flops are only enabled on sclk edges b/c transmit fifo is read on sclk
2023-10-17 05:57:02 +00:00
always_ff @ ( posedge PCLK , negedge PRESETn )
2023-11-01 08:26:34 +00:00
if ( ~ PRESETn ) begin
rptr < = 0 ;
wptr < = 0 ;
wfull < = 1 'b0 ;
rempty < = 1 'b1 ;
end
else begin
wfull < = wfull_val ;
wptr < = wptrnext ;
if ( sclken ) begin
rptr < = rptrnext ;
rempty < = rempty_val ;
end
end
2023-10-17 05:57:02 +00:00
assign raddr = rptr [ M - 1 : 0 ] ;
assign rptrnext = rptr + { 3 'b0 , ( rinc & ~ rempty ) } ;
2023-11-01 08:26:34 +00:00
assign rempty_val = ( wptr = = rptrnext ) ;
assign rwatermark = ( ( rptr [ M - 1 : 0 ] - wptr [ M - 1 : 0 ] ) < rwatermarklevel ) ;
2023-10-17 05:57:02 +00:00
assign waddr = wptr [ M - 1 : 0 ] ;
assign wwatermark = ( ( wptr [ M - 1 : 0 ] - rptr [ M - 1 : 0 ] ) > wwatermarklevel ) ;
assign wptrnext = wptr + { 3 'b0 , ( winc & ~ wfull ) } ;
assign wfull_val = ( { ~ wptrnext [ M ] , wptrnext [ M - 1 : 0 ] } = = rptr ) ;
2023-11-01 08:26:34 +00:00
2023-10-17 05:57:02 +00:00
endmodule
module ReceiveSynchFIFO # ( parameter M = 3 , N = 8 ) (
2023-11-01 08:26:34 +00:00
input logic PCLK , sclken , PRESETn ,
2023-10-17 05:57:02 +00:00
input logic winc , rinc ,
input logic [ N - 1 : 0 ] wdata ,
input logic [ M - 1 : 0 ] wwatermarklevel , rwatermarklevel ,
output logic [ N - 1 : 0 ] rdata ,
output logic wfull , rempty ,
output logic wwatermark , rwatermark ) ;
logic [ N - 1 : 0 ] mem [ 2 * * M ] ;
logic [ M: 0 ] rptr , wptr ;
logic [ M: 0 ] rptrnext , wptrnext ;
logic rempty_val ;
logic wfull_val ;
logic [ M - 1 : 0 ] raddr ;
logic [ M - 1 : 0 ] waddr ;
2023-10-13 21:22:32 +00:00
2023-10-17 05:57:02 +00:00
assign rdata = mem [ raddr ] ;
always_ff @ ( posedge PCLK )
if ( winc & ~ wfull & PCLK ) mem [ waddr ] < = wdata ;
2023-11-01 08:26:34 +00:00
//write flops are enabled only on sclk edges b/c receive fifo is written then
2023-10-17 05:57:02 +00:00
always_ff @ ( posedge PCLK , negedge PRESETn )
2023-11-01 08:26:34 +00:00
if ( ~ PRESETn ) begin
rptr < = 0 ;
wptr < = 0 ;
wfull < = 0 ;
rempty < = 0 ;
end else begin
rptr < = rptrnext ;
rempty < = rempty_val ;
if ( sclken ) begin
wptr < = wptrnext ;
wfull < = wfull_val ;
end
end
2023-10-17 05:57:02 +00:00
assign rwatermark = ( ( rptr [ M - 1 : 0 ] - wptr [ M - 1 : 0 ] ) < rwatermarklevel ) ;
assign raddr = rptr [ M - 1 : 0 ] ;
assign rptrnext = rptr + { 3 'b0 , ( rinc & ~ rempty ) } ;
assign rempty_val = ( wptr = = rptrnext ) ;
assign waddr = wptr [ M - 1 : 0 ] ;
assign wwatermark = ( ( wptr [ M - 1 : 0 ] - rptr [ M - 1 : 0 ] ) > wwatermarklevel ) ;
assign wptrnext = wptr + { 3 'b0 , ( winc & ~ wfull ) } ;
assign wfull_val = ( { ~ wptrnext [ M ] , wptrnext [ M - 1 : 0 ] } = = rptr ) ;
2023-11-01 08:26:34 +00:00
2023-10-12 20:36:57 +00:00
2023-10-17 05:57:02 +00:00
endmodule
2023-10-12 20:36:57 +00:00
module TransmitFIFO # ( parameter M = 3 , N = 8 ) (
input logic wclk , rclk , PRESETn ,
input logic winc , rinc ,
input logic [ N - 1 : 0 ] wdata ,
input logic [ M - 1 : 0 ] wwatermarklevel , rwatermarklevel ,
output logic [ N - 1 : 0 ] rdata ,
output logic wfull , rempty ,
output logic wwatermark , rwatermark ) ;
logic [ N - 1 : 0 ] mem [ 2 * * M ] ;
logic [ M: 0 ] wq1_rptr , wq2_rptr , rptr ;
logic [ M: 0 ] rq1_wptr , rq2_wptr , wptr ;
logic [ M: 0 ] rbin , rgraynext , rbinnext ;
logic [ M: 0 ] wbin , wgraynext , wbinnext ;
logic rempty_val ;
logic wfull_val ;
logic [ M: 0 ] wq2_rptr_bin , rq2_wptr_bin ;
logic [ M - 1 : 0 ] raddr ;
logic [ M - 1 : 0 ] waddr ;
assign rdata = mem [ raddr ] ;
always_ff @ ( posedge wclk )
if ( winc & ~ wfull ) mem [ waddr ] < = wdata ;
always_ff @ ( posedge wclk , negedge PRESETn )
if ( ~ PRESETn ) begin
wq2_rptr < = 0 ;
wq1_rptr < = 0 ;
end
else begin
wq2_rptr < = wq1_rptr ;
wq1_rptr < = rptr ;
end
always_ff @ ( posedge wclk , negedge PRESETn )
if ( ~ PRESETn ) begin
rq2_wptr < = 0 ;
rq1_wptr < = 0 ;
end
else if ( rclk ) begin
rq2_wptr < = rq1_wptr ;
rq1_wptr < = wptr ;
end
always_ff @ ( posedge wclk , negedge PRESETn )
if ( ~ PRESETn ) begin
rbin < = 0 ;
rptr < = 0 ;
end
else if ( rclk ) begin
rbin < = rbinnext ;
rptr < = rgraynext ;
end
assign rq2_wptr_bin = { rq2_wptr [ 3 ] , ( rq2_wptr [ 3 ] ^ rq2_wptr [ 2 ] ) , ( rq2_wptr [ 3 ] ^ rq2_wptr [ 2 ] ^ rq2_wptr [ 1 ] ) , ( rq2_wptr [ 3 ] ^ rq2_wptr [ 2 ] ^ rq2_wptr [ 1 ] ^ rq2_wptr [ 0 ] ) } ;
assign rwatermark = ( ( rbin [ M - 1 : 0 ] - rq2_wptr_bin [ M - 1 : 0 ] ) < rwatermarklevel ) ;
assign raddr = rbin [ M - 1 : 0 ] ;
assign rbinnext = rbin + { 3 'b0 , ( rinc & ~ rempty ) } ;
assign rgraynext = ( rbinnext > > 1 ) ^ rbinnext ;
assign rempty_val = ( rgraynext = = rq2_wptr ) ;
always_ff @ ( posedge wclk , negedge PRESETn )
if ( ~ PRESETn ) rempty < = 1 'b1 ;
else if ( rclk ) rempty < = rempty_val ;
always_ff @ ( posedge wclk , negedge PRESETn )
if ( ~ PRESETn ) begin
wbin < = 0 ;
wptr < = 0 ;
end else begin
wbin < = wbinnext ;
wptr < = wgraynext ;
end
assign waddr = wbin [ M - 1 : 0 ] ;
assign wq2_rptr_bin = { wq2_rptr [ 3 ] , ( wq2_rptr [ 3 ] ^ wq2_rptr [ 2 ] ) , ( wq2_rptr [ 3 ] ^ wq2_rptr [ 2 ] ^ wq2_rptr [ 1 ] ) , ( wq2_rptr [ 3 ] ^ wq2_rptr [ 2 ] ^ wq2_rptr [ 1 ] ^ wq2_rptr [ 0 ] ) } ;
assign wwatermark = ( ( wbin [ M - 1 : 0 ] - wq2_rptr_bin [ M - 1 : 0 ] ) > wwatermarklevel ) ;
assign wbinnext = wbin + { 3 'b0 , ( winc & ~ wfull ) } ;
assign wgraynext = ( wbinnext > > 1 ) ^ wbinnext ;
assign wfull_val = ( wgraynext = = { ( ~ wq2_rptr [ M: M - 1 ] ) , wq2_rptr [ M - 2 : 0 ] } ) ;
always_ff @ ( posedge wclk , negedge PRESETn )
if ( ~ PRESETn ) wfull < = 1 'b0 ;
else wfull < = wfull_val ;
endmodule
module ReceiveFIFO # ( parameter M = 3 , N = 8 ) (
input logic wclk , rclk , PRESETn ,
input logic winc , rinc ,
input logic [ N - 1 : 0 ] wdata ,
input logic [ M - 1 : 0 ] wwatermarklevel , rwatermarklevel ,
output logic [ N - 1 : 0 ] rdata ,
output logic wfull , rempty ,
output logic wwatermark , rwatermark ) ;
logic [ N - 1 : 0 ] mem [ 2 * * M ] ;
logic [ M: 0 ] wq1_rptr , wq2_rptr , rptr ;
logic [ M: 0 ] rq1_wptr , rq2_wptr , wptr ;
logic [ M: 0 ] rbin , rgraynext , rbinnext ;
logic [ M: 0 ] wbin , wgraynext , wbinnext ;
logic rempty_val ;
logic wfull_val ;
logic [ M: 0 ] wq2_rptr_bin , rq2_wptr_bin ;
logic [ M - 1 : 0 ] raddr ;
logic [ M - 1 : 0 ] waddr ;
assign rdata = mem [ raddr ] ;
always_ff @ ( posedge rclk )
if ( winc & ~ wfull & wclk ) mem [ waddr ] < = wdata ;
always_ff @ ( posedge rclk , negedge PRESETn )
if ( ~ PRESETn ) begin
wq2_rptr < = 0 ;
wq1_rptr < = 0 ;
end
else if ( wclk ) begin
wq2_rptr < = wq1_rptr ;
wq1_rptr < = rptr ;
end
always_ff @ ( posedge rclk , negedge PRESETn )
if ( ~ PRESETn ) begin
rq2_wptr < = 0 ;
rq1_wptr < = 0 ;
end
else begin
rq2_wptr < = rq1_wptr ;
rq1_wptr < = wptr ;
end
always_ff @ ( posedge rclk , negedge PRESETn )
if ( ~ PRESETn ) begin
rbin < = 0 ;
rptr < = 0 ;
end
else begin
rbin < = rbinnext ;
rptr < = rgraynext ;
end
assign rq2_wptr_bin = { rq2_wptr [ 3 ] , ( rq2_wptr [ 3 ] ^ rq2_wptr [ 2 ] ) , ( rq2_wptr [ 3 ] ^ rq2_wptr [ 2 ] ^ rq2_wptr [ 1 ] ) , ( rq2_wptr [ 3 ] ^ rq2_wptr [ 2 ] ^ rq2_wptr [ 1 ] ^ rq2_wptr [ 0 ] ) } ;
assign rwatermark = ( ( rbin [ M - 1 : 0 ] - rq2_wptr_bin [ M - 1 : 0 ] ) < rwatermarklevel ) ;
assign raddr = rbin [ M - 1 : 0 ] ;
assign rbinnext = rbin + { 3 'b0 , ( rinc & ~ rempty ) } ;
assign rgraynext = ( rbinnext > > 1 ) ^ rbinnext ;
assign rempty_val = ( rgraynext = = rq2_wptr ) ;
always_ff @ ( posedge rclk , negedge PRESETn )
if ( ~ PRESETn ) rempty < = 1 'b1 ;
else rempty < = rempty_val ;
always_ff @ ( posedge rclk , negedge PRESETn )
if ( ~ PRESETn ) begin
wbin < = 0 ;
wptr < = 0 ;
end else if ( wclk ) begin
wbin < = wbinnext ;
wptr < = wgraynext ;
end
assign waddr = wbin [ M - 1 : 0 ] ;
assign wq2_rptr_bin = { wq2_rptr [ 3 ] , ( wq2_rptr [ 3 ] ^ wq2_rptr [ 2 ] ) , ( wq2_rptr [ 3 ] ^ wq2_rptr [ 2 ] ^ wq2_rptr [ 1 ] ) , ( wq2_rptr [ 3 ] ^ wq2_rptr [ 2 ] ^ wq2_rptr [ 1 ] ^ wq2_rptr [ 0 ] ) } ;
assign wwatermark = ( ( wbin [ M - 1 : 0 ] - wq2_rptr_bin [ M - 1 : 0 ] ) > wwatermarklevel ) ;
assign wbinnext = wbin + { 3 'b0 , ( winc & ~ wfull ) } ;
assign wgraynext = ( wbinnext > > 1 ) ^ wbinnext ;
assign wfull_val = ( wgraynext = = { ( ~ wq2_rptr [ M: M - 1 ] ) , wq2_rptr [ M - 2 : 0 ] } ) ;
always_ff @ ( posedge rclk , negedge PRESETn )
if ( ~ PRESETn ) wfull < = 1 'b0 ;
else if ( wclk ) wfull < = wfull_val ;
endmodule
module TransmitShiftFSM (
input logic PCLK , PRESETn ,
input logic TransmitFIFOReadEmpty , ReceivePenultimateFrameBoolean , Active0 ,
output logic TransmitShiftEmpty ) ;
typedef enum logic [ 1 : 0 ] { TransmitShiftEmptyState , TransmitShiftHoldState , TransmitShiftNotEmptyState } statetype ;
statetype TransmitState , TransmitNextState ;
always_ff @ ( posedge PCLK , negedge PRESETn )
if ( ~ PRESETn ) TransmitState < = TransmitShiftEmptyState ;
else TransmitState < = TransmitNextState ;
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
module ReceiveShiftFSM (
2023-10-31 00:00:20 +00:00
input logic PCLK , PRESETn , SCLKenable ,
2023-10-12 20:36:57 +00:00
input logic ReceivePenultimateFrameBoolean , SampleEdge , SckMode ,
output logic ReceiveShiftFull
) ;
typedef enum logic [ 1 : 0 ] { ReceiveShiftFullState , ReceiveShiftNotFullState , ReceiveShiftDelayState } statetype ;
statetype ReceiveState , ReceiveNextState ;
always_ff @ ( posedge PCLK , negedge PRESETn )
if ( ~ PRESETn ) ReceiveState < = ReceiveShiftNotFullState ;
2023-10-31 00:00:20 +00:00
else if ( SCLKenable ) begin
2023-10-12 20:36:57 +00:00
case ( ReceiveState )
ReceiveShiftFullState: ReceiveState < = ReceiveShiftNotFullState ;
ReceiveShiftNotFullState: if ( ReceivePenultimateFrameBoolean & ( SampleEdge ) ) ReceiveState < = ReceiveShiftDelayState ;
else ReceiveState < = ReceiveShiftNotFullState ;
ReceiveShiftDelayState: ReceiveState < = ReceiveShiftFullState ;
endcase
end
assign ReceiveShiftFull = SckMode ? ( ReceiveState = = ReceiveShiftFullState ) : ( ReceiveState = = ReceiveShiftDelayState ) ;
endmodule