Updated the SPI test to include a test of the inverted clock mode. Also fixed a number of problems with the SPI implementation and added a status register for determining if data is still being sent.
diff --git a/README.md b/README.md index e6bae20..defe829 100644 --- a/README.md +++ b/README.md
@@ -63,10 +63,9 @@ ### verify-coreArch-gl: Not implemented # Need to do -- Write SPI test - Fix timing violations - Make final version of art -- Add buffer to interrupt signals input +- Add buffer to interrupt signals input and data registers # Could do - Misaligned architecture instructions
diff --git a/verilog/dv/peripheralsSPI/peripheralsSPI.c b/verilog/dv/peripheralsSPI/peripheralsSPI.c index cf20f1f..a7d38cc 100644 --- a/verilog/dv/peripheralsSPI/peripheralsSPI.c +++ b/verilog/dv/peripheralsSPI/peripheralsSPI.c
@@ -117,7 +117,7 @@ reg_mprj_io_13 = GPIO_MODE_USER_STD_OUTPUT; reg_mprj_io_22 = GPIO_MODE_USER_STD_OUTPUT; reg_mprj_io_23 = GPIO_MODE_USER_STD_OUTPUT; - reg_mprj_io_24 = GPIO_MODE_USER_STD_OUTPUT; + reg_mprj_io_24 = GPIO_MODE_USER_STD_INPUT_NOPULL; reg_mprj_io_25 = GPIO_MODE_USER_STD_OUTPUT; /* Apply configuration */ @@ -155,7 +155,7 @@ if (wbRead (SPI0_STATUS_REGISTER) != 0) testPass = false; nextTest (testPass); - // Check data data was received + // Check that data was received if (wbRead (SPI0_DATA) != 0xC5) testPass = false; nextTest (testPass); @@ -165,6 +165,33 @@ // Check data received back is correct // This should be the first test byte if (wbRead (SPI0_DATA) != 0x1F) testPass = false; + nextTest (testPass); + + // Change to active low clock mode + device0Config = (0b1 << 8) | (0b11 << 5) | (0b11 << 3) | 0x04; + wbWrite (SPI0_CONFIGURATION_REGISTER, device0Config); + if (wbRead (SPI0_CONFIGURATION_REGISTER) != device0Config) testPass = false; + nextTest (testPass); + + // Write fist test byte + wbWrite (SPI0_DATA, 0x1F); + + // Check data data was received + if (wbRead (SPI0_DATA) != 0xA3) testPass = false; + nextTest (testPass); + + // Write second test byte + wbWrite (SPI0_DATA, 0x83); + + // Check data received back is correct + // This should be the first test byte + if (wbRead (SPI0_DATA) != 0x1F) testPass = false; + nextTest (testPass); + + device0Config = (0b1 << 8) | (0b11 << 5) | 0x04; + wbWrite (SPI0_CONFIGURATION_REGISTER, device0Config); + if (wbRead (SPI0_CONFIGURATION_REGISTER) != device0Config) testPass = false; + nextTest (testPass); // Write third test byte for timing test wbWrite (SPI0_DATA, 0x9B);
diff --git a/verilog/dv/peripheralsSPI/peripheralsSPI_tb.v b/verilog/dv/peripheralsSPI/peripheralsSPI_tb.v index 7ab770f..7420e91 100644 --- a/verilog/dv/peripheralsSPI/peripheralsSPI_tb.v +++ b/verilog/dv/peripheralsSPI/peripheralsSPI_tb.v
@@ -54,14 +54,18 @@ assign mprj_io[21:17] = 5'b0; assign mprj_io[37:26] = 12'b0; - always @(posedge sck) begin - if (!chipSelect) shiftValue <= { shiftValue[7:1], mosi }; + reg clockMode; + wire spiClock = clockMode ^ sck; + + always @(posedge spiClock) begin + if (!chipSelect) shiftValue <= { shiftValue[6:0], mosi }; end initial begin clock = 0; timingValid = 1'b1; shiftValue = 8'hC5; + clockMode = 1'b0; end realtime timerStart; @@ -78,7 +82,7 @@ `endif // Repeat cycles of 1000 clock edges as needed to complete testbench - repeat (200) begin + repeat (500) begin repeat (1000) @(posedge clock); //$display("+1000 cycles"); end @@ -97,7 +101,7 @@ // Wait for clock signal @(posedge chipSelect); @(posedge sck); - @(posedge sck); + @(negedge sck); // Check device 0 config @(posedge nextTestOutput); @@ -108,25 +112,48 @@ // Check device isn't busy @(posedge nextTestOutput); - // Check data data was received + // Check that data was received @(posedge nextTestOutput); // Check that CS is asserted - wait(chipSelect == 1'b0); + @(negedge chipSelect); // Check that the second byte was received correctly wait(shiftValue == 8'hA3); // Check that CS is cleared - wait(chipSelect == 1'b1); + @(posedge chipSelect); // Check data received back in @(posedge nextTestOutput); - // Check that the third byte was received correctly - wait(shiftValue == 8'h9B); + clockMode = 1'b1; + + // Check device 0 config + @(posedge nextTestOutput); + + // Check that the first byte was received correctly + wait(shiftValue == 8'h1F); + + // Check that data was received + @(posedge nextTestOutput); + + // Check that the second byte was received correctly + wait(shiftValue == 8'h83); + + // Check data received back in + @(posedge nextTestOutput); + + clockMode = 1'b0; + + // Check device 0 config + @(posedge nextTestOutput); // Check clock period is correct + + // Check that CS is asserted + wait(chipSelect == 1'b0); + // Wait for signal start @(negedge sck); timerStart = $realtime; @@ -145,6 +172,8 @@ if (timerLength < 390 || timerLength > 410) timingValid = 1'b0; else $display("Invalid time, should be between 390 and 410"); + // Check that the third byte was received correctly + wait(shiftValue == 8'h9B); // Wait for management core to output the final output test result @(posedge nextTestOutput);
diff --git a/verilog/rtl/Peripherals/SPI/SPIDevice.v b/verilog/rtl/Peripherals/SPI/SPIDevice.v index 60d078a..69084a0 100644 --- a/verilog/rtl/Peripherals/SPI/SPIDevice.v +++ b/verilog/rtl/Peripherals/SPI/SPIDevice.v
@@ -12,13 +12,13 @@ output wire peripheralBus_busy, input wire[15:0] peripheralBus_address, input wire[3:0] peripheralBus_byteSelect, - output wire[31:0] peripheralBus_dataRead, + output reg[31:0] peripheralBus_dataRead, input wire[31:0] peripheralBus_dataWrite, output wire requestOutput, // SPI interface output wire spi_en, - output wire spi_clk, + output reg spi_clk, output wire spi_mosi, input wire spi_miso, output wire spi_cs @@ -73,121 +73,162 @@ wire spiClockPolarity = spiMode[1]; wire spiSampleMode = spiMode[0]; - // Input and Output register - wire[31:0] dataRegisterOutputData; - wire dataRegisterOutputRequest; - wire[7:0] readData; - wire[7:0] writeData; - wire writeData_en; - wire dataRegisterBusBusy_nc; - wire dataRegisterReadDataEnable_nc; - DataRegister #(.WIDTH(8), .ADDRESS(12'h004)) dataRegister( + // Status register + wire deviceBusy = state != STATE_IDLE; + wire[31:0] statusRegisterOutputData; + wire statusRegisterOutputRequest; + wire statusRegisterWriteData_nc; + wire statusRegisterWriteDataEnable_nc; + wire statusRegisterReadDataEnable_nc; + wire statusRegisterBusBusy_nc; + DataRegister #(.WIDTH(1), .ADDRESS(12'h004)) statusRegister( .clk(clk), .rst(rst), .enable(deviceEnable), .peripheralBus_we(peripheralBus_we), .peripheralBus_oe(peripheralBus_oe), - .peripheralBus_busy(dataRegisterBusBusy_nc), + .peripheralBus_busy(statusRegisterBusBusy_nc), + .peripheralBus_address(localAddress), + .peripheralBus_byteSelect(peripheralBus_byteSelect), + .peripheralBus_dataWrite(peripheralBus_dataWrite), + .peripheralBus_dataRead(statusRegisterOutputData), + .requestOutput(statusRegisterOutputRequest), + .writeData(statusRegisterWriteData_nc), + .writeData_en(statusRegisterWriteDataEnable_nc), + .writeData_busy(1'b0), + .readData(deviceBusy), + .readData_en(statusRegisterReadDataEnable_nc), + .readData_busy(1'b0)); + + // Input and Output register + wire[31:0] dataRegisterOutputData; + wire dataRegisterOutputRequest; + wire[7:0] dataRegisterReadData; + wire[7:0] dataRegisterWriteData; + wire dataRegisterWriteDataEnable; + wire dataRegisterBusBusy; + wire dataRegisterReadDataEnable_nc; + DataRegister #(.WIDTH(8), .ADDRESS(12'h008)) dataRegister( + .clk(clk), + .rst(rst), + .enable(deviceEnable), + .peripheralBus_we(peripheralBus_we), + .peripheralBus_oe(peripheralBus_oe), + .peripheralBus_busy(dataRegisterBusBusy), .peripheralBus_address(localAddress), .peripheralBus_byteSelect(peripheralBus_byteSelect), .peripheralBus_dataWrite(peripheralBus_dataWrite), .peripheralBus_dataRead(dataRegisterOutputData), .requestOutput(dataRegisterOutputRequest), - .writeData(writeData), - .writeData_en(writeData_en), - .writeData_busy(1'b0), - .readData(readData), + .writeData(dataRegisterWriteData), + .writeData_en(dataRegisterWriteDataEnable), + .writeData_busy(deviceBusy), + .readData(dataRegisterReadData), .readData_en(dataRegisterReadDataEnable_nc), - .readData_busy(1'b0)); + .readData_busy(deviceBusy)); // State control reg[1:0] state = STATE_IDLE; - wire busy = state != STATE_IDLE; reg[2:0] bitCounter = 3'b0; wire[2:0] nextBitCounter = bitCounter + 1; reg[CLOCK_WIDTH-1:0] clockCounter = {CLOCK_WIDTH{1'b0}}; - wire nextClockCounter = clockCounter + 1; - wire[CLOCK_WIDTH-1:0] clockScaleHalfMask = {CLOCK_BITS{1'b1}} << clockScale; - wire[CLOCK_WIDTH-1:0] clockScaleMask = { clockScaleMask[CLOCK_WIDTH-2:0], 1'b0 }; - wire spiHalfClock = clockCounter == (clockScaleHalfMask - 1);//|(clockCounter & clockScaleHalfMask); - wire spiClock = clockCounter == (clockScaleMask - 1); + wire[CLOCK_WIDTH-1:0] nextClockCounter = clockCounter + 1; + wire[CLOCK_WIDTH-1:0] clockScaleCompare = { {(CLOCK_WIDTH-1){1'b0}}, 1'b1 } << clockScale; + wire[CLOCK_WIDTH-1:0] clockScaleHalfCompare = { 1'b0, clockScaleCompare[CLOCK_WIDTH-1:1] }; + wire halfClockCounterMatch = nextClockCounter == clockScaleHalfCompare; + wire clockCounterMatch = nextClockCounter == clockScaleCompare; reg spiClockRise = 1'b0; reg spiClockFall = 1'b0; + reg spiClock; wire shiftInEnable = spiSampleMode ? spiClockFall : spiClockRise; wire shiftOutEnable = spiSampleMode ? spiClockRise : spiClockFall; - - reg loadEnable; + + wire serialOut; ShiftRegister #(.WIDTH(8)) register ( .clk(clk), .rst(rst), - .loadEnable(loadEnable), + .loadEnable(dataRegisterWriteDataEnable), .shiftInEnable(shiftInEnable), .shiftOutEnable(shiftOutEnable), .msbFirst(msbFirst), - .parallelIn(writeData), - .parallelOut(readData), + .parallelIn(dataRegisterWriteData), + .parallelOut(dataRegisterReadData), .serialIn(spi_miso), - .serialOut(spi_mosi)); + .serialOut(serialOut)); always @(posedge clk) begin if (rst) begin state <= STATE_IDLE; bitCounter <= 3'b0; clockCounter <= {CLOCK_WIDTH{1'b0}}; - loadEnable <= 1'b0; spiClockRise <= 1'b0; spiClockFall <= 1'b0; + spiClock <= 1'b0; end else begin case (state) STATE_IDLE: begin bitCounter <= 3'b0; clockCounter <= {CLOCK_WIDTH{1'b0}}; - loadEnable <= 1'b0; + spiClockRise <= 1'b0; + spiClockFall <= 1'b0; + spiClock <= 1'b0; - if (writeData_en && peripheralBus_byteSelect[0]) begin + if (dataRegisterWriteDataEnable && peripheralBus_byteSelect[0]) begin state <= STATE_SETUP; - loadEnable <= 1'b1; end end STATE_SETUP: begin - loadEnable <= 1'b0; + clockCounter <= nextClockCounter; - if (spiHalfClock) begin - clockCounter <= {CLOCK_WIDTH{1'b0}}; + if (halfClockCounterMatch) begin bitCounter <= 1'b0; + spiClock <= 1'b1; state <= STATE_SHIFT; - end else begin - clockCounter <= nextClockCounter; - end + + if (spiClockPolarity) begin + spiClockRise <= 1'b0; + spiClockFall <= 1'b1; + end else begin + spiClockRise <= 1'b1; + spiClockFall <= 1'b0; + end + end end STATE_SHIFT: begin - if (spiClock) begin + if (clockCounterMatch) begin + clockCounter <= {CLOCK_WIDTH{1'b0}}; + spiClock <= 1'b0; + if (spiClockPolarity) begin - spiClockRise <= 1'b0; - spiClockFall <= 1'b1; - end else begin spiClockRise <= 1'b1; spiClockFall <= 1'b0; + end else begin + spiClockRise <= 1'b0; + spiClockFall <= 1'b1; end - clockCounter <= {CLOCK_WIDTH{1'b0}}; - if (bitCounter == 3'h7) state <= STATE_END; - else bitCounter <= nextBitCounter; - end else if (spiHalfClock) begin + if (bitCounter == 3'h7) begin + state <= STATE_END; + end else begin + bitCounter <= nextBitCounter; + end + end else if (halfClockCounterMatch) begin if (spiClockPolarity) begin - spiClockRise <= 1'b1; - spiClockFall <= 1'b0; - end else begin spiClockRise <= 1'b0; spiClockFall <= 1'b1; - end - + end else begin + spiClockRise <= 1'b1; + spiClockFall <= 1'b0; + end + + spiClock <= 1'b1; + clockCounter <= nextClockCounter; end else begin spiClockRise <= 1'b0; spiClockFall <= 1'b0; @@ -198,8 +239,9 @@ STATE_END: begin spiClockRise <= 1'b0; spiClockFall <= 1'b0; + spiClock <= 1'b0; - if (spiClock) state <= STATE_IDLE; + if (clockCounterMatch) state <= STATE_IDLE; else clockCounter <= nextClockCounter; end @@ -207,21 +249,34 @@ state <= STATE_IDLE; bitCounter <= 3'b0; clockCounter <= {CLOCK_WIDTH{1'b0}}; - loadEnable <= 1'b0; spiClockRise <= 1'b0; spiClockFall <= 1'b0; + spiClock <= 1'b0; end endcase end end - assign requestOutput = configurationRegisterOutputRequest || dataRegisterOutputRequest; - assign peripheralBus_dataRead = configurationRegisterOutputRequest ? configurationRegisterOutputData : - dataRegisterOutputRequest ? dataRegisterOutputData : - ~32'b0; - assign peripheralBus_busy = busy; + // Buffer the spi clock by one cycle so that it lines up with when data is sampled + always @(posedge clk) begin + if (rst) spi_clk <= 1'b0; + else spi_clk <= spiClockPolarity ? !spiClock : spiClock; + end - assign spi_clk = spiClockPolarity ? !(spiClock && busy) : spiClock && busy; - assign spi_cs = useCS ? (activeHighCS ? busy : !busy) : 1'b0; + assign requestOutput = configurationRegisterOutputRequest || statusRegisterOutputRequest || dataRegisterOutputRequest; + + always @(*) begin + case (1'b1) + configurationRegisterOutputRequest: peripheralBus_dataRead <= configurationRegisterOutputData; + statusRegisterOutputRequest: peripheralBus_dataRead <= statusRegisterOutputData; + dataRegisterOutputRequest: peripheralBus_dataRead <= dataRegisterOutputData; + default: peripheralBus_dataRead <= ~32'b0; + endcase + end + + assign peripheralBus_busy = dataRegisterBusBusy; + + assign spi_mosi = serialOut & deviceBusy; + assign spi_cs = useCS ? (activeHighCS ? deviceBusy : !deviceBusy) : 1'b0; endmodule \ No newline at end of file