From 2330f4ee63fe8d6b0a046bc82f3652888c6140a8 Mon Sep 17 00:00:00 2001 From: naichewa Date: Mon, 30 Oct 2023 17:00:20 -0700 Subject: [PATCH] hardware interlock --- sim/sim-wally | 2 +- src/uncore/spi_apb.sv | 209 +++++++++++------- testbench/testbench.sv | 2 +- .../references/WALLY-spi-01.reference_output | 40 ++++ .../rv64i_m/privilege/src/WALLY-spi-01.S | 115 +++++++++- 5 files changed, 286 insertions(+), 82 deletions(-) diff --git a/sim/sim-wally b/sim/sim-wally index 6ffc3ca4f..78558c7f1 100755 --- a/sim/sim-wally +++ b/sim/sim-wally @@ -1,2 +1,2 @@ -vsim -do "do wally.do rv64gc wally64priv" +vsim -do "do wally.do rv64gc wally64periph" diff --git a/src/uncore/spi_apb.sv b/src/uncore/spi_apb.sv index deaccc346..9fab982ce 100644 --- a/src/uncore/spi_apb.sv +++ b/src/uncore/spi_apb.sv @@ -26,8 +26,11 @@ //////////////////////////////////////////////////////////////////////////////////////////////// // 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 -//TODO: change tests to reflect swizzled Delay0, Delay1, Format +// Hardware interlock cs_mode hold interaction +// 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 - 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; + logic [11:0] SckDiv, HISckDiv; + logic [1:0] SckMode, HISckMode; + logic [1:0] ChipSelectID, HIChipSelectID; + logic [3:0] ChipSelectDef, HIChipSelectDef; + logic [1:0] ChipSelectMode, HIChipSelectMode; + logic [15:0] Delay0, Delay1, HIDelay0, HIDelay1; + logic [7:0] Format, HIFormat; logic [8:0] ReceiveData; logic [8:0] ReceiveDataPlaceholder; - logic [2:0] TransmitWatermark, ReceiveWatermark; + logic [2:0] TransmitWatermark, ReceiveWatermark, HITransmitWatermark, HIReceiveWatermark; logic [8:0] TransmitData; - logic [1:0] InterruptEnable, InterruptPending; + logic [1:0] InterruptEnable, InterruptPending, HIInterruptEnable; //bus interface signals logic [7:0] Entry; @@ -87,7 +90,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( //transmission signals logic sck; logic [12:0] DivCounter; - logic SCLKDuty; + logic SCLKenable; logic [8:0] Delay0Count; logic [8:0] Delay1Count; logic Delay0Compare; @@ -131,10 +134,22 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( 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 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 // -- 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; InterruptEnable <= #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 //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 @@ -173,19 +199,32 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( /* verilator lint_off CASEINCOMPLETE */ if (Memwrite) case(Entry) //flop to sample inputs - 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]}; + 8'h00: HISckDiv <= Din[11:0]; + 8'h04: HISckMode <= Din[1:0]; + 8'h10: HIChipSelectID <= Din[1:0]; + 8'h14: HIChipSelectDef <= Din[3:0]; + 8'h18: HIChipSelectMode <= Din[1:0]; + 8'h28: HIDelay0 <= {Din[23:16], Din[7:0]}; + 8'h2C: HIDelay1 <= {Din[23:16], Din[7:0]}; + 8'h40: HIFormat <= {Din[19:16], Din[3:0]}; 8'h48: if (~TransmitFIFOWriteFull) TransmitData[7:0] <= Din[7:0]; - 8'h50: TransmitWatermark <= Din[2:0]; - 8'h54: ReceiveWatermark <= Din[2:0]; - 8'h70: InterruptEnable <= Din[1:0]; + 8'h50: HITransmitWatermark <= Din[2:0]; + 8'h54: HIReceiveWatermark <= Din[2:0]; + 8'h70: HIInterruptEnable <= Din[1:0]; 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 */ //interrupt clearance InterruptPending[0] <= TransmitReadMark; @@ -208,6 +247,23 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( default: Dout <= #1 32'b0; endcase 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 //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 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 - // SCLK = PCLK/(2*(sclk_div + 1)) - // SCLKDuty is high every half-period of SCLK - - assign SCLKDuty = (DivCounter >= {1'b0,SckDiv}); + //calculate tx/rx fifo write and recieve increment signals + assign TransmitFIFOWriteIncrement = (Memwrite & (Entry == 8'h48) & ~TransmitFIFOWriteFull); always_ff @(posedge PCLK, negedge PRESETn) - if (~PRESETn) DivCounter <= #1 0; - else if (SCLKDuty) DivCounter <= 0; - else DivCounter <= DivCounter + 13'b1; + 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; + + + 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 @@ -292,7 +376,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( FrameCount <= 5'b0; /* verilator lint_off CASEINCOMPLETE */ - end else if (SCLKDuty) begin + end else if (SCLKenable) begin case (state) CS_INACTIVE: begin Delay0Count <= 9'b1; @@ -346,6 +430,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( end endcase end + /* 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 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 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 Inactive = (state == CS_INACTIVE); @@ -363,54 +450,20 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( /* 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 */ - 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 case(SckMode[1:0]) - 2'b00: sckPhaseSelect = ~sck & SCLKDuty; - 2'b01: sckPhaseSelect = (sck & |(FrameCount) & SCLKDuty); - 2'b10: sckPhaseSelect = sck & SCLKDuty; - 2'b11: sckPhaseSelect = (~sck & |(FrameCount) & SCLKDuty); - default: sckPhaseSelect = sck & SCLKDuty; + 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; 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) if(~PRESETn) begin TransmitShiftReg <= 8'b0; @@ -437,11 +490,11 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( default: SPIOut = {3'b0, TransmitShiftReg[7]}; endcase end else SPIOut = 4'b0; - logic [3:0] shiftin; + assign shiftin = P.SPI_LOOPBACK_TEST ? SPIOut : SPIIn; always_ff @(posedge PCLK, negedge PRESETn) if(~PRESETn) ReceiveShiftReg <= 8'b0; - else if (SampleEdge & SCLKDuty) begin + else if (SampleEdge & SCLKenable) begin if (~Active) ReceiveShiftReg <= 8'b0; else if (~Format[3]) begin case(Format[1:0]) @@ -452,7 +505,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( endcase 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]; always_comb @@ -805,7 +858,7 @@ module TransmitShiftFSM( endmodule module ReceiveShiftFSM( - input logic PCLK, PRESETn, SCLKDuty, + input logic PCLK, PRESETn, SCLKenable, input logic ReceivePenultimateFrameBoolean, SampleEdge, SckMode, output logic ReceiveShiftFull ); @@ -813,7 +866,7 @@ module ReceiveShiftFSM( statetype ReceiveState, ReceiveNextState; always_ff @(posedge PCLK, negedge PRESETn) if (~PRESETn) ReceiveState <= ReceiveShiftNotFullState; - else if (SCLKDuty) begin + else if (SCLKenable) begin case (ReceiveState) ReceiveShiftFullState: ReceiveState <= ReceiveShiftNotFullState; ReceiveShiftNotFullState: if (ReceivePenultimateFrameBoolean & (SampleEdge)) ReceiveState <= ReceiveShiftDelayState; diff --git a/testbench/testbench.sv b/testbench/testbench.sv index 8d1fdff50..a417e4075 100644 --- a/testbench/testbench.sv +++ b/testbench/testbench.sv @@ -510,7 +510,7 @@ module testbench; errors = errors+1; $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]); - $stop; //***debug + //$stop; //***debug end i = i + 1; end diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-spi-01.reference_output b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-spi-01.reference_output index e8e10dc90..520908265 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-spi-01.reference_output +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-spi-01.reference_output @@ -146,6 +146,46 @@ 00000000 0000001F 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 00000000 00000000 #read mip diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S index 85c0f4d4c..c76843ef0 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S @@ -166,7 +166,7 @@ test_cases: # 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 0x0, 0x00000000, spi_data_wait # wait for transmission to end .8byte rx_data, 0x00000048, read32_test # read rx_data @@ -216,6 +216,7 @@ test_cases: .8byte delay0, 0x00010001, write32_test # reset delay0 register .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 0x0, 0x00000003, spi_data_wait # wait for transmission to end .8byte rx_data, 0x00000011, read32_test @@ -226,6 +227,7 @@ test_cases: #test long inter_cs delay .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 0x0, 0x00000000, spi_data_wait .8byte rx_data, 0x0000007B, read32_test @@ -234,6 +236,7 @@ test_cases: # Test inter_cs delay set to 0 .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 0x0, 0x00000003, spi_data_wait # wait for transmission to end .8byte rx_data, 0x00000021, read32_test @@ -276,6 +279,7 @@ test_cases: # test long inter_xfr delay .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 0x0, 0x00000000, spi_data_wait .8byte rx_data, 0x00000048, read32_test @@ -284,6 +288,7 @@ test_cases: .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 rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock .8byte tx_data, 0xAABBCCDD, spi_burst_send .8byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end .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 cs_mode, 0x00000000, write32_test # set cs_mode to AUTO .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 0x0, 0x00000000, spi_data_wait # wait for transmission to end .8byte rx_data, 0x000000F0, read32_test # read rx_data @@ -323,6 +329,7 @@ test_cases: # test frame length 1 burst .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 0x0, 0x00000003, spi_data_wait .8byte rx_data, 0x00000000, read32_test @@ -334,12 +341,14 @@ test_cases: # Test big endian with frame length = 5 .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 0x0, 0x00000000, spi_data_wait # wait for transmission to end .8byte rx_data, 0x000000A8, read32_test # read rx_data # 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 0x0, 0x00000003, spi_data_wait .8byte rx_data, 0x000000F8, read32_test @@ -353,12 +362,14 @@ test_cases: # Test little endian with frame length = 5 .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 0x0, 0x00000000, spi_data_wait # wait for transmission to end .8byte rx_data, 0x00000008, read32_test # read rx_data -> 08 #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 0x0, 0x00000003, spi_data_wait .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 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 transmit watermark interrupt (triggers when entries in tx FIFO < tx watermark) without external enables 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 ie, 0x00000000, write32_test # enable transmit interrupt .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) .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_mark, 0x00000003, write32_test # set recieve watermark to 3 .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 0x0, 0x00000000, readmip_test + + .8byte 0x0, 0x0, terminate_test \ No newline at end of file