diff --git a/.gitmodules b/.gitmodules index eed0bb58f..34a374174 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,9 +25,10 @@ sparseCheckout = true path = addins/verilog-ethernet url = https://github.com/rosethompson/verilog-ethernet.git -[submodule "cvw-arch-verif"] +[submodule "addins/cvw-arch-verif"] path = addins/cvw-arch-verif url = https://github.com/openhwgroup/cvw-arch-verif + ignore = dirty [submodule "addins/riscvISACOV"] path = addins/riscvISACOV url = https://github.com/riscv-verification/riscvISACOV.git diff --git a/addins/cvw-arch-verif b/addins/cvw-arch-verif index bbcba7864..6d658b7b4 160000 --- a/addins/cvw-arch-verif +++ b/addins/cvw-arch-verif @@ -1 +1 @@ -Subproject commit bbcba78647080dee82e96bc1b8ff9cd9a3cf7fa1 +Subproject commit 6d658b7b42c83fd584008d72964cc75d0876b769 diff --git a/addins/riscv-arch-test b/addins/riscv-arch-test index ce04b4930..3843c736e 160000 --- a/addins/riscv-arch-test +++ b/addins/riscv-arch-test @@ -1 +1 @@ -Subproject commit ce04b4930545ae4c81e2f3b6f6935e2aac08679e +Subproject commit 3843c736e427a2b52a0d06e6220b073afa4be401 diff --git a/config/rv32gc/coverage.svh b/config/rv32gc/coverage.svh index 217e8788a..97496a8b9 100644 --- a/config/rv32gc/coverage.svh +++ b/config/rv32gc/coverage.svh @@ -10,6 +10,9 @@ `include "RV32M_coverage.svh" `include "RV32F_coverage.svh" `include "RV32D_coverage.svh" +`include "RV32ZfaF_coverage.svh" +`include "RV32ZfaD_coverage.svh" +`include "RV32ZfaZfh_coverage.svh" `include "RV32ZfhD_coverage.svh" `include "RV32Zfh_coverage.svh" `include "RV32Zicond_coverage.svh" @@ -22,3 +25,5 @@ // Privileged extensions `include "ZicsrM_coverage.svh" +`include "RV32VM_coverage.svh" +`include "RV32VM_PMP_coverage.svh" diff --git a/config/rv64gc/coverage.svh b/config/rv64gc/coverage.svh index 0491b4ab3..d594a3a44 100644 --- a/config/rv64gc/coverage.svh +++ b/config/rv64gc/coverage.svh @@ -10,6 +10,9 @@ `include "RV64M_coverage.svh" `include "RV64F_coverage.svh" `include "RV64D_coverage.svh" +`include "RV64ZfaF_coverage.svh" +`include "RV32ZfaD_coverage.svh" +`include "RV32ZfaZfh_coverage.svh" `include "RV64ZfhD_coverage.svh" `include "RV64Zfh_coverage.svh" `include "RV64Zicond_coverage.svh" diff --git a/fpga/constraints/marked_debug.txt b/fpga/constraints/marked_debug.txt index 1d23c29a2..a50091827 100644 --- a/fpga/constraints/marked_debug.txt +++ b/fpga/constraints/marked_debug.txt @@ -5,3 +5,22 @@ wally/wallypipelinedcore.sv: logic InstrM lsu/lsu.sv: logic IEUAdrM lsu/lsu.sv: logic MemRWM mmu/hptw.sv: logic SATP_REGW +uncore/spi_apb.sv: logic ShiftIn +uncore/spi_apb.sv: logic ReceiveShiftReg +uncore/spi_apb.sv: logic SCLKenable +uncore/spi_apb.sv: logic SampleEdge +uncore/spi_apb.sv: logic Active +uncore/spi_apb.sv: statetype state +uncore/spi_apb.sv: typedef rsrstatetype +uncore/spi_apb.sv: logic SPICLK +uncore/spi_apb.sv: logic SPIOut +uncore/spi_apb.sv: logic SPICS +uncore/spi_apb.sv: logic SckMode +uncore/spi_apb.sv: logic SckDiv +uncore/spi_apb.sv: logic ShiftEdge +uncore/spi_apb.sv: logic TransmitShiftRegLoad +uncore/spi_apb.sv: logic TransmitShiftReg +uncore/spi_apb.sv: logic TransmitData +uncore/spi_apb.sv: logic ReceiveData +uncore/spi_apb.sv: logic ReceiveShiftRegEndian +uncore/spi_apb.sv: logic ASR diff --git a/fpga/constraints/small-debug-spi.xdc b/fpga/constraints/small-debug-spi.xdc index f62e3d4d3..5951bdcb8 100644 --- a/fpga/constraints/small-debug-spi.xdc +++ b/fpga/constraints/small-debug-spi.xdc @@ -191,7 +191,6 @@ set_property port_width 1 [get_debug_ports u_ila_0/probe33] set_property PROBE_TYPE DATA_AND_TRIGGER [get_debug_ports u_ila_0/probe33] connect_debug_port u_ila_0/probe33 [get_nets [list {wallypipelinedsoc/uncoregen.uncore/sdc.sdc/TransmitFIFOReadEmpty} ]] - # the debug hub has issues with the clocks from the mmcm so lets give up an connect to the 100Mhz input clock. #connect_debug_port dbg_hub/clk [get_nets default_100mhz_clk] connect_debug_port dbg_hub/clk [get_nets CPUCLK] diff --git a/fpga/generator/Makefile b/fpga/generator/Makefile index 7ffd9f163..52e46ec38 100644 --- a/fpga/generator/Makefile +++ b/fpga/generator/Makefile @@ -69,8 +69,8 @@ PreProcessFiles: ./insert_debug_comment.sh # This line allows the Bootloader to be loaded in a Block RAM on the FPGA sed -i "s/bit \[DATA_WIDTH-1:0\].*ROM.*/(\* rom_style=\"block\" \*) &/g" ../src/CopiedFiles_do_not_add_to_repo/generic/mem/rom1p1r.sv - sed -i 's/$$WALLY/\.\.\/\.\.\/\.\.\//g' ../src/CopiedFiles_do_not_add_to_repo/generic/mem/rom1p1r.sv - sed -i 's/$$WALLY/\.\.\/\.\.\/\.\.\//g' ../src/CopiedFiles_do_not_add_to_repo/generic/mem/ram1p1rwbe.sv + sed -i 's/$$WALLY/\.\.\/\.\.\//g' ../src/CopiedFiles_do_not_add_to_repo/generic/mem/rom1p1r.sv + sed -i 's/$$WALLY/\.\.\/\.\.\//g' ../src/CopiedFiles_do_not_add_to_repo/generic/mem/ram1p1rwbe.sv # build the Zero stage boot loader (ZSBL) .PHONY: zsbl diff --git a/fpga/generator/wally.tcl b/fpga/generator/wally.tcl index 3ca0c3360..7935b5913 100644 --- a/fpga/generator/wally.tcl +++ b/fpga/generator/wally.tcl @@ -102,7 +102,8 @@ if {$board=="ArtyA7"} { } else { #source ../constraints/vcu-small-debug.xdc #source ../constraints/small-debug.xdc - source ../constraints/small-debug-spi.xdc + #source ../constraints/small-debug.xdc + source ../constraints/big-debug-spi.xdc } diff --git a/fpga/zsbl/boot.c b/fpga/zsbl/boot.c index d9a824a49..7665b2df2 100644 --- a/fpga/zsbl/boot.c +++ b/fpga/zsbl/boot.c @@ -135,45 +135,45 @@ int disk_read(BYTE * buf, LBA_t sector, UINT count) { /* crc = crc16(crc, x); */ /* } while (--n > 0); */ - /* n = 512/8; */ - /* do { */ - /* // Send 8 dummy bytes (fifo should be empty) */ - /* for (j = 0; j < 8; j++) { */ - /* spi_sendbyte(0xff); */ - /* } */ - - /* // Reset counter. Process bytes AS THEY COME IN. */ - /* for (j = 0; j < 8; j++) { */ - /* while (!(read_reg(SPI_IP) & 2)) {} */ - /* uint8_t x = spi_readbyte(); */ - /* *p++ = x; */ - /* // crc = crc16(crc, x); */ - /* crc = ((crc << 8) ^ crctable[x ^ (crc >> 8)]) & 0xffff; */ - /* } */ - /* } while(--n > 0); */ - - n = 512; - // Initially fill the transmit fifo - for (j = 0; j < 8; j++) { - spi_sendbyte(0xff); - } - - - while (n > 0) { - // Wait for bytes to be received - while (!(read_reg(SPI_IP) & 2)) {} - // Read byte - uint8_t x = spi_readbyte(); - // Send another dummy byte - if (n > 8) { + n = 512/8; + do { + // Send 8 dummy bytes (fifo should be empty) + for (j = 0; j < 8; j++) { spi_sendbyte(0xff); } - // Place received byte into memory - *p++ = x; - // Update CRC16 with fast table based method - crc = ((crc << 8) ^ crctable[x ^ (crc >> 8)]) & 0xffff; - n = n - 1; - } + + // Reset counter. Process bytes AS THEY COME IN. + for (j = 0; j < 8; j++) { + while (!(read_reg(SPI_IP) & 2)) {} + uint8_t x = spi_readbyte(); + *p++ = x; + // crc = crc16(crc, x); + crc = ((crc << 8) ^ crctable[x ^ (crc >> 8)]) & 0xffff; + } + } while(--n > 0); + + /* n = 512; */ + /* // Initially fill the transmit fifo */ + /* for (j = 0; j < 8; j++) { */ + /* spi_sendbyte(0xff); */ + /* } */ + + + /* while (n > 0) { */ + /* // Wait for bytes to be received */ + /* while (!(read_reg(SPI_IP) & 2)) {} */ + /* // Read byte */ + /* uint8_t x = spi_readbyte(); */ + /* // Send another dummy byte */ + /* if (n > 8) { */ + /* spi_sendbyte(0xff); */ + /* } */ + /* // Place received byte into memory */ + /* *p++ = x; */ + /* // Update CRC16 with fast table based method */ + /* crc = ((crc << 8) ^ crctable[x ^ (crc >> 8)]) & 0xffff; */ + /* n = n - 1; */ + /* } */ // Read CRC16 and check crc_exp = ((uint16_t)spi_dummy() << 8); diff --git a/linux/sdcard/flash-sd.sh b/linux/sdcard/flash-sd.sh index 7a2c58d42..31e6ee45f 100755 --- a/linux/sdcard/flash-sd.sh +++ b/linux/sdcard/flash-sd.sh @@ -1,4 +1,30 @@ #!/bin/bash +########################################### +## flash-sd.sh +## +## Written: Jacob Pease jacobpease@protonmail.com +## Created: August 22, 2023 +## +## Purpose: A script to flash an sd card with a bootable linux image. +## +## A component of the CORE-V-WALLY configurable RISC-V project. +## https://github.com/openhwgroup/cvw +## +## Copyright (C) 2021-24 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. +################################################################################################ # Exit on any error (return code != 0) # set -e diff --git a/linux/sdcard/write-bytes.sh b/linux/sdcard/write-bytes.sh new file mode 100755 index 000000000..b9c312ceb --- /dev/null +++ b/linux/sdcard/write-bytes.sh @@ -0,0 +1,80 @@ +#!/bin/bash +########################################### +## write-bytes.sh +## +## Written: Jacob Pease jacobpease@protonmail.com +## Created: November 2nd, 2024 +## Modified: +## +## Purpose: Write a sequence of bytes from text file to an output file and a flash card. +## +## A component of the CORE-V-WALLY configurable RISC-V project. +## https://github.com/openhwgroup/cvw +## +## Copyright (C) 2021-24 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. +################################################################################################ + + +# This file writes a bunch of bytes to the flash card based on a text +# file input with bytes written in hexadecimal. + +usage() { echo "Usage: $0 [-zh] [-b ] " 1>&2; exit 1; } + +help() { + echo "Usage: $0 [OPTIONS] " + echo " -i Input text file with hex bytes." + echo " -b Output binary file." + exit 0; +} + +INPUTFILE="" +OUTPUTFILE="" + +ARGS=() +while [ $OPTIND -le "$#" ] ; do + if getopts "hi:o:" arg ; then + case "${arg}" in + h) help + ;; + i) INPUTFILE=${OPTARG} + ;; + o) OUTPUTFILE=${OPTARG} + ;; + esac + else + ARGS+=("${!OPTIND}") + ((OPTIND++)) + fi +done + +SDCARD=${ARGS[0]} + +if [ ! -e $INPUTFILE ] ; then + echo -e "Error: Input file $INPUTFILE does not exist." + exit 1 +fi + +if [ -e $OUTPUTFILE ] ; then + echo -e "Error: Output file $OUTPUTFILE already exists." + exit 1 +fi + +for word in $(cat "$INPUTFILE") +do + echo -en "\x$word" >> $OUTPUTFILE +done + +dd if=$OUTPUTFILE of="$SDCARD" diff --git a/sim/questa/wally.do b/sim/questa/wally.do index a53a0e3c7..c692b06e1 100644 --- a/sim/questa/wally.do +++ b/sim/questa/wally.do @@ -181,7 +181,7 @@ if {$DEBUG > 0} { # suppress spurious warnngs about # "Extra checking for conflicts with always_comb done at vopt time" # because vsim will run vopt -set INC_DIRS "+incdir+${CONFIG}/${CFG} +incdir+${CONFIG}/deriv/${CFG} +incdir+${CONFIG}/shared +incdir+${FCRVVI} +incdir+${FCRVVI}/rv32 +incdir+${FCRVVI}/rv64 +incdir+${FCRVVI}/rv64_priv +incdir+${FCRVVI}/priv +incdir+${FCRVVI}/common +incdir+${FCRVVI}" +set INC_DIRS "+incdir+${CONFIG}/${CFG} +incdir+${CONFIG}/deriv/${CFG} +incdir+${CONFIG}/shared +incdir+${FCRVVI} +incdir+${FCRVVI}/rv32 +incdir+${FCRVVI}/rv64 +incdir+${FCRVVI}/rv64_priv +incdir+${FCRVVI}/priv +incdir+${FCRVVI}/rv32_priv +incdir+${FCRVVI}/common +incdir+${FCRVVI}" set SOURCES "${SRC}/cvw.sv ${TB}/${TESTBENCH}.sv ${TB}/common/*.sv ${SRC}/*/*.sv ${SRC}/*/*/*.sv ${WALLY}/addins/verilog-ethernet/*/*.sv ${WALLY}/addins/verilog-ethernet/*/*/*/*.sv" vlog -permissive -lint -work ${WKDIR} {*}${INC_DIRS} {*}${FCvlog} {*}${FCdefineCOVER_EXTS} {*}${lockstepvlog} {*}${SOURCES} -suppress 2282,2583,7053,7063,2596,13286 diff --git a/src/fpu/fround.sv b/src/fpu/fround.sv index 6c37d2973..b5c1b975e 100644 --- a/src/fpu/fround.sv +++ b/src/fpu/fround.sv @@ -126,7 +126,7 @@ module fround import cvw::*; #(parameter cvw_t P) ( 3'b001: RoundUp = 0; // RZ 3'b010: RoundUp = Xs & (Rp | Tp); // RN 3'b011: RoundUp = ~Xs & (Rp | Tp); // RP - 3'b101: RoundUp = Rp; // RNTA + 3'b100: RoundUp = Rp; // RNTA default: RoundUp = 0; // should never happen endcase diff --git a/src/uncore/spi_apb.sv b/src/uncore/spi_apb.sv index 54a072ac9..293c2c2b5 100644 --- a/src/uncore/spi_apb.sv +++ b/src/uncore/spi_apb.sv @@ -1,7 +1,9 @@ /////////////////////////////////////////// // spi_apb.sv // -// Written: Naiche Whyte-Aguayo nwhyteaguayo@g.hmc.edu 11/16/2022 +// Written: Naiche Whyte-Aguayo nwhyteaguayo@g.hmc.edu +// Jacob Pease jacobpease@protonmail.com (October 29th, 2024) +// Created: November 16th, 2022 // // Purpose: SPI peripheral // @@ -13,7 +15,7 @@ // // A component of the Wally configurable RISC-V project. // -// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University +// Copyright (C) 2021-24 Harvey Mudd College & Oklahoma State University // // SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 // @@ -30,438 +32,337 @@ //////////////////////////////////////////////////////////////////////////////////////////////// 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 SPIOut, - input logic SPIIn, - output logic [3:0] SPICS, - output logic SPIIntr, - output logic SPICLK + 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 SPIOut, + input logic SPIIn, + output logic [3:0] SPICS, + output logic SPIIntr, + output logic SPICLK ); // register map - localparam SPI_SCKDIV = 8'h00; - localparam SPI_SCKMODE = 8'h04; - localparam SPI_CSID = 8'h10; - localparam SPI_CSDEF = 8'h14; - localparam SPI_CSMODE = 8'h18; - localparam SPI_DELAY0 = 8'h28; - localparam SPI_DELAY1 = 8'h2C; - localparam SPI_FMT = 8'h40; - localparam SPI_TXDATA = 8'h48; - localparam SPI_RXDATA = 8'h4C; - localparam SPI_TXMARK = 8'h50; - localparam SPI_RXMARK = 8'h54; - localparam SPI_IE = 8'h70; - localparam SPI_IP = 8'h74; - - // receive shift register states - typedef enum logic [1:0] {ReceiveShiftFullState, ReceiveShiftNotFullState, ReceiveShiftDelayState} rsrstatetype; - - - // SPI control registers. Refer to SiFive FU540-C000 manual - 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 [4:0] Format; - logic [7:0] ReceiveData; - logic [2:0] TransmitWatermark, ReceiveWatermark; - logic [8:0] TransmitData; - logic [1:0] InterruptEnable, InterruptPending; - - // Bus interface signals - logic [7:0] Entry; - logic Memwrite; - logic [31:0] Din, Dout; - logic TransmitInactive; // High when there is no transmission, used as hardware interlock signal - - // FIFO FSM signals - // Watermark signals - TransmitReadMark = ip[0], ReceiveWriteMark = ip[1] - logic TransmitWriteMark, TransmitReadMark, RecieveWriteMark, RecieveReadMark; - logic TransmitFIFOWriteFull, TransmitFIFOReadEmpty; - logic TransmitFIFOWriteIncrement; - logic ReceiveFiFoWriteInc; - logic ReceiveFIFOReadIncrement; - logic ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty; - logic [7:0] TransmitFIFOReadData; - /* verilator lint_off UNDRIVEN */ - logic [2:0] TransmitWriteWatermarkLevel, ReceiveReadWatermarkLevel; // unused generic FIFO outputs - /* verilator lint_off UNDRIVEN */ - logic [7:0] ReceiveShiftRegEndian; // Reverses ReceiveShiftReg if Format[2] set (little endian transmission) - rsrstatetype ReceiveState; - logic ReceiveFiFoTakingData; - - // Transmission signals - logic ZeroDiv; // High when SckDiv is 0 - logic [11:0] DivCounter; // Counter for sck - logic SCLKenable; // Flip flop enable high every sclk edge - - // Delay signals - logic [8:0] ImplicitDelay1; // Adds implicit delay to cs-sck delay counter based on phase - logic [8:0] ImplicitDelay2; // Adds implicit delay to sck-cs delay counter based on phase - logic [8:0] CS_SCKCount; // Counter for cs-sck delay - logic [8:0] SCK_CSCount; // Counter for sck-cs delay - logic [8:0] InterCSCount; // Counter for inter cs delay - logic [8:0] InterXFRCount; // Counter for inter xfr delay - logic ZeroDelayHoldMode; // High when ChipSelectMode is hold and Delay1[15:8] (InterXFR delay) is 0 - - // Frame counting signals - logic FirstFrame; - logic [3:0] FrameCount; // Counter for number of frames in transmission - logic ReceivePenultimateFrame; // High when penultimate frame in transmission has been reached - - // State fsm signals - logic Active; // High when state is either Active1 or Active0 (during transmission) - logic Active0; // High when state is Active0 - - // Shift reg signals - logic ShiftEdge; // Determines which edge of sck to shift from TransmitShiftReg - logic [7:0] TransmitShiftReg; // Transmit shift register - logic [7:0] ReceiveShiftReg; // Receive shift register - logic SampleEdge; // Determines which edge of sck to sample from ReceiveShiftReg - logic [7:0] TransmitDataEndian; // Reverses TransmitData from txFIFO if littleendian, since TransmitReg always shifts MSB - logic TransmitShiftRegLoad; // Determines when to load TransmitShiftReg - logic TransmitShiftRegLoadSingleCycle; // Version of TransmitShiftRegLoad which is only high for a single SCLK cycle to prevent double loads - logic TransmitShiftRegLoadDelay; // TransmitShiftRegLoad delayed by an SCLK cycle, inverted and anded with TransmitShiftRegLoad to create a single cycle signal - logic TransmitFIFOReadIncrement; // Increments Tx FIFO read ptr 1 cycle after Tx FIFO is read - logic ReceiveShiftFull; // High when receive shift register is full - logic TransmitShiftEmpty; // High when transmit shift register is empty - logic ShiftIn; // Determines whether to shift from SPIIn or SPIOut (if SPI_LOOPBACK_TEST) - logic [3:0] LeftShiftAmount; // Determines left shift amount to left-align data when little endian - logic [7:0] ASR; // AlignedReceiveShiftReg - logic ShiftEdgeSPICLK; // Changes ShiftEdge when SckDiv is 0 - - // CS signals - logic [3:0] ChipSelectAuto; // Assigns ChipSelect value to selected CS signal based on CS ID - logic [3:0] ChipSelectInternal; // Defines what each ChipSelect signal should be based on transmission status and ChipSelectDef - logic DelayMode; // Determines where to place implicit half cycle delay based on sck phase for CS assertion - - // Miscellaneous signals delayed/early by 1 PCLK cycle - logic ReceiveShiftFullDelay; // Delays ReceiveShiftFull signal by 1 PCLK cycle - logic ReceiveShiftFullDelayPCLK; // ReceiveShiftFull delayed by 1 PCLK cycle - logic TransmitFIFOReadEmptyDelay; - logic SCLKenableEarly; // SCLKenable 1 PCLK cycle early, needed for on time register changes when ChipSelectMode is hold and Delay1[15:8] (InterXFR delay) is 0 - - - - // APB access - assign Entry = {PADDR[7:2],2'b00}; // 32-bit word-aligned accesses - assign Memwrite = PWRITE & PENABLE & PSEL; // Only write in access phase - assign PREADY = Entry == SPI_TXDATA | Entry == SPI_RXDATA | Entry == SPI_IP | TransmitInactive; // Tie PREADY to transmission for hardware interlock - - // Account for subword read/write circuitry - // -- Note SPI registers are 32 bits no matter what; access them with LW SW. - - assign Din = PWDATA[31:0]; - if (P.XLEN == 64) assign PRDATA = { Dout, Dout}; - else assign PRDATA = Dout; - - // Register access - always_ff@(posedge PCLK) - if (~PRESETn) begin - SckDiv <= 12'd3; - SckMode <= 2'b0; - ChipSelectID <= 2'b0; - ChipSelectDef <= 4'b1111; - ChipSelectMode <= 2'b0; - Delay0 <= {8'b1,8'b1}; - Delay1 <= {8'b0,8'b1}; - Format <= {5'b10000}; - TransmitData <= 9'b0; - TransmitWatermark <= 3'b0; - ReceiveWatermark <= 3'b0; - InterruptEnable <= 2'b0; - InterruptPending <= 2'b0; - end else begin // writes - - - /* verilator lint_off CASEINCOMPLETE */ - if (Memwrite & TransmitInactive) - case(Entry) // flop to sample inputs - SPI_SCKDIV: SckDiv <= Din[11:0]; - SPI_SCKMODE: SckMode <= Din[1:0]; - SPI_CSID: ChipSelectID <= Din[1:0]; - SPI_CSDEF: ChipSelectDef <= Din[3:0]; - SPI_CSMODE: ChipSelectMode <= Din[1:0]; - SPI_DELAY0: Delay0 <= {Din[23:16], Din[7:0]}; - SPI_DELAY1: Delay1 <= {Din[23:16], Din[7:0]}; - SPI_FMT: Format <= {Din[19:16], Din[2]}; - SPI_TXMARK: TransmitWatermark <= Din[2:0]; - SPI_RXMARK: ReceiveWatermark <= Din[2:0]; - SPI_IE: InterruptEnable <= Din[1:0]; - endcase - - if (Memwrite) - case(Entry) - SPI_TXDATA: if (~TransmitFIFOWriteFull) TransmitData[7:0] <= Din[7:0]; - endcase - /* verilator lint_off CASEINCOMPLETE */ - - // According to FU540 spec: Once interrupt is pending, it will remain set until number - // of entries in tx/rx fifo is strictly more/less than tx/rxmark - InterruptPending[0] <= TransmitReadMark; - InterruptPending[1] <= RecieveWriteMark; - - case(Entry) // Flop to sample inputs - SPI_SCKDIV: Dout <= {20'b0, SckDiv}; - SPI_SCKMODE: Dout <= {30'b0, SckMode}; - SPI_CSID: Dout <= {30'b0, ChipSelectID}; - SPI_CSDEF: Dout <= {28'b0, ChipSelectDef}; - SPI_CSMODE: Dout <= {30'b0, ChipSelectMode}; - SPI_DELAY0: Dout <= {8'b0, Delay0[15:8], 8'b0, Delay0[7:0]}; - SPI_DELAY1: Dout <= {8'b0, Delay1[15:8], 8'b0, Delay1[7:0]}; - SPI_FMT: Dout <= {12'b0, Format[4:1], 13'b0, Format[0], 2'b0}; - SPI_TXDATA: Dout <= {TransmitFIFOWriteFull, 23'b0, 8'b0}; - SPI_RXDATA: Dout <= {ReceiveFIFOReadEmpty, 23'b0, ReceiveData[7:0]}; - SPI_TXMARK: Dout <= {29'b0, TransmitWatermark}; - SPI_RXMARK: Dout <= {29'b0, ReceiveWatermark}; - SPI_IE: Dout <= {30'b0, InterruptEnable}; - SPI_IP: Dout <= {30'b0, InterruptPending}; - default: Dout <= 32'b0; - endcase - end - - // SPI enable generation, where SCLK = PCLK/(2*(SckDiv + 1)) - // Asserts SCLKenable at the rising and falling edge of SCLK by counting from 0 to SckDiv - // Active at 2x SCLK frequency to account for implicit half cycle delays and actions on both clock edges depending on phase - // When SckDiv is 0, count doesn't work and SCLKenable is simply PCLK *** dh 10/26/24: this logic is seriously broken. SCLK is not scaled to PCLK/(2*(SckDiv + 1)). SCLKenableEarly doesn't work right for SckDiv=0 - assign ZeroDiv = ~|(SckDiv[10:0]); - assign SCLKenable = ZeroDiv ? 1 : (DivCounter == SckDiv); - assign SCLKenableEarly = ((DivCounter + 12'b1) == SckDiv); - always_ff @(posedge PCLK) - if (~PRESETn) DivCounter <= '0; - else if (SCLKenable) DivCounter <= 12'b0; - else DivCounter <= DivCounter + 12'b1; - - // Asserts when transmission is one frame before complete - assign ReceivePenultimateFrame = ((FrameCount + 4'b0001) == Format[4:1]); - assign FirstFrame = (FrameCount == 4'b0); - - // 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 ImplicitDelay1 = SckMode[0] ? 9'b0 : 9'b1; - assign ImplicitDelay2 = SckMode[0] ? 9'b1 : 9'b0; - - // Calculate when tx/rx shift registers are full/empty - - // Transmit Shift FSM - always_ff @(posedge PCLK) - if (~PRESETn) TransmitShiftEmpty <= 1'b1; - else if (TransmitShiftEmpty) begin - if (TransmitFIFOReadEmpty | (~TransmitFIFOReadEmpty & (ReceivePenultimateFrame & Active0))) TransmitShiftEmpty <= 1'b1; - else if (~TransmitFIFOReadEmpty) TransmitShiftEmpty <= 1'b0; - end else begin - if (ReceivePenultimateFrame & Active0) TransmitShiftEmpty <= 1'b1; - else TransmitShiftEmpty <= 1'b0; - end - - // Receive Shift FSM - always_ff @(posedge PCLK) - if (~PRESETn) ReceiveState <= ReceiveShiftNotFullState; - else if (SCLKenable) begin - case (ReceiveState) - ReceiveShiftFullState: ReceiveState <= ReceiveShiftNotFullState; - ReceiveShiftNotFullState: if (ReceivePenultimateFrame & (SampleEdge)) ReceiveState <= ReceiveShiftDelayState; - else ReceiveState <= ReceiveShiftNotFullState; - ReceiveShiftDelayState: ReceiveState <= ReceiveShiftFullState; - endcase - end - - assign ReceiveShiftFull = SckMode[0] ? (ReceiveState == ReceiveShiftFullState) : (ReceiveState == ReceiveShiftDelayState); - - // Calculate tx/rx fifo write and recieve increment signals - - always_ff @(posedge PCLK) - if (~PRESETn) TransmitFIFOWriteIncrement <= 1'b0; - else TransmitFIFOWriteIncrement <= (Memwrite & (Entry == SPI_TXDATA) & ~TransmitFIFOWriteFull); - - always_ff @(posedge PCLK) - if (~PRESETn) ReceiveFIFOReadIncrement <= 1'b0; - else ReceiveFIFOReadIncrement <= ((Entry == SPI_RXDATA) & ~ReceiveFIFOReadEmpty & PSEL & ~ReceiveFIFOReadIncrement); - - assign TransmitShiftRegLoad = ~TransmitShiftEmpty & ~Active | (((ChipSelectMode == 2'b10) & ~|(Delay1[15:8])) & ((ReceiveShiftFullDelay | ReceiveShiftFull) & ~SampleEdge & ~TransmitFIFOReadEmpty)); - - always_ff @(posedge PCLK) - if (~PRESETn) TransmitShiftRegLoadDelay <=0; - else if (SCLKenable) TransmitShiftRegLoadDelay <= TransmitShiftRegLoad; - assign TransmitShiftRegLoadSingleCycle = TransmitShiftRegLoad & ~TransmitShiftRegLoadDelay; - always_ff @(posedge PCLK) - if (~PRESETn) TransmitFIFOReadIncrement <= 0; - else if (SCLKenable) TransmitFIFOReadIncrement <= TransmitShiftRegLoadSingleCycle; - // Tx/Rx FIFOs - spi_fifo #(3,8) txFIFO(PCLK, 1'b1, SCLKenable, PRESETn, TransmitFIFOWriteIncrement, TransmitFIFOReadIncrement, TransmitData[7:0], TransmitWriteWatermarkLevel, TransmitWatermark[2:0], - TransmitFIFOReadData[7:0], TransmitFIFOWriteFull, TransmitFIFOReadEmpty, TransmitWriteMark, TransmitReadMark); - spi_fifo #(3,8) rxFIFO(PCLK, SCLKenable, 1'b1, PRESETn, ReceiveFiFoWriteInc, ReceiveFIFOReadIncrement, ReceiveShiftRegEndian, ReceiveWatermark[2:0], ReceiveReadWatermarkLevel, - ReceiveData[7:0], ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty, RecieveWriteMark, RecieveReadMark); - - always_ff @(posedge PCLK) - if (~PRESETn) TransmitFIFOReadEmptyDelay <= 1'b1; - else if (SCLKenable) TransmitFIFOReadEmptyDelay <= TransmitFIFOReadEmpty; - - always_ff @(posedge PCLK) - if (~PRESETn) ReceiveShiftFullDelay <= 1'b0; - else if (SCLKenable) ReceiveShiftFullDelay <= ReceiveShiftFull; - - assign ReceiveFiFoTakingData = ReceiveFiFoWriteInc & ~ReceiveFIFOWriteFull; + localparam SPI_SCKDIV = 8'h00; + localparam SPI_SCKMODE = 8'h04; + localparam SPI_CSID = 8'h10; + localparam SPI_CSDEF = 8'h14; + localparam SPI_CSMODE = 8'h18; + localparam SPI_DELAY0 = 8'h28; + localparam SPI_DELAY1 = 8'h2C; + localparam SPI_FMT = 8'h40; + localparam SPI_TXDATA = 8'h48; + localparam SPI_RXDATA = 8'h4C; + localparam SPI_TXMARK = 8'h50; + localparam SPI_RXMARK = 8'h54; + localparam SPI_IE = 8'h70; + localparam SPI_IP = 8'h74; - always_ff @(posedge PCLK) - if (~PRESETn) ReceiveFiFoWriteInc <= 1'b0; - else if (SCLKenable & ReceiveShiftFull) ReceiveFiFoWriteInc <= 1'b1; - else if (SCLKenable & ReceiveFiFoTakingData) ReceiveFiFoWriteInc <= 1'b0; - always_ff @(posedge PCLK) - if (~PRESETn) ReceiveShiftFullDelayPCLK <= 1'b0; - else if (SCLKenableEarly) ReceiveShiftFullDelayPCLK <= ReceiveShiftFull; + // SPI control registers. Refer to SiFive FU540-C000 manual + 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 [4:0] Format; + logic [7:0] ReceiveData; + logic [8:0] TransmitData; + logic [2:0] TransmitWatermark, ReceiveWatermark; + logic [1:0] InterruptEnable, InterruptPending; + // Bus interface signals + logic [7:0] Entry; + logic Memwrite; + logic [31:0] Din, Dout; + // SPI Controller signals + logic SCLKenable; + logic EndOfFrame; + logic EndOfFrameDelay; + logic Transmitting; + logic InactiveState; + logic [3:0] FrameLength; + logic ResetSCLKenable; + logic TransmitStart; + logic TransmitStartD; - // 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; + // Transmit Start State Machine Variables + typedef enum logic [1:0] {READY, START, WAIT} txState; + txState CurrState, NextState; + + // FIFO FSM signals + // Watermark signals - TransmitReadMark = ip[0], ReceiveWriteMark = ip[1] + logic TransmitWriteMark, TransmitReadMark, RecieveWriteMark, RecieveReadMark; + logic TransmitFIFOWriteFull, TransmitFIFOReadEmpty; + logic TransmitFIFOWriteIncrement; + logic [7:0] TransmitFIFOReadData; - always_ff @(posedge PCLK) - if (~PRESETn) begin - state <= CS_INACTIVE; - FrameCount <= 4'b0; - SPICLK <= SckMode[1]; - end else if (SCLKenable) begin + logic ReceiveFIFOWriteInc; + logic ReceiveFIFOReadIncrement; + logic ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty; + + /* verilator lint_off UNDRIVEN */ + logic [2:0] TransmitWriteWatermarkLevel, ReceiveReadWatermarkLevel; // unused generic FIFO outputs + /* verilator lint_off UNDRIVEN */ + logic [7:0] ReceiveShiftRegEndian; // Reverses ReceiveShiftReg if Format[2] set (little endian transmission) + + // Shift reg signals + logic ShiftEdge; // Determines which edge of sck to shift from TransmitReg + logic SampleEdge; // Determines which edge of sck to sample from ReceiveShiftReg + logic [7:0] TransmitReg; // Transmit shift register + logic [7:0] ReceiveShiftReg; // Receive shift register + logic [7:0] TransmitDataEndian; // Reverses TransmitData from txFIFO if littleendian, since TransmitReg always shifts MSB + logic TransmitLoad; // Determines when to load TransmitReg + logic TransmitFIFOReadIncrement; // Increments Tx FIFO read ptr 1 cycle after Tx FIFO is read + + // Shift stuff due to Format register? + logic ShiftIn; // Determines whether to shift from SPIIn or SPIOut (if SPI_LOOPBACK_TEST) + logic [3:0] LeftShiftAmount; // Determines left shift amount to left-align data when little endian + logic [7:0] ASR; // AlignedReceiveShiftReg + + // CS signals + logic [3:0] ChipSelectAuto; // Assigns ChipSelect value to selected CS signal based on CS ID + logic [3:0] ChipSelectInternal; // Defines what each ChipSelect signal should be based on transmission status and ChipSelectDef + + // APB access + assign Entry = {PADDR[7:2],2'b00}; // 32-bit word-aligned accesses + assign Memwrite = PWRITE & PENABLE & PSEL; // Only write in access phase + // assign PREADY = Entry == SPI_TXDATA | Entry == SPI_RXDATA | Entry == SPI_IP; + assign PREADY = 1'b1; + + // Account for subword read/write circuitry + // -- Note SPI registers are 32 bits no matter what; access them with LW SW. + + assign Din = PWDATA[31:0]; + if (P.XLEN == 64) assign PRDATA = { Dout, Dout}; + else assign PRDATA = Dout; + + // Register access + always_ff@(posedge PCLK) + if (~PRESETn) begin + SckDiv <= 12'd3; + SckMode <= 2'b0; + ChipSelectID <= 2'b0; + ChipSelectDef <= 4'b1111; + ChipSelectMode <= 2'b0; + Delay0 <= {8'b1,8'b1}; + Delay1 <= {8'b0,8'b1}; + Format <= {5'b10000}; + TransmitData <= 9'b0; + TransmitWatermark <= 3'b0; + ReceiveWatermark <= 3'b0; + InterruptEnable <= 2'b0; + InterruptPending <= 2'b0; + end else begin // writes /* verilator lint_off CASEINCOMPLETE */ - case (state) - CS_INACTIVE: begin - CS_SCKCount <= 9'b1; - SCK_CSCount <= 9'b10; - FrameCount <= 4'b0; - InterCSCount <= 9'b10; - InterXFRCount <= 9'b1; - if ((~TransmitFIFOReadEmpty | ~TransmitShiftEmpty) & ((|(Delay0[7:0])) | ~SckMode[0])) state <= DELAY_0; - else if ((~TransmitFIFOReadEmpty | ~TransmitShiftEmpty)) begin - state <= ACTIVE_0; - SPICLK <= ~SckMode[1]; - end else SPICLK <= SckMode[1]; - end - DELAY_0: begin - CS_SCKCount <= CS_SCKCount + 9'b1; - if (CS_SCKCount >= (({Delay0[7:0], 1'b0}) + ImplicitDelay1)) begin - state <= ACTIVE_0; - SPICLK <= ~SckMode[1]; - end - end - ACTIVE_0: begin - FrameCount <= FrameCount + 4'b1; - SPICLK <= SckMode[1]; - state <= ACTIVE_1; - end - ACTIVE_1: begin - InterXFRCount <= 9'b1; - if (FrameCount < Format[4:1]) begin - state <= ACTIVE_0; - SPICLK <= ~SckMode[1]; - end - else if ((ChipSelectMode[1:0] == 2'b10) & ~|(Delay1[15:8]) & (~TransmitFIFOReadEmpty)) begin - state <= ACTIVE_0; - SPICLK <= ~SckMode[1]; - CS_SCKCount <= 9'b1; - SCK_CSCount <= 9'b10; - FrameCount <= 4'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 - SCK_CSCount <= SCK_CSCount + 9'b1; - if (SCK_CSCount >= (({Delay0[15:8], 1'b0}) + ImplicitDelay2)) state <= INTER_CS; - end - INTER_CS: begin - InterCSCount <= InterCSCount + 9'b1; - SPICLK <= SckMode[1]; - if (InterCSCount >= ({Delay1[7:0],1'b0})) state <= CS_INACTIVE; - end - INTER_XFR: begin - CS_SCKCount <= 9'b1; - SCK_CSCount <= 9'b10; - FrameCount <= 4'b0; - InterCSCount <= 9'b10; - InterXFRCount <= InterXFRCount + 9'b1; - if ((InterXFRCount >= ({Delay1[15:8], 1'b0})) & (~TransmitFIFOReadEmptyDelay | ~TransmitShiftEmpty)) begin - state <= ACTIVE_0; - SPICLK <= ~SckMode[1]; - end else if (~|ChipSelectMode[1:0]) state <= CS_INACTIVE; - else SPICLK <= SckMode[1]; - end - endcase - /* verilator lint_off CASEINCOMPLETE */ - end - - - - assign DelayMode = SckMode[0] ? (state == DELAY_1) : (state == ACTIVE_1 & ReceiveShiftFull); - assign ChipSelectInternal = (state == CS_INACTIVE | state == INTER_CS | DelayMode & ~|(Delay0[15:8])) ? ChipSelectDef : ~ChipSelectDef; - assign 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) | ((state == ACTIVE_1) & ((ChipSelectMode[1:0] == 2'b10) & ~|(Delay1[15:8]) & (~TransmitFIFOReadEmpty) & (FrameCount == Format[4:1])))); - assign Active0 = (state == ACTIVE_0); - assign ShiftEdgeSPICLK = ZeroDiv ? ~SPICLK : SPICLK; - - // Signal tracks which edge of sck to shift data - always_comb - case(SckMode[1:0]) - 2'b00: ShiftEdge = ShiftEdgeSPICLK & SCLKenable; - 2'b01: ShiftEdge = (~ShiftEdgeSPICLK & ~FirstFrame & (|(FrameCount) | (CS_SCKCount >= (({Delay0[7:0], 1'b0}) + ImplicitDelay1))) & SCLKenable & (FrameCount != Format[4:1]) & ~TransmitInactive); - 2'b10: ShiftEdge = ~ShiftEdgeSPICLK & SCLKenable; - 2'b11: ShiftEdge = (ShiftEdgeSPICLK & ~FirstFrame & (|(FrameCount) | (CS_SCKCount >= (({Delay0[7:0], 1'b0}) + ImplicitDelay1))) & SCLKenable & (FrameCount != Format[4:1]) & ~TransmitInactive); - default: ShiftEdge = ShiftEdgeSPICLK & SCLKenable; + if (Memwrite) + case(Entry) // flop to sample inputs + SPI_SCKDIV: SckDiv <= Din[11:0]; + SPI_SCKMODE: SckMode <= Din[1:0]; + SPI_CSID: ChipSelectID <= Din[1:0]; + SPI_CSDEF: ChipSelectDef <= Din[3:0]; + SPI_CSMODE: ChipSelectMode <= Din[1:0]; + SPI_DELAY0: Delay0 <= {Din[23:16], Din[7:0]}; + SPI_DELAY1: Delay1 <= {Din[23:16], Din[7:0]}; + SPI_FMT: Format <= {Din[19:16], Din[2]}; + SPI_TXMARK: TransmitWatermark <= Din[2:0]; + SPI_RXMARK: ReceiveWatermark <= Din[2:0]; + SPI_IE: InterruptEnable <= Din[1:0]; endcase - // Transmit shift register - assign TransmitDataEndian = Format[0] ? {TransmitFIFOReadData[0], TransmitFIFOReadData[1], TransmitFIFOReadData[2], TransmitFIFOReadData[3], TransmitFIFOReadData[4], TransmitFIFOReadData[5], TransmitFIFOReadData[6], TransmitFIFOReadData[7]} : TransmitFIFOReadData[7:0]; - always_ff @(posedge PCLK) - if(~PRESETn) TransmitShiftReg <= 8'b0; - else if (TransmitShiftRegLoadSingleCycle) TransmitShiftReg <= TransmitDataEndian; - else if (ShiftEdge & Active) TransmitShiftReg <= {TransmitShiftReg[6:0], TransmitShiftReg[0]}; - - assign SPIOut = TransmitShiftReg[7]; - - // 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 - assign ShiftIn = P.SPI_LOOPBACK_TEST ? SPIOut : SPIIn; - - // Receive shift register - always_ff @(posedge PCLK) - if(~PRESETn) ReceiveShiftReg <= 8'b0; - else if (SampleEdge & SCLKenable) begin - if (~Active) ReceiveShiftReg <= 8'b0; - else ReceiveShiftReg <= {ReceiveShiftReg[6:0], ShiftIn}; - end - - // Aligns received data and reverses if little-endian - assign LeftShiftAmount = 4'h8 - Format[4:1]; - assign ASR = ReceiveShiftReg << LeftShiftAmount[2:0]; - assign ReceiveShiftRegEndian = Format[0] ? {ASR[0], ASR[1], ASR[2], ASR[3], ASR[4], ASR[5], ASR[6], ASR[7]} : ASR[7:0]; - - // Interrupt logic: raise interrupt if any enabled interrupts are pending - assign SPIIntr = |(InterruptPending & InterruptEnable); - - // Chip select logic - 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]}; + if (Memwrite) + case(Entry) + SPI_TXDATA: if (~TransmitFIFOWriteFull) TransmitData[7:0] <= Din[7:0]; endcase + /* verilator lint_off CASEINCOMPLETE */ + + // According to FU540 spec: Once interrupt is pending, it will remain set until number + // of entries in tx/rx fifo is strictly more/less than tx/rxmark + InterruptPending[0] <= TransmitReadMark; + InterruptPending[1] <= RecieveWriteMark; + + case(Entry) // Flop to sample inputs + SPI_SCKDIV: Dout <= {20'b0, SckDiv}; + SPI_SCKMODE: Dout <= {30'b0, SckMode}; + SPI_CSID: Dout <= {30'b0, ChipSelectID}; + SPI_CSDEF: Dout <= {28'b0, ChipSelectDef}; + SPI_CSMODE: Dout <= {30'b0, ChipSelectMode}; + SPI_DELAY0: Dout <= {8'b0, Delay0[15:8], 8'b0, Delay0[7:0]}; + SPI_DELAY1: Dout <= {8'b0, Delay1[15:8], 8'b0, Delay1[7:0]}; + SPI_FMT: Dout <= {12'b0, Format[4:1], 13'b0, Format[0], 2'b0}; + SPI_TXDATA: Dout <= {TransmitFIFOWriteFull, 23'b0, 8'b0}; + SPI_RXDATA: Dout <= {ReceiveFIFOReadEmpty, 23'b0, ReceiveData[7:0]}; + SPI_TXMARK: Dout <= {29'b0, TransmitWatermark}; + SPI_RXMARK: Dout <= {29'b0, ReceiveWatermark}; + SPI_IE: Dout <= {30'b0, InterruptEnable}; + SPI_IP: Dout <= {30'b0, InterruptPending}; + default: Dout <= 32'b0; + endcase + end - assign SPICS = ChipSelectMode[0] ? ChipSelectDef : ChipSelectAuto; + // SPI enable generation, where SCLK = PCLK/(2*(SckDiv + 1)) + // Asserts SCLKenable at the rising and falling edge of SCLK by counting from 0 to SckDiv + // Active at 2x SCLK frequency to account for implicit half cycle delays and actions on both clock edges depending on phase + // When SckDiv is 0, count doesn't work and SCLKenable is simply PCLK *** dh 10/26/24: this logic is seriously broken. SCLK is not scaled to PCLK/(2*(SckDiv + 1)). + + // SPI Controller module ------------------------------------------- + // This module controls state and timing signals that drive the rest of this module + assign ResetSCLKenable = Memwrite & (Entry == SPI_SCKDIV); + assign FrameLength = Format[4:1]; + + spi_controller controller(PCLK, PRESETn, + // Transmit Signals + TransmitStart, TransmitStartD, ResetSCLKenable, + // Register Inputs + SckDiv, SckMode, ChipSelectMode, Delay0, Delay1, FrameLength, + // txFIFO stuff + TransmitFIFOReadEmpty, + // Timing + SCLKenable, ShiftEdge, SampleEdge, EndOfFrame, EndOfFrameDelay, + // State stuff + Transmitting, InactiveState, + // Outputs + SPICLK); + + // Transmit FIFO --------------------------------------------------- + always_ff @(posedge PCLK) + if (~PRESETn) begin + TransmitFIFOWriteIncrement <= 1'b0; + end else begin + TransmitFIFOWriteIncrement <= (Memwrite & (Entry == SPI_TXDATA) & ~TransmitFIFOWriteFull); + end + + always_ff @(posedge PCLK) + if (~PRESETn) begin + TransmitFIFOReadIncrement <= 1'b0; + end else if (SCLKenable) begin + TransmitFIFOReadIncrement <= TransmitStartD | (EndOfFrameDelay & ~TransmitFIFOReadEmpty) ; + end + + // Check whether TransmitReg has been loaded. + // We use this signal to prevent returning to the Ready state for TransmitStart + logic TransmitRegLoaded; + always_ff @(posedge PCLK) begin + if (~PRESETn) begin + TransmitRegLoaded <= 1'b0; + end else if (TransmitLoad) begin + TransmitRegLoaded <= 1'b1; + end else if (ShiftEdge | EndOfFrameDelay) begin + TransmitRegLoaded <= 1'b0; + end + end + + // Setup TransmitStart state machine + always_ff @(posedge PCLK) begin + if (~PRESETn) begin + CurrState <= READY; + end else begin + CurrState <= NextState; + end + end + + // State machine for starting transmissions + always_comb begin + case (CurrState) + READY: if (~TransmitFIFOReadEmpty & ~Transmitting) NextState = START; + else NextState = READY; + START: NextState = WAIT; + WAIT: if (~Transmitting & ~TransmitRegLoaded) NextState = READY; + else NextState = WAIT; + default: NextState = READY; + endcase + end + + assign TransmitStart = (CurrState == START); + always_ff @(posedge PCLK) + if (~PRESETn) TransmitStartD <= 1'b0; + else if (TransmitStart) TransmitStartD <= 1'b1; + else if (SCLKenable) TransmitStartD <= 1'b0; + + spi_fifo #(3,8) txFIFO(PCLK, 1'b1, SCLKenable, PRESETn, + TransmitFIFOWriteIncrement, TransmitFIFOReadIncrement, + TransmitData[7:0], + TransmitWriteWatermarkLevel, TransmitWatermark[2:0], + TransmitFIFOReadData[7:0], + TransmitFIFOWriteFull, + TransmitFIFOReadEmpty, + TransmitWriteMark, TransmitReadMark); + + + // Receive FIFO ---------------------------------------------------- + always_ff @(posedge PCLK) + if (~PRESETn) begin + ReceiveFIFOReadIncrement <= 1'b0; + end else begin + ReceiveFIFOReadIncrement <= ((Entry == SPI_RXDATA) & ~ReceiveFIFOReadEmpty & PSEL & ~ReceiveFIFOReadIncrement); + end + + always_ff @(posedge PCLK) + if (~PRESETn) begin + ReceiveFIFOWriteInc <= 1'b0; + end else if (SCLKenable) begin + ReceiveFIFOWriteInc <= EndOfFrameDelay; + end + + spi_fifo #(3,8) rxFIFO(PCLK, SCLKenable, 1'b1, PRESETn, + ReceiveFIFOWriteInc, ReceiveFIFOReadIncrement, + ReceiveShiftRegEndian, ReceiveWatermark[2:0], + ReceiveReadWatermarkLevel, + ReceiveData[7:0], + ReceiveFIFOWriteFull, + ReceiveFIFOReadEmpty, + RecieveWriteMark, RecieveReadMark); + + // Transmit shift register + assign TransmitLoad = TransmitStart | (EndOfFrameDelay & ~TransmitFIFOReadEmpty); + assign TransmitDataEndian = Format[0] ? {<<{TransmitFIFOReadData[7:0]}} : TransmitFIFOReadData[7:0]; + always_ff @(posedge PCLK) + if(~PRESETn) TransmitReg <= 8'b0; + else if (TransmitLoad) TransmitReg <= TransmitDataEndian; + else if (ShiftEdge) TransmitReg <= {TransmitReg[6:0], TransmitReg[0]}; + + assign SPIOut = TransmitReg[7]; + + // 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 + assign ShiftIn = P.SPI_LOOPBACK_TEST ? SPIOut : SPIIn; + + // Receive shift register + always_ff @(posedge PCLK) + if(~PRESETn) begin + ReceiveShiftReg <= 8'b0; + end else if (SampleEdge) begin + if (~Transmitting) ReceiveShiftReg <= 8'b0; + else ReceiveShiftReg <= {ReceiveShiftReg[6:0], ShiftIn}; + end + + // Aligns received data and reverses if little-endian + assign LeftShiftAmount = 4'h8 - Format[4:1]; + assign ASR = ReceiveShiftReg << LeftShiftAmount[2:0]; + assign ReceiveShiftRegEndian = Format[0] ? {<<{ASR[7:0]}} : ASR[7:0]; + + // Interrupt logic: raise interrupt if any enabled interrupts are pending + assign SPIIntr = |(InterruptPending & InterruptEnable); + + // Chip select logic + assign ChipSelectInternal = InactiveState ? ChipSelectDef : ~ChipSelectDef; + 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 diff --git a/src/uncore/spi_controller.sv b/src/uncore/spi_controller.sv index c4305047e..19b32cab3 100644 --- a/src/uncore/spi_controller.sv +++ b/src/uncore/spi_controller.sv @@ -1,9 +1,8 @@ /////////////////////////////////////////// // spi_controller.sv // -// Written: jacobpease@protonmail.com +// Written: Jacob Pease jacobpease@protonmail.com // Created: October 28th, 2024 -// Modified: // // Purpose: Controller logic for SPI // @@ -12,7 +11,7 @@ // A component of the CORE-V-WALLY configurable RISC-V project. // https://github.com/openhwgroup/cvw // -// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University +// Copyright (C) 2021-24 Harvey Mudd College & Oklahoma State University // // SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 // @@ -28,21 +27,35 @@ // and limitations under the License. //////////////////////////////////////////////////////////////////////////////////////////////// - -module spi_controller ( +module spi_controller ( input logic PCLK, input logic PRESETn, + + // Start Transmission input logic TransmitStart, + input logic TransmitStartD, + input logic ResetSCLKenable, + + // Registers input logic [11:0] SckDiv, input logic [1:0] SckMode, input logic [1:0] CSMode, - input logic [15:0] Delay0, - input logic [15:0] Delay1, - input logic [7:0] txFIFORead, + input logic [15:0] Delay0, + input logic [15:0] Delay1, + input logic [3:0] FrameLength, + + // Is the Transmit FIFO Empty? input logic txFIFOReadEmpty, - output logic SPICLK, - output logic SPIOUT, - output logic CS + + // Control signals + output logic SCLKenable, + output logic ShiftEdge, + output logic SampleEdge, + output logic EndOfFrame, + output logic EndOfFrameDelay, + output logic Transmitting, + output logic InactiveState, + output logic SPICLK ); // CSMode Stuff @@ -55,36 +68,35 @@ module spi_controller ( // SCLKenable stuff logic [11:0] DivCounter; - logic SCLKenable; - logic SCLKenableEarly; - logic SCLKenableLate; - logic EdgeTiming; + // logic SCLKenable; + // logic SCLKenableEarly; logic ZeroDiv; - logic Clock0; - logic Clock1; logic SCK; // SUPER IMPORTANT, THIS CAN'T BE THE SAME AS SPICLK! // Shift and Sample Edges logic PreShiftEdge; logic PreSampleEdge; - logic ShiftEdge; - logic SampleEdge; + // logic ShiftEdge; + // logic SampleEdge; + logic ShiftEdgePulse; + logic SampleEdgePulse; + logic EndOfFramePulse; // Frame stuff - logic [2:0] BitNum; + logic [3:0] BitNum; logic LastBit; - logic EndOfFrame; - logic EndOfFrameDelay; + //logic EndOfFrame; + //logic EndOfFrameDelay; logic PhaseOneOffset; // Transmit Stuff logic ContinueTransmit; // SPIOUT Stuff - logic TransmitLoad; + // logic TransmitLoad; logic [7:0] TransmitReg; - logic Transmitting; + //logic Transmitting; logic EndTransmission; logic HoldMode; @@ -135,15 +147,12 @@ module spi_controller ( // SampleEdge. This makes sure that SPICLK is an output of a register // and it properly synchronizes signals. - assign SCLKenableLate = DivCounter > SckDiv; assign SCLKenable = DivCounter == SckDiv; - assign SCLKenableEarly = (DivCounter + 1'b1) == SckDiv; - assign LastBit = BitNum == 3'd7; - assign EdgeTiming = SckDiv > 12'b0 ? SCLKenableEarly : SCLKenable; + // assign SCLKenableEarly = (DivCounter + 1'b1) == SckDiv; + assign LastBit = (BitNum == FrameLength - 4'b1); - //assign SPICLK = Clock0; - - assign ContinueTransmit = ~txFIFOReadEmpty & EndOfFrame; + //assign EndOfFrame = SCLKenable & LastBit & Transmitting; + assign ContinueTransmit = ~txFIFOReadEmpty & EndOfFrameDelay; assign EndTransmission = txFIFOReadEmpty & EndOfFrameDelay; always_ff @(posedge PCLK) begin @@ -151,10 +160,14 @@ module spi_controller ( DivCounter <= 12'b0; SPICLK <= SckMode[1]; SCK <= 0; - BitNum <= 3'h0; + BitNum <= 4'h0; PreShiftEdge <= 0; PreSampleEdge <= 0; EndOfFrame <= 0; + CSSCKCounter <= 0; + SCKCSCounter <= 0; + INTERCSCounter <= 0; + INTERXFRCounter <= 0; end else begin // TODO: Consolidate into one delay counter since none of the // delays happen at the same time? @@ -164,27 +177,27 @@ module spi_controller ( SCK <= ~SCK; end - if ((CurrState == CSSCK) & SCK) begin + if ((CurrState == CSSCK) & SCK & SCLKenable) begin CSSCKCounter <= CSSCKCounter + 8'd1; - end else begin + end else if (SCLKenable & EndOfCSSCK) begin CSSCKCounter <= 8'd0; end - if ((CurrState == SCKCS) & SCK) begin + if ((CurrState == SCKCS) & SCK & SCLKenable) begin SCKCSCounter <= SCKCSCounter + 8'd1; - end else begin + end else if (SCLKenable & EndOfSCKCS) begin SCKCSCounter <= 8'd0; end - if ((CurrState == INTERCS) & SCK) begin + if ((CurrState == INTERCS) & SCK & SCLKenable) begin INTERCSCounter <= INTERCSCounter + 8'd1; - end else begin + end else if (SCLKenable & EndOfINTERCS) begin INTERCSCounter <= 8'd0; end - if ((CurrState == INTERXFR) & SCK) begin + if ((CurrState == INTERXFR) & SCK & SCLKenable) begin INTERXFRCounter <= INTERXFRCounter + 8'd1; - end else begin + end else if (SCLKenable & EndOfINTERXFR) begin INTERXFRCounter <= 8'd0; end @@ -196,10 +209,10 @@ module spi_controller ( end // Reset divider - if (SCLKenable | TransmitStart) begin + if (SCLKenable | TransmitStart | ResetSCLKenable) begin DivCounter <= 12'b0; end else begin - DivCounter = DivCounter + 12'd1; + DivCounter <= DivCounter + 12'd1; end // EndOfFrame controller @@ -209,15 +222,16 @@ module spi_controller ( // EndOfFrame <= 1'b0; // end + // TODO: Rename EndOfFrameDelay to EndOfFrame and remove this logic if (~TransmitStart) begin EndOfFrame <= (SckMode[1] ^ SckMode[0] ^ SPICLK) & SCLKenable & LastBit & Transmitting; end // Increment BitNum if (ShiftEdge & Transmitting) begin - BitNum <= BitNum + 3'd1; + BitNum <= BitNum + 4'd1; end else if (EndOfFrameDelay) begin - BitNum <= 3'b0; + BitNum <= 4'b0; end end end @@ -225,26 +239,71 @@ module spi_controller ( // Delay ShiftEdge and SampleEdge by a half PCLK period // Aligned EXACTLY ON THE MIDDLE of the leading and trailing edges. // Sweeeeeeeeeet... + + assign ShiftEdgePulse = SCLKenable & ~LastBit & Transmitting; + assign SampleEdgePulse = SCLKenable & Transmitting & ~DelayIsNext; + assign EndOfFramePulse = SCLKenable & LastBit & Transmitting; + always_ff @(posedge ~PCLK) begin if (~PRESETn | TransmitStart) begin ShiftEdge <= 0; PhaseOneOffset <= 0; SampleEdge <= 0; EndOfFrameDelay <= 0; - end else begin - ShiftEdge <= ((SckMode[1] ^ SckMode[0] ^ SPICLK) & SCLKenable & ~LastBit & Transmitting) & PhaseOneOffset; - PhaseOneOffset <= PhaseOneOffset == 0 ? Transmitting & SCLKenable : PhaseOneOffset; - SampleEdge <= (SckMode[1] ^ SckMode[0] ^ ~SPICLK) & SCLKenable & Transmitting; - EndOfFrameDelay <= (SckMode[1] ^ SckMode[0] ^ SPICLK) & SCLKenable & LastBit & Transmitting; + end else begin + PhaseOneOffset <= (PhaseOneOffset == 0) ? Transmitting & SCLKenable : ~EndOfFrameDelay; + case(SckMode) + 2'b00: begin + ShiftEdge <= SPICLK & ShiftEdgePulse; + SampleEdge <= ~SPICLK & SampleEdgePulse; + EndOfFrameDelay <= SPICLK & EndOfFramePulse; + end + 2'b01: begin + ShiftEdge <= ~SPICLK & ShiftEdgePulse & PhaseOneOffset; + SampleEdge <= SPICLK & SampleEdgePulse; + EndOfFrameDelay <= ~SPICLK & EndOfFramePulse; + end + 2'b10: begin + ShiftEdge <= ~SPICLK & ShiftEdgePulse; + SampleEdge <= SPICLK & SampleEdgePulse; + EndOfFrameDelay <= ~SPICLK & EndOfFramePulse; + end + 2'b11: begin + ShiftEdge <= SPICLK & ShiftEdgePulse & PhaseOneOffset; + SampleEdge <= ~SPICLK & SampleEdgePulse; + EndOfFrameDelay <= SPICLK & EndOfFramePulse; + end + // ShiftEdge <= ((SckMode[1] ^ SckMode[0] ^ SPICLK) & SCLKenable & ~LastBit & Transmitting) & PhaseOneOffset; + // PhaseOneOffset <= PhaseOneOffset == 0 ? Transmitting & SCLKenable : ~EndOfFrameDelay; + // SampleEdge <= (SckMode[1] ^ SckMode[0] ^ ~SPICLK) & SCLKenable & Transmitting & ~DelayIsNext; + // EndOfFrameDelay <= (SckMode[1] ^ SckMode[0] ^ SPICLK) & SCLKenable & LastBit & Transmitting; + endcase end end // typedef enum logic [2:0] {INACTIVE, CSSCK, TRANSMIT, SCKCS, HOLD, INTERCS, INTERXFR} statetype; // statetype CurrState, NextState; - assign HoldMode = CSMode == 2'b10; - assign TransmitLoad = TransmitStart | (EndOfFrameDelay & ~txFIFOReadEmpty); + assign HoldMode = CSMode == HOLDMODE; + // assign TransmitLoad = TransmitStart | (EndOfFrameDelay & ~txFIFOReadEmpty); + logic ContinueTransmitD; + logic NextEndDelay; + logic CurrentEndDelay; + + assign NextEndDelay = NextState == SCKCS | NextState == INTERCS | NextState == INTERXFR; + assign CurrentEndDelay = CurrState == SCKCS | CurrState == INTERCS | CurrState == INTERXFR; + + always_ff @(posedge PCLK) begin + if (~PRESETn) begin + ContinueTransmitD <= 1'b0; + end else if (NextEndDelay & ~CurrentEndDelay) begin + ContinueTransmitD <= ContinueTransmit; + end else if (EndOfSCKCS & SCLKenable) begin + ContinueTransmitD <= 1'b0; + end + end + always_ff @(posedge PCLK) begin if (~PRESETn) begin CurrState <= INACTIVE; @@ -255,71 +314,68 @@ module spi_controller ( always_comb begin case (CurrState) - INACTIVE: begin // INACTIVE case -------------------------------- - if (TransmitStart) begin - if (~HasCSSCK) begin - NextState = TRANSMIT; - end else begin - NextState = CSSCK; - end - end else begin - NextState = INACTIVE; - end - end - CSSCK: begin // DELAY0 case ------------------------------------- - if (EndOfCSSCK) begin - NextState = TRANSMIT; - end - end + INACTIVE: if (TransmitStartD) begin + if (~HasCSSCK) NextState = TRANSMIT; + else NextState = CSSCK; + end else begin + NextState = INACTIVE; + end + CSSCK: if (EndOfCSSCK) NextState = TRANSMIT; + else NextState = CSSCK; TRANSMIT: begin // TRANSMIT case -------------------------------- case(CSMode) AUTOMODE: begin - if (EndTransmission) begin - NextState = INACTIVE; - end else if (ContinueTransmit) begin - NextState = SCKCS; - end + if (EndTransmission) NextState = INACTIVE; + else if (EndOfFrameDelay) NextState = SCKCS; + else NextState = TRANSMIT; end HOLDMODE: begin - if (EndTransmission) begin - NextState = HOLD; - end else if (ContinueTransmit) begin - if (HasINTERXFR) NextState = INTERXFR; - end + if (EndTransmission) NextState = HOLD; + else if (ContinueTransmit & HasINTERXFR) NextState = INTERXFR; + else NextState = TRANSMIT; end OFFMODE: begin - + if (EndTransmission) NextState = INACTIVE; + else if (ContinueTransmit & HasINTERXFR) NextState = INTERXFR; + else NextState = TRANSMIT; end - + default: NextState = TRANSMIT; endcase end SCKCS: begin // SCKCS case -------------------------------------- if (EndOfSCKCS) begin - if (EndTransmission) begin - if (CSMode == AUTOMODE) NextState = INACTIVE; - else if (CSMode == HOLDMODE) NextState = HOLD; - end else if (ContinueTransmit) begin + if (~ContinueTransmitD) begin + // if (CSMode == AUTOMODE) NextState = INACTIVE; + if (CSMode == HOLDMODE) NextState = HOLD; + else NextState = INACTIVE; + end else begin if (HasINTERCS) NextState = INTERCS; else NextState = TRANSMIT; end + end else begin + NextState = SCKCS; end end HOLD: begin // HOLD mode case ----------------------------------- if (CSMode == AUTOMODE) begin NextState = INACTIVE; - end else if (TransmitStart) begin // If FIFO is written to, start again. + end else if (TransmitStartD) begin // If FIFO is written to, start again. NextState = TRANSMIT; - end + end else NextState = HOLD; end INTERCS: begin // INTERCS case ---------------------------------- if (EndOfINTERCS) begin if (HasCSSCK) NextState = CSSCK; else NextState = TRANSMIT; + end else begin + NextState = INTERCS; end end INTERXFR: begin // INTERXFR case -------------------------------- if (EndOfINTERXFR) begin NextState = TRANSMIT; + end else begin + NextState = INTERXFR; end end default: begin @@ -330,19 +386,6 @@ module spi_controller ( assign Transmitting = CurrState == TRANSMIT; assign DelayIsNext = (NextState == CSSCK | NextState == SCKCS | NextState == INTERCS | NextState == INTERXFR); - - // - always_ff @(posedge PCLK) begin - if (~PRESETn) begin - TransmitReg <= 8'b0; - end else if (TransmitLoad) begin - TransmitReg <= txFIFORead; - end else if (ShiftEdge) begin - TransmitReg <= {TransmitReg[6:0], TransmitReg[0]}; - end - end - - assign SPIOUT = TransmitReg[7]; - assign CS = CurrState == INACTIVE | CurrState == INTERCS; + assign InactiveState = CurrState == INACTIVE | CurrState == INTERCS; endmodule diff --git a/testbench/tests.vh b/testbench/tests.vh index bef41ef22..2b8d3a2ec 100644 --- a/testbench/tests.vh +++ b/testbench/tests.vh @@ -72,7 +72,8 @@ string coverage64gc[] = '{ "pmpcfg2", "pmppriority", "pmpcbo", - "pmpadrdecs" + "pmpadrdecs", + "btbthrash" }; string buildroot[] = '{ diff --git a/tests/coverage/btbthrash.S b/tests/coverage/btbthrash.S new file mode 100644 index 000000000..8fedf372a --- /dev/null +++ b/tests/coverage/btbthrash.S @@ -0,0 +1,145 @@ +/////////////////////////////////////////// +// btbtrash.S +// +// Written: Rose Thompson rose@rosethompson.net 23 October 2024 +// +// Purpose: Test the branch target buffer alias with divide and cache pipeline stalls +// +// A component of the CORE-V-WALLY configurable RISC-V project. +// https://github.com/openhwgroup/cvw +// +// 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. +//////////////////////////////////////////////////////////////////////////////////////////////// + +// load code to initalize stack, handle interrupts, terminate +#include "WALLY-init-lib.h" + +main: + + # Division test (having trouble with buildroot) + li x1, 1938759018 + li x2, 3745029 + li x3, 458 + li x4, 29587209347 + li x5, 28957 + li x6, 298 + li x7, 238562 + li x8, 198674 + li x9, 134 + li x10, 906732 + li x11, 29 + li x12, 50912 + li x13, 59 + li x14, 6902385 + li x15, 1923857 + li x16, 3985 + li x17, 3947 + li x18, 15984 + li x19, 5 + li x20, 9684658489 + li x21, 6548 + li x22, 3564 + li x23, 94 + li x24, 689464 + li x25, 42567 + li x26, 98453 + li x27, 648 + li x28, 984 + li x29, 6984 + li x30, 864 + + # x31 will be our loop counter + li x31, 4 + +.align 12 +jump1: + divuw x0, x1, x2 + j jump3 +jump4: + divuw x0, x5, x6 + j jump5 +jump6: + divuw x0, x10, x9 + j jump7 +jump8: + divuw x0, x14, x3 + j jump9 +jump10: + divuw x0, x18, x17 + j jump11 +jump12: + divuw x0, x21, x22 + j jump13 +jump14: + divuw x0, x24, x25 + j jump15 +jump16: + divuw x0, x29, x28 + j jump17 +jump18: + divuw x0, x1, x30 + j jump19 +jump20: + divuw x0, x3, x19 + j jump21 +jump22: + divuw x0, x12, x13 + j jump23 + +.align 12 # size of the 1024 btb apart +jump2: + j jump1 +jump3: + divuw x0, x4, x3 + j jump4 +jump5: + divuw x0, x7, x8 + j jump6 +jump7: + divuw x0, x12, x11 + j jump8 +jump9: + divuw x0, x15, x16 + j jump10 +jump11: + divuw x0, x20, x19 + j jump12 +jump13: + divuw x0, x24, x23 + j jump14 +jump15: + divuw x0, x26, x27 + j jump16 +jump17: + divuw x0, x29, x30 + j jump18 +jump19: + divuw x0, x2, x3 + j jump20 +jump21: + divuw x0, x4, x5 + j jump22 +jump23: + divuw x0, x20, x21 + #j jump22 + + fence.i + + addi x31, x31, -1 + bne x31, x0, jump1 +finsihed: + j done + diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/references/WALLY-spi-01.reference_output b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/references/WALLY-spi-01.reference_output index 425866ac2..027e02f54 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/references/WALLY-spi-01.reference_output +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/references/WALLY-spi-01.reference_output @@ -238,46 +238,6 @@ 0000001F -00000062 # hardware interlock - -00000026 - -000000D2 - -0000002D - -00000048 - -00000037 - -00000026 - -00000015 - -00000084 - -00000073 - -00000062 - -00000051 - -00000046 - -00000035 - -00000024 - -00000013 - -00000064 - -00000053 - -00000042 - -00000031 - 00000001 #watermark interrupts 00000000 #read mip diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-spi-01.S b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-spi-01.S index 4048c4c4c..94defaf87 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-spi-01.S +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-spi-01.S @@ -547,108 +547,13 @@ test_cases: #.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end #.4byte rx_data, 0x000000F0, read32_test # read rx_data -#=========== Test Hardware Interlock ================ - -# interlock in base case - -.4byte fmt, 0x00080000, write32_test # reset fmt register -.4byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock -.4byte tx_data, 0x00000062, write32_test # initiate transmission -.4byte sck_mode, 0x00000002, write32_test # flip polarity during transmission -.4byte tx_data, 0x00000026, write32_test # transmit second frame w/ control register updated -.4byte 0x0, 0x00000001, spi_data_wait -.4byte rx_data, 0x00000062, read32_test -.4byte rx_data, 0x00000026, read32_test # clear rx fifo -.4byte sck_mode, 0x00000000, write32_test # reset polarity - -# interlock in case where cs_mode is auto, but there is minimal intercs delay - -.4byte delay0, 0x00000001, write32_test # set sck-cs delay to 0, with sck.pha 0 there is 0 delay -.4byte tx_data, 0x000000D2, write32_test # initiate transmission -.4byte sck_mode, 0x00000002, write32_test # flip sck polarity -.4byte tx_data, 0x0000002D, write32_test # transmit second frame -.4byte 0x0, 0x00000001, spi_data_wait -.4byte rx_data, 0x000000D2, read32_test -.4byte rx_data, 0x0000002D, read32_test # clear rx fifo -.4byte sck_mode, 0x00000000, write32_test # reset polarity - -# interlock in case where cs_mode = hold, 0 intercs delay -.4byte delay0, 0x00010001, write32_test # reset delay0 -.4byte sck_mode, 0x00000000, write32_test # reset polarity -.4byte cs_mode, 0x00000002, write32_test # set cs_mode to hold -.4byte tx_data, 0x15263748, spi_burst_send # place 4 frames into tx fifo -.4byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame) -.4byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end -.4byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock -.4byte sck_mode, 0x00000000, write32_test # flip polarity again -.4byte 0x0, 0x00000003, spi_data_wait # wait for final frame -.4byte rx_data, 0x00000048, read32_test -.4byte rx_data, 0x00000037, read32_test -.4byte rx_data, 0x00000026, read32_test -.4byte rx_data, 0x00000015, read32_test #clear rx fifo - -# interlock in case where cs_mode = hold, intercs delay - -.4byte sck_mode, 0x00000000, write32_test # reset polarity -.4byte delay1, 0x00010001, write32_test # set intercs delay to 1 -.4byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock -.4byte tx_data, 0x51627384, spi_burst_send # place 4 frames into tx fifo -.4byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame) -.4byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end -.4byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock -.4byte sck_mode, 0x00000000, write32_test # flip polarity again -.4byte 0x0, 0x00000003, spi_data_wait # wait for final frame -.4byte rx_data, 0x00000084, read32_test -.4byte rx_data, 0x00000073, read32_test -.4byte rx_data, 0x00000062, read32_test -.4byte rx_data, 0x00000051, read32_test #clear rx fifo - -# repeat previous set of tests with cs_mode = off - -.4byte cs_mode, 0x00000003, write32_test # set cs_mode to hold -.4byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock -.4byte tx_data, 0x13243546, spi_burst_send # place 4 frames into tx fifo -.4byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame) -.4byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end -.4byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock -.4byte sck_mode, 0x00000000, write32_test # flip polarity again -.4byte 0x0, 0x00000003, spi_data_wait # wait for final frame -.4byte rx_data, 0x00000046, read32_test -.4byte rx_data, 0x00000035, read32_test -.4byte rx_data, 0x00000024, read32_test -.4byte rx_data, 0x00000013, read32_test #clear rx fifo - -# interlock in case where cs_mode = hold, intercs delay - -.4byte sck_mode, 0x00000000, write32_test # reset polarity -.4byte delay1, 0x00000000, write32_test # set intercs delay to 0 -.4byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock -.4byte tx_data, 0x31425364, spi_burst_send # place 4 frames into tx fifo -.4byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame) -.4byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end -.4byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock -.4byte sck_mode, 0x00000000, write32_test # flip polarity again -.4byte 0x0, 0x00000003, spi_data_wait # wait for final frame -.4byte rx_data, 0x00000064, read32_test -.4byte rx_data, 0x00000053, read32_test -.4byte rx_data, 0x00000042, read32_test -.4byte 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 - +.4byte fmt, 0x00080000, write32_test # reset format register .4byte delay1, 0x0000001, write32_test # reset delay1 register .4byte cs_mode, 0x00000000, write32_test # reset cs_mode .4byte tx_mark, 0x00000001, write32_test # set transmit watermark to 1 (any entry turns mark off) 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 7520479ce..8d9ae8bbc 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 @@ -238,46 +238,6 @@ 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 2a04f02f0..23cfd169a 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 @@ -551,94 +551,6 @@ 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 - - @@ -652,7 +564,7 @@ test_cases: # Test transmit watermark interrupt (triggers when entries in tx FIFO < tx watermark) without external enables SETUP_PLIC - +.8byte fmt, 0x00080000, write32_test # reset format register .8byte delay1, 0x0000001, write32_test # reset delay1 register .8byte cs_mode, 0x00000000, write32_test # reset cs_mode .8byte sck_div, 0x00000100, write32_test # lower SPI clock rate so reads are done at correct time when ICACHE not supported