hardware interlock

This commit is contained in:
naichewa 2023-10-30 17:00:20 -07:00
parent 0ff9ce527d
commit 2330f4ee63
5 changed files with 286 additions and 82 deletions

View File

@ -1,2 +1,2 @@
vsim -do "do wally.do rv64gc wally64priv" vsim -do "do wally.do rv64gc wally64periph"

View File

@ -26,8 +26,11 @@
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
// Current limitations: Flash read sequencer mode not implemented, dual and quad modes untestable with current test plan. // Current limitations: Flash read sequencer mode not implemented, dual and quad modes untestable with current test plan.
// Hardware interlocks to ensure transfer finishes before register changes unimplemented // Hardware interlock cs_mode hold interaction
//TODO: change tests to reflect swizzled Delay0, Delay1, Format // relook at fifo empty full logic; might be that watermark level is low when full
@ -52,18 +55,18 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
//SPI registers //SPI registers
logic [11:0] SckDiv; logic [11:0] SckDiv, HISckDiv;
logic [1:0] SckMode; logic [1:0] SckMode, HISckMode;
logic [1:0] ChipSelectID; logic [1:0] ChipSelectID, HIChipSelectID;
logic [3:0] ChipSelectDef; logic [3:0] ChipSelectDef, HIChipSelectDef;
logic [1:0] ChipSelectMode; logic [1:0] ChipSelectMode, HIChipSelectMode;
logic [15:0] Delay0, Delay1; logic [15:0] Delay0, Delay1, HIDelay0, HIDelay1;
logic [7:0] Format; logic [7:0] Format, HIFormat;
logic [8:0] ReceiveData; logic [8:0] ReceiveData;
logic [8:0] ReceiveDataPlaceholder; logic [8:0] ReceiveDataPlaceholder;
logic [2:0] TransmitWatermark, ReceiveWatermark; logic [2:0] TransmitWatermark, ReceiveWatermark, HITransmitWatermark, HIReceiveWatermark;
logic [8:0] TransmitData; logic [8:0] TransmitData;
logic [1:0] InterruptEnable, InterruptPending; logic [1:0] InterruptEnable, InterruptPending, HIInterruptEnable;
//bus interface signals //bus interface signals
logic [7:0] Entry; logic [7:0] Entry;
@ -87,7 +90,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
//transmission signals //transmission signals
logic sck; logic sck;
logic [12:0] DivCounter; logic [12:0] DivCounter;
logic SCLKDuty; logic SCLKenable;
logic [8:0] Delay0Count; logic [8:0] Delay0Count;
logic [8:0] Delay1Count; logic [8:0] Delay1Count;
logic Delay0Compare; logic Delay0Compare;
@ -131,10 +134,22 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
logic ReceiveShiftFullDelay; logic ReceiveShiftFullDelay;
logic SCLKenableDelay;
logic [3:0] shiftin;
logic [7:0] ReceiveShiftRegInvert;
logic ZeroDelayHoldMode;
logic TransmitInactive;
logic SCLKenableEarly;
logic ReceiveShiftFullDelayPCLK;
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 = 1'b1; // spi never takes >1 cycle to respond (float module) assign PREADY = 1'b1; // tie high if hardware interlock solution doesn't involve bus
//assign PREADY = TransmitInactive; // tie PREADY to transmission for hardware interlock
// account for subword read/write circuitry // account for subword read/write circuitry
// -- Note GPIO registers are 32 bits no matter what; access them with LW SW. // -- Note GPIO registers are 32 bits no matter what; access them with LW SW.
@ -164,6 +179,17 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
ReceiveWatermark <= #1 3'b0; ReceiveWatermark <= #1 3'b0;
InterruptEnable <= #1 2'b0; InterruptEnable <= #1 2'b0;
InterruptPending <= #1 2'b0; InterruptPending <= #1 2'b0;
HISckDiv <= #1 12'd3;
HISckMode <= #1 2'b0;
HIChipSelectID <= #1 2'b0;
HIChipSelectDef <= #1 4'b1111;
HIChipSelectMode <= #1 0;
HIDelay0 <= #1 {8'b1,8'b1};
HIDelay1 <= #1 {8'b0,8'b1};
HIFormat <= #1 {8'b10000000};
HITransmitWatermark <= #1 3'b0;
HIReceiveWatermark <= #1 3'b0;
HIInterruptEnable <= #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 //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
@ -173,19 +199,32 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
/* verilator lint_off CASEINCOMPLETE */ /* verilator lint_off CASEINCOMPLETE */
if (Memwrite) if (Memwrite)
case(Entry) //flop to sample inputs case(Entry) //flop to sample inputs
8'h00: SckDiv <= Din[11:0]; 8'h00: HISckDiv <= Din[11:0];
8'h04: SckMode <= Din[1:0]; 8'h04: HISckMode <= Din[1:0];
8'h10: ChipSelectID <= Din[1:0]; 8'h10: HIChipSelectID <= Din[1:0];
8'h14: ChipSelectDef <= Din[3:0]; 8'h14: HIChipSelectDef <= Din[3:0];
8'h18: ChipSelectMode <= Din[1:0]; 8'h18: HIChipSelectMode <= Din[1:0];
8'h28: Delay0 <= {Din[23:16], Din[7:0]}; 8'h28: HIDelay0 <= {Din[23:16], Din[7:0]};
8'h2C: Delay1 <= {Din[23:16], Din[7:0]}; 8'h2C: HIDelay1 <= {Din[23:16], Din[7:0]};
8'h40: Format <= {Din[19:16], Din[3:0]}; 8'h40: HIFormat <= {Din[19:16], Din[3:0]};
8'h48: if (~TransmitFIFOWriteFull) TransmitData[7:0] <= Din[7:0]; 8'h48: if (~TransmitFIFOWriteFull) TransmitData[7:0] <= Din[7:0];
8'h50: TransmitWatermark <= Din[2:0]; 8'h50: HITransmitWatermark <= Din[2:0];
8'h54: ReceiveWatermark <= Din[2:0]; 8'h54: HIReceiveWatermark <= Din[2:0];
8'h70: InterruptEnable <= Din[1:0]; 8'h70: HIInterruptEnable <= Din[1:0];
endcase endcase
if (TransmitInactive) begin
SckDiv <= HISckDiv;
SckMode <= HISckMode;
ChipSelectID <= HIChipSelectID;
ChipSelectDef <= HIChipSelectDef;
ChipSelectMode <= HIChipSelectMode;
Delay0 <= HIDelay0;
Delay1 <= HIDelay1;
Format <= HIFormat;
TransmitWatermark <= HITransmitWatermark;
ReceiveWatermark <= HIReceiveWatermark;
InterruptEnable <= HIInterruptEnable;
end
/* verilator lint_off CASEINCOMPLETE */ /* verilator lint_off CASEINCOMPLETE */
//interrupt clearance //interrupt clearance
InterruptPending[0] <= TransmitReadMark; InterruptPending[0] <= TransmitReadMark;
@ -208,6 +247,23 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
default: Dout <= #1 32'b0; default: Dout <= #1 32'b0;
endcase endcase
end end
assign SCLKenable = (DivCounter >= {1'b0,SckDiv});
assign SCLKenableEarly = ((DivCounter + 13'b1) >= {1'b0, SckDiv});
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;
//SCK_CONTROL //SCK_CONTROL
//multiplies frame count by 2 or 4 if in dual or quad mode //multiplies frame count by 2 or 4 if in dual or quad mode
@ -269,18 +325,46 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
// double number of frames in dual or quad mode because we must wait for peripheral to send back // 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]}; assign FrameCompare = (Format[0] | Format[1]) ? ({Format[7:4], 1'b0}) : {1'b0,Format[7:4]};
// 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);
// Producing SCLK //calculate tx/rx fifo write and recieve increment signals
// SCLK = PCLK/(2*(sclk_div + 1)) assign TransmitFIFOWriteIncrement = (Memwrite & (Entry == 8'h48) & ~TransmitFIFOWriteFull);
// SCLKDuty is high every half-period of SCLK
assign SCLKDuty = (DivCounter >= {1'b0,SckDiv});
always_ff @(posedge PCLK, negedge PRESETn) always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) DivCounter <= #1 0; if (~PRESETn) TransmitFIFOWriteIncrementDelay <= 0;
else if (SCLKDuty) DivCounter <= 0; else TransmitFIFOWriteIncrementDelay <= TransmitFIFOWriteIncrement;
else DivCounter <= DivCounter + 13'b1;
assign TransmitFIFOReadIncrement = TransmitShiftEmpty;
assign ReceiveFIFOWriteIncrement = ReceiveShiftFullDelay;
always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) ReceiveFIFOReadIncrement <= 0;
else if (~ReceiveFIFOReadIncrement) ReceiveFIFOReadIncrement <= ((Entry == 8'h4C) & ~ReceiveFIFOReadEmpty & PSEL);
else ReceiveFIFOReadIncrement <= 0;
assign TransmitDataEndian = Format[2] ? {TransmitData[0], TransmitData[1], TransmitData[2], TransmitData[3], TransmitData[4], TransmitData[5], TransmitData[6], TransmitData[7]} : TransmitData[7:0];
TransmitSynchFIFO #(3,8) txFIFO(PCLK, SCLKenable, PRESETn, TransmitFIFOWriteIncrementDelay, TransmitFIFOReadIncrement, TransmitDataEndian, TransmitWriteWatermarkLevel, TransmitWatermark[2:0], TransmitFIFOReadData[7:0], TransmitFIFOWriteFull, TransmitFIFOReadEmpty, TransmitWriteMark, TransmitReadMark);
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));
//Main FSM which controls SPI transmission //Main FSM which controls SPI transmission
@ -292,7 +376,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
FrameCount <= 5'b0; FrameCount <= 5'b0;
/* verilator lint_off CASEINCOMPLETE */ /* verilator lint_off CASEINCOMPLETE */
end else if (SCLKDuty) begin end else if (SCLKenable) begin
case (state) case (state)
CS_INACTIVE: begin CS_INACTIVE: begin
Delay0Count <= 9'b1; Delay0Count <= 9'b1;
@ -346,6 +430,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
end end
endcase endcase
end end
/* verilator lint_off CASEINCOMPLETE */ /* verilator lint_off CASEINCOMPLETE */
@ -353,7 +438,9 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
assign sck = (state == ACTIVE_0) ? ~SckMode[1] : SckMode[1]; assign sck = (state == ACTIVE_0) ? ~SckMode[1] : SckMode[1];
assign busy = (state == DELAY_0 | state == ACTIVE_0 | ((state == ACTIVE_1) & ~((|(Delay1[15:8]) & (ChipSelectMode[1:0]) == 2'b10) & ((FrameCount << Format[1:0]) >= FrameCompare))) | state == DELAY_1); assign busy = (state == DELAY_0 | state == ACTIVE_0 | ((state == ACTIVE_1) & ~((|(Delay1[15:8]) & (ChipSelectMode[1:0]) == 2'b10) & ((FrameCount << Format[1:0]) >= FrameCompare))) | state == DELAY_1);
assign Active = (state == ACTIVE_0 | state == ACTIVE_1); assign Active = (state == ACTIVE_0 | state == ACTIVE_1);
assign SampleEdge = SckMode[0] ? (state == ACTIVE_1) : (state == ACTIVE_0);
assign ZeroDelayHoldMode = ((ChipSelectMode == 2'b10) & (~|(Delay1[7:4])));
assign TransmitInactive = ((state == INTER_CS) | (state == CS_INACTIVE) | (state == INTER_XFR) | (ReceiveShiftFullDelayPCLK & ZeroDelayHoldMode));
assign Active0 = (state == ACTIVE_0); assign Active0 = (state == ACTIVE_0);
assign Inactive = (state == CS_INACTIVE); assign Inactive = (state == CS_INACTIVE);
@ -363,54 +450,20 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
/* verilator lint_off WIDTH */ /* 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; 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 */ /* verilator lint_on WIDTH */
assign TransmitFIFOWriteIncrement = (Memwrite & (Entry == 8'h48) & ~TransmitFIFOWriteFull);
always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) TransmitFIFOWriteIncrementDelay <= 0;
else TransmitFIFOWriteIncrementDelay <= TransmitFIFOWriteIncrement;
assign TransmitFIFOReadIncrement = TransmitShiftEmpty;
assign ReceiveFIFOWriteIncrement = ReceiveShiftFullDelay;
always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) ReceiveFIFOReadIncrement <= 0;
else if (~ReceiveFIFOReadIncrement) ReceiveFIFOReadIncrement <= ((Entry == 8'h4C) & ~ReceiveFIFOReadEmpty & PSEL);
else ReceiveFIFOReadIncrement <= 0;
//replace literal 9th bit of ReceiveData register with concatenation of 1 bit empty signal and 8 bits of data
//so that all resets can be handled at the same time
assign SampleEdge = SckMode[0] ? (state == ACTIVE_1) : (state == ACTIVE_0);
assign TransmitDataEndian = Format[2] ? {TransmitData[0], TransmitData[1], TransmitData[2], TransmitData[3], TransmitData[4], TransmitData[5], TransmitData[6], TransmitData[7]} : TransmitData[7:0];
//TransmitFIFO #(3,8) txFIFO(PCLK, SCLKDuty, PRESETn, TransmitFIFOWriteIncrementDelay, TransmitFIFOReadIncrement, TransmitDataEndian,TransmitWriteWatermarkLevel, TransmitWatermark[2:0], TransmitFIFOReadData[7:0], TransmitFIFOWriteFull, TransmitFIFOReadEmpty, TransmitWriteMark, TransmitReadMark);
TransmitSynchFIFO #(3,8) txFIFO(PCLK, SCLKDuty, PRESETn, TransmitFIFOWriteIncrementDelay, TransmitFIFOReadIncrement, TransmitDataEndian, TransmitWriteWatermarkLevel, TransmitWatermark[2:0], TransmitFIFOReadData[7:0], TransmitFIFOWriteFull, TransmitFIFOReadEmpty, TransmitWriteMark, TransmitReadMark);
//ReceiveFIFO #(3,8) rxFIFO(SCLKDuty, PCLK, PRESETn, ReceiveFIFOWriteIncrement, ReceiveFIFOReadIncrement, ReceiveShiftRegEndian, ReceiveWatermark[2:0], ReceiveReadWatermarkLevel, ReceiveData[7:0], ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty, RecieveWriteMark, RecieveReadMark);
ReceiveSynchFIFO #(3,8) rxFIFO(PCLK, SCLKDuty, PRESETn, ReceiveFIFOWriteIncrement, ReceiveFIFOReadIncrement, ReceiveShiftRegEndian, ReceiveWatermark[2:0], ReceiveReadWatermarkLevel, ReceiveData[7:0], ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty, RecieveWriteMark, RecieveReadMark);
TransmitShiftFSM TransmitShiftFSM_1 (PCLK, PRESETn, TransmitFIFOReadEmpty, ReceivePenultimateFrameBoolean, Active0, TransmitShiftEmpty);
ReceiveShiftFSM ReceiveShiftFSM_1 (PCLK, PRESETn, SCLKDuty, ReceivePenultimateFrameBoolean, SampleEdge, SckMode[0], ReceiveShiftFull);
always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) TransmitFIFOReadEmptyDelay <= 1;
else if (SCLKDuty) TransmitFIFOReadEmptyDelay <= TransmitFIFOReadEmpty;
logic SCLKDutyDelay;
always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) SCLKDutyDelay <= 0;
else SCLKDutyDelay <= SCLKDuty;
always_comb always_comb
case(SckMode[1:0]) case(SckMode[1:0])
2'b00: sckPhaseSelect = ~sck & SCLKDuty; 2'b00: sckPhaseSelect = ~sck & SCLKenable;
2'b01: sckPhaseSelect = (sck & |(FrameCount) & SCLKDuty); 2'b01: sckPhaseSelect = (sck & |(FrameCount) & SCLKenable);
2'b10: sckPhaseSelect = sck & SCLKDuty; 2'b10: sckPhaseSelect = sck & SCLKenable;
2'b11: sckPhaseSelect = (~sck & |(FrameCount) & SCLKDuty); 2'b11: sckPhaseSelect = (~sck & |(FrameCount) & SCLKenable);
default: sckPhaseSelect = sck & SCLKDuty; default: sckPhaseSelect = sck & SCLKenable;
endcase endcase
always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) ReceiveShiftFullDelay <= 0;
else if (SCLKDuty) ReceiveShiftFullDelay <= ReceiveShiftFull;
assign TransmitShiftRegLoad = ~TransmitShiftEmpty & ~Active | (((ChipSelectMode == 2'b10) & ~|(Delay1[15:8])) & ((ReceiveShiftFullDelay | ReceiveShiftFull) & ~SampleEdge & ~TransmitFIFOReadEmpty));
always_ff @(posedge PCLK, negedge PRESETn) always_ff @(posedge PCLK, negedge PRESETn)
if(~PRESETn) begin if(~PRESETn) begin
TransmitShiftReg <= 8'b0; TransmitShiftReg <= 8'b0;
@ -437,11 +490,11 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
default: SPIOut = {3'b0, TransmitShiftReg[7]}; default: SPIOut = {3'b0, TransmitShiftReg[7]};
endcase endcase
end else SPIOut = 4'b0; end else SPIOut = 4'b0;
logic [3:0] shiftin;
assign shiftin = P.SPI_LOOPBACK_TEST ? SPIOut : SPIIn; assign shiftin = P.SPI_LOOPBACK_TEST ? SPIOut : SPIIn;
always_ff @(posedge PCLK, negedge PRESETn) always_ff @(posedge PCLK, negedge PRESETn)
if(~PRESETn) ReceiveShiftReg <= 8'b0; if(~PRESETn) ReceiveShiftReg <= 8'b0;
else if (SampleEdge & SCLKDuty) begin else if (SampleEdge & SCLKenable) begin
if (~Active) ReceiveShiftReg <= 8'b0; if (~Active) ReceiveShiftReg <= 8'b0;
else if (~Format[3]) begin else if (~Format[3]) begin
case(Format[1:0]) case(Format[1:0])
@ -452,7 +505,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
endcase endcase
end end
end end
logic [7:0] ReceiveShiftRegInvert;
assign ReceiveShiftRegInvert = (Format[2]) ? {ReceiveShiftReg[0], ReceiveShiftReg[1], ReceiveShiftReg[2], ReceiveShiftReg[3], ReceiveShiftReg[4], ReceiveShiftReg[5], ReceiveShiftReg[6], ReceiveShiftReg[7]} : ReceiveShiftReg[7:0]; assign ReceiveShiftRegInvert = (Format[2]) ? {ReceiveShiftReg[0], ReceiveShiftReg[1], ReceiveShiftReg[2], ReceiveShiftReg[3], ReceiveShiftReg[4], ReceiveShiftReg[5], ReceiveShiftReg[6], ReceiveShiftReg[7]} : ReceiveShiftReg[7:0];
always_comb always_comb
@ -805,7 +858,7 @@ module TransmitShiftFSM(
endmodule endmodule
module ReceiveShiftFSM( module ReceiveShiftFSM(
input logic PCLK, PRESETn, SCLKDuty, input logic PCLK, PRESETn, SCLKenable,
input logic ReceivePenultimateFrameBoolean, SampleEdge, SckMode, input logic ReceivePenultimateFrameBoolean, SampleEdge, SckMode,
output logic ReceiveShiftFull output logic ReceiveShiftFull
); );
@ -813,7 +866,7 @@ module ReceiveShiftFSM(
statetype ReceiveState, ReceiveNextState; statetype ReceiveState, ReceiveNextState;
always_ff @(posedge PCLK, negedge PRESETn) always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) ReceiveState <= ReceiveShiftNotFullState; if (~PRESETn) ReceiveState <= ReceiveShiftNotFullState;
else if (SCLKDuty) begin else if (SCLKenable) begin
case (ReceiveState) case (ReceiveState)
ReceiveShiftFullState: ReceiveState <= ReceiveShiftNotFullState; ReceiveShiftFullState: ReceiveState <= ReceiveShiftNotFullState;
ReceiveShiftNotFullState: if (ReceivePenultimateFrameBoolean & (SampleEdge)) ReceiveState <= ReceiveShiftDelayState; ReceiveShiftNotFullState: if (ReceivePenultimateFrameBoolean & (SampleEdge)) ReceiveState <= ReceiveShiftDelayState;

View File

@ -510,7 +510,7 @@ module testbench;
errors = errors+1; errors = errors+1;
$display(" Error on test %s result %d: adr = %h sim (D$) %h sim (DTIM_SUPPORTED) = %h, signature = %h", $display(" Error on test %s result %d: adr = %h sim (D$) %h sim (DTIM_SUPPORTED) = %h, signature = %h",
TestName, i, (testadr+i)*(P.XLEN/8), testbench.DCacheFlushFSM.ShadowRAM[testadr+i], sig, signature[i]); TestName, i, (testadr+i)*(P.XLEN/8), testbench.DCacheFlushFSM.ShadowRAM[testadr+i], sig, signature[i]);
$stop; //***debug //$stop; //***debug
end end
i = i + 1; i = i + 1;
end end

View File

@ -146,6 +146,46 @@
00000000 00000000
0000001F 0000001F
00000000 00000000
00000062 # hardware interlock
00000000
00000026
00000000
000000D2
00000000
0000002D
00000000
00000048
00000000
00000037
00000000
00000026
00000000
00000015
00000000
00000084
00000000
00000073
00000000
00000062
00000000
00000051
00000000
00000046
00000000
00000035
00000000
00000024
00000000
00000013
00000000
00000064
00000000
00000053
00000000
00000042
00000000
00000031
00000000
00000001 #watermark interrupts 00000001 #watermark interrupts
00000000 00000000
00000000 #read mip 00000000 #read mip

View File

@ -166,7 +166,7 @@ test_cases:
# Test arbitrary cs-sck delay (sck phase 1) # Test arbitrary cs-sck delay (sck phase 1)
.8byte delay0, 0x00000105, write32_test # set cs-sck delay to 5 cycles .8byte delay0, 0x00010005, write32_test # set cs-sck delay to 5 cycles
.8byte tx_data, 0x00000048, write32_test # place 8'h11 into tx_data .8byte tx_data, 0x00000048, write32_test # place 8'h11 into tx_data
.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end .8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x00000048, read32_test # read rx_data .8byte rx_data, 0x00000048, read32_test # read rx_data
@ -216,6 +216,7 @@ test_cases:
.8byte delay0, 0x00010001, write32_test # reset delay0 register .8byte delay0, 0x00010001, write32_test # reset delay0 register
.8byte delay1, 0x00000005, write32_test # set inter_cs delay to 5 .8byte delay1, 0x00000005, write32_test # set inter_cs delay to 5
.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x44332211, spi_burst_send .8byte tx_data, 0x44332211, spi_burst_send
.8byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end .8byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x00000011, read32_test .8byte rx_data, 0x00000011, read32_test
@ -226,6 +227,7 @@ test_cases:
#test long inter_cs delay #test long inter_cs delay
.8byte delay1, 0x000000A5, write32_test .8byte delay1, 0x000000A5, write32_test
.8byte rx_mark, 0x0000000, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x0000007B, write32_test .8byte tx_data, 0x0000007B, write32_test
.8byte 0x0, 0x00000000, spi_data_wait .8byte 0x0, 0x00000000, spi_data_wait
.8byte rx_data, 0x0000007B, read32_test .8byte rx_data, 0x0000007B, read32_test
@ -234,6 +236,7 @@ test_cases:
# Test inter_cs delay set to 0 # Test inter_cs delay set to 0
.8byte delay1, 0x00000000, write32_test # set inter_cs delay to 5 .8byte delay1, 0x00000000, write32_test # set inter_cs delay to 5
.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x54433221, spi_burst_send .8byte tx_data, 0x54433221, spi_burst_send
.8byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end .8byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x00000021, read32_test .8byte rx_data, 0x00000021, read32_test
@ -276,6 +279,7 @@ test_cases:
# test long inter_xfr delay # test long inter_xfr delay
.8byte delay1, 0x00A50001, write32_test .8byte delay1, 0x00A50001, write32_test
.8byte rx_mark, 0x0000000, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x00000048, write32_test .8byte tx_data, 0x00000048, write32_test
.8byte 0x0, 0x00000000, spi_data_wait .8byte 0x0, 0x00000000, spi_data_wait
.8byte rx_data, 0x00000048, read32_test .8byte rx_data, 0x00000048, read32_test
@ -284,6 +288,7 @@ test_cases:
.8byte delay1, 0x00000001, write32_test # set inter_xfr delay to 0 .8byte delay1, 0x00000001, write32_test # set inter_xfr delay to 0
.8byte delay0, 0x00010005, write32_test # set cs-sck delay to 5 (should have no effect because cs is never inactive) .8byte delay0, 0x00010005, write32_test # set cs-sck delay to 5 (should have no effect because cs is never inactive)
.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0xAABBCCDD, spi_burst_send .8byte tx_data, 0xAABBCCDD, spi_burst_send
.8byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end .8byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x000000DD, read32_test # read rx_data .8byte rx_data, 0x000000DD, read32_test # read rx_data
@ -310,6 +315,7 @@ test_cases:
.8byte sck_mode, 0x00000000, write32_test #reset sckmode register .8byte sck_mode, 0x00000000, write32_test #reset sckmode register
.8byte cs_mode, 0x00000000, write32_test # set cs_mode to AUTO .8byte cs_mode, 0x00000000, write32_test # set cs_mode to AUTO
.8byte fmt, 0x00040000, write32_test # set frame length to 4 .8byte fmt, 0x00040000, write32_test # set frame length to 4
.8byte rx_mark, 0x0000000, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x000000F0, write32_test # place 8'h11 into tx_data .8byte tx_data, 0x000000F0, write32_test # place 8'h11 into tx_data
.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end .8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x000000F0, read32_test # read rx_data .8byte rx_data, 0x000000F0, read32_test # read rx_data
@ -323,6 +329,7 @@ test_cases:
# test frame length 1 burst # test frame length 1 burst
.8byte fmt, 0x00010000, write32_test .8byte fmt, 0x00010000, write32_test
.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x80008000, spi_burst_send .8byte tx_data, 0x80008000, spi_burst_send
.8byte 0x0, 0x00000003, spi_data_wait .8byte 0x0, 0x00000003, spi_data_wait
.8byte rx_data, 0x00000000, read32_test .8byte rx_data, 0x00000000, read32_test
@ -334,12 +341,14 @@ test_cases:
# Test big endian with frame length = 5 # Test big endian with frame length = 5
.8byte fmt, 0x00050000, write32_test # set frame length to 5, big endian .8byte fmt, 0x00050000, write32_test # set frame length to 5, big endian
.8byte rx_mark, 0x0000000, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x000000A8, write32_test # place 8'h11 into tx_data .8byte tx_data, 0x000000A8, write32_test # place 8'h11 into tx_data
.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end .8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x000000A8, read32_test # read rx_data .8byte rx_data, 0x000000A8, read32_test # read rx_data
# Test big endian burst with frame length = 5 # Test big endian burst with frame length = 5
.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x03774FFF, spi_burst_send .8byte tx_data, 0x03774FFF, spi_burst_send
.8byte 0x0, 0x00000003, spi_data_wait .8byte 0x0, 0x00000003, spi_data_wait
.8byte rx_data, 0x000000F8, read32_test .8byte rx_data, 0x000000F8, read32_test
@ -353,12 +362,14 @@ test_cases:
# Test little endian with frame length = 5 # Test little endian with frame length = 5
.8byte fmt, 0x00050004, write32_test # set frame length to 5, little-endian .8byte fmt, 0x00050004, write32_test # set frame length to 5, little-endian
.8byte rx_mark, 0x0000000, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x000000A8, write32_test # place 8'h11 into tx_data .8byte tx_data, 0x000000A8, write32_test # place 8'h11 into tx_data
.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end .8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x00000008, read32_test # read rx_data -> 08 .8byte rx_data, 0x00000008, read32_test # read rx_data -> 08
#test little endian burst with frame length = 5 #test little endian burst with frame length = 5
.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0xFF4F7703, spi_burst_send .8byte tx_data, 0xFF4F7703, spi_burst_send
.8byte 0x0, 0x00000003, spi_data_wait .8byte 0x0, 0x00000003, spi_data_wait
.8byte rx_data, 0x00000003, read32_test #03 .8byte rx_data, 0x00000003, read32_test #03
@ -416,13 +427,110 @@ test_cases:
#.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end #.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
#.8byte rx_data, 0x000000F0, read32_test # read rx_data #.8byte rx_data, 0x000000F0, read32_test # read rx_data
#=========== Test Hardware Interlock ================
# interlock in base case
.8byte fmt, 0x00080000, write32_test # reset fmt register
.8byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x00000062, write32_test # initiate transmission
.8byte sck_mode, 0x00000002, write32_test # flip polarity during transmission
.8byte tx_data, 0x00000026, write32_test # transmit second frame w/ control register updated
.8byte 0x0, 0x00000001, spi_data_wait
.8byte rx_data, 0x00000062, read32_test
.8byte rx_data, 0x00000026, read32_test # clear rx fifo
.8byte sck_mode, 0x00000000, write32_test # reset polarity
# interlock in case where cs_mode is auto, but there is minimal intercs delay
.8byte delay0, 0x00000001, write32_test # set sck-cs delay to 0, with sck.pha 0 there is 0 delay
.8byte tx_data, 0x000000D2, write32_test # initiate transmission
.8byte sck_mode, 0x00000002, write32_test # flip sck polarity
.8byte tx_data, 0x0000002D, write32_test # transmit second frame
.8byte 0x0, 0x00000001, spi_data_wait
.8byte rx_data, 0x000000D2, read32_test
.8byte rx_data, 0x0000002D, read32_test # clear rx fifo
.8byte sck_mode, 0x00000000, write32_test # reset polarity
# interlock in case where cs_mode = hold, 0 intercs delay
.8byte delay0, 0x00010001, write32_test # reset delay0
.8byte sck_mode, 0x00000000, write32_test # reset polarity
.8byte cs_mode, 0x00000002, write32_test # set cs_mode to hold
.8byte tx_data, 0x15263748, spi_burst_send # place 4 frames into tx fifo
.8byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame)
.8byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end
.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.8byte sck_mode, 0x00000000, write32_test # flip polarity again
.8byte 0x0, 0x00000003, spi_data_wait # wait for final frame
.8byte rx_data, 0x00000048, read32_test
.8byte rx_data, 0x00000037, read32_test
.8byte rx_data, 0x00000026, read32_test
.8byte rx_data, 0x00000015, read32_test #clear rx fifo
# interlock in case where cs_mode = hold, intercs delay
.8byte sck_mode, 0x00000000, write32_test # reset polarity
.8byte delay1, 0x00010001, write32_test # set intercs delay to 1
.8byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x51627384, spi_burst_send # place 4 frames into tx fifo
.8byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame)
.8byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end
.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.8byte sck_mode, 0x00000000, write32_test # flip polarity again
.8byte 0x0, 0x00000003, spi_data_wait # wait for final frame
.8byte rx_data, 0x00000084, read32_test
.8byte rx_data, 0x00000073, read32_test
.8byte rx_data, 0x00000062, read32_test
.8byte rx_data, 0x00000051, read32_test #clear rx fifo
# repeat previous set of tests with cs_mode = off
.8byte cs_mode, 0x00000003, write32_test # set cs_mode to hold
.8byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x13243546, spi_burst_send # place 4 frames into tx fifo
.8byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame)
.8byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end
.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.8byte sck_mode, 0x00000000, write32_test # flip polarity again
.8byte 0x0, 0x00000003, spi_data_wait # wait for final frame
.8byte rx_data, 0x00000046, read32_test
.8byte rx_data, 0x00000035, read32_test
.8byte rx_data, 0x00000024, read32_test
.8byte rx_data, 0x00000013, read32_test #clear rx fifo
# interlock in case where cs_mode = hold, intercs delay
.8byte sck_mode, 0x00000000, write32_test # reset polarity
.8byte delay1, 0x00000000, write32_test # set intercs delay to 0
.8byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x31425364, spi_burst_send # place 4 frames into tx fifo
.8byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame)
.8byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end
.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.8byte sck_mode, 0x00000000, write32_test # flip polarity again
.8byte 0x0, 0x00000003, spi_data_wait # wait for final frame
.8byte rx_data, 0x00000064, read32_test
.8byte rx_data, 0x00000053, read32_test
.8byte rx_data, 0x00000042, read32_test
.8byte rx_data, 0x00000031, read32_test #clear rx fifo
# =========== Test watermark interrupts =========== # =========== Test watermark interrupts ===========
# Test transmit watermark interrupt (triggers when entries in tx FIFO < tx watermark) without external enables # Test transmit watermark interrupt (triggers when entries in tx FIFO < tx watermark) without external enables
SETUP_PLIC SETUP_PLIC
.8byte fmt, 0x00080000, write32_test # reset fmt register .8byte delay1, 0x0000001, write32_test # reset delay1 register
.8byte cs_mode, 0x00000000, write32_test # reset cs_mode
.8byte tx_mark, 0x00000004, write32_test # set transmit watermark to 4 .8byte tx_mark, 0x00000004, write32_test # set transmit watermark to 4
#.8byte ie, 0x00000000, write32_test # enable transmit interrupt #.8byte ie, 0x00000000, write32_test # enable transmit interrupt
.8byte ip, 0x00000001, read32_test # tx watermark interupt should be pending .8byte ip, 0x00000001, read32_test # tx watermark interupt should be pending
@ -462,6 +570,7 @@ SETUP_PLIC
# test recieve watermark interrupt (triggers when entries in rx FIFO > rx watermark) # test recieve watermark interrupt (triggers when entries in rx FIFO > rx watermark)
.8byte tx_mark, 0x00000000, write32_test .8byte tx_mark, 0x00000000, write32_test
.8byte 0x0, 0x00000000, claim_m_plic_interrupts
.8byte rx_data, 0x00000022, read32_test # clear one entry from rx FIFO .8byte rx_data, 0x00000022, read32_test # clear one entry from rx FIFO
.8byte rx_mark, 0x00000003, write32_test # set recieve watermark to 3 .8byte rx_mark, 0x00000003, write32_test # set recieve watermark to 3
.8byte ie, 0x0000002, write32_test # enable receive interrupts .8byte ie, 0x0000002, write32_test # enable receive interrupts
@ -475,4 +584,6 @@ SETUP_PLIC
.8byte ip, 0x00000000, read32_test # receive interrupt should be low .8byte ip, 0x00000000, read32_test # receive interrupt should be low
.8byte 0x0, 0x00000000, readmip_test .8byte 0x0, 0x00000000, readmip_test
.8byte 0x0, 0x0, terminate_test .8byte 0x0, 0x0, terminate_test