Merge branch 'main' of https://github.com/openhwgroup/cvw into fetch_buffer

This commit is contained in:
Jordan Carlin 2024-11-03 16:17:34 -08:00
commit 250a8f2f5e
No known key found for this signature in database
22 changed files with 794 additions and 833 deletions

3
.gitmodules vendored
View File

@ -25,9 +25,10 @@
sparseCheckout = true sparseCheckout = true
path = addins/verilog-ethernet path = addins/verilog-ethernet
url = https://github.com/rosethompson/verilog-ethernet.git url = https://github.com/rosethompson/verilog-ethernet.git
[submodule "cvw-arch-verif"] [submodule "addins/cvw-arch-verif"]
path = addins/cvw-arch-verif path = addins/cvw-arch-verif
url = https://github.com/openhwgroup/cvw-arch-verif url = https://github.com/openhwgroup/cvw-arch-verif
ignore = dirty
[submodule "addins/riscvISACOV"] [submodule "addins/riscvISACOV"]
path = addins/riscvISACOV path = addins/riscvISACOV
url = https://github.com/riscv-verification/riscvISACOV.git url = https://github.com/riscv-verification/riscvISACOV.git

@ -1 +1 @@
Subproject commit bbcba78647080dee82e96bc1b8ff9cd9a3cf7fa1 Subproject commit 6d658b7b42c83fd584008d72964cc75d0876b769

@ -1 +1 @@
Subproject commit ce04b4930545ae4c81e2f3b6f6935e2aac08679e Subproject commit 3843c736e427a2b52a0d06e6220b073afa4be401

View File

@ -10,6 +10,9 @@
`include "RV32M_coverage.svh" `include "RV32M_coverage.svh"
`include "RV32F_coverage.svh" `include "RV32F_coverage.svh"
`include "RV32D_coverage.svh" `include "RV32D_coverage.svh"
`include "RV32ZfaF_coverage.svh"
`include "RV32ZfaD_coverage.svh"
`include "RV32ZfaZfh_coverage.svh"
`include "RV32ZfhD_coverage.svh" `include "RV32ZfhD_coverage.svh"
`include "RV32Zfh_coverage.svh" `include "RV32Zfh_coverage.svh"
`include "RV32Zicond_coverage.svh" `include "RV32Zicond_coverage.svh"
@ -22,3 +25,5 @@
// Privileged extensions // Privileged extensions
`include "ZicsrM_coverage.svh" `include "ZicsrM_coverage.svh"
`include "RV32VM_coverage.svh"
`include "RV32VM_PMP_coverage.svh"

View File

@ -10,6 +10,9 @@
`include "RV64M_coverage.svh" `include "RV64M_coverage.svh"
`include "RV64F_coverage.svh" `include "RV64F_coverage.svh"
`include "RV64D_coverage.svh" `include "RV64D_coverage.svh"
`include "RV64ZfaF_coverage.svh"
`include "RV32ZfaD_coverage.svh"
`include "RV32ZfaZfh_coverage.svh"
`include "RV64ZfhD_coverage.svh" `include "RV64ZfhD_coverage.svh"
`include "RV64Zfh_coverage.svh" `include "RV64Zfh_coverage.svh"
`include "RV64Zicond_coverage.svh" `include "RV64Zicond_coverage.svh"

View File

@ -5,3 +5,22 @@ wally/wallypipelinedcore.sv: logic InstrM
lsu/lsu.sv: logic IEUAdrM lsu/lsu.sv: logic IEUAdrM
lsu/lsu.sv: logic MemRWM lsu/lsu.sv: logic MemRWM
mmu/hptw.sv: logic SATP_REGW 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

View File

@ -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] 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} ]] 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. # 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 default_100mhz_clk]
connect_debug_port dbg_hub/clk [get_nets CPUCLK] connect_debug_port dbg_hub/clk [get_nets CPUCLK]

View File

@ -69,8 +69,8 @@ PreProcessFiles:
./insert_debug_comment.sh ./insert_debug_comment.sh
# This line allows the Bootloader to be loaded in a Block RAM on the FPGA # 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/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/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/ram1p1rwbe.sv
# build the Zero stage boot loader (ZSBL) # build the Zero stage boot loader (ZSBL)
.PHONY: zsbl .PHONY: zsbl

View File

@ -102,7 +102,8 @@ if {$board=="ArtyA7"} {
} else { } else {
#source ../constraints/vcu-small-debug.xdc #source ../constraints/vcu-small-debug.xdc
#source ../constraints/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
} }

View File

@ -135,45 +135,45 @@ int disk_read(BYTE * buf, LBA_t sector, UINT count) {
/* crc = crc16(crc, x); */ /* crc = crc16(crc, x); */
/* } while (--n > 0); */ /* } while (--n > 0); */
/* n = 512/8; */ n = 512/8;
/* do { */ do {
/* // Send 8 dummy bytes (fifo should be empty) */ // 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++) { for (j = 0; j < 8; j++) {
spi_sendbyte(0xff); spi_sendbyte(0xff);
} }
// Reset counter. Process bytes AS THEY COME IN.
while (n > 0) { for (j = 0; j < 8; j++) {
// Wait for bytes to be received
while (!(read_reg(SPI_IP) & 2)) {} while (!(read_reg(SPI_IP) & 2)) {}
// Read byte
uint8_t x = spi_readbyte(); uint8_t x = spi_readbyte();
// Send another dummy byte
if (n > 8) {
spi_sendbyte(0xff);
}
// Place received byte into memory
*p++ = x; *p++ = x;
// Update CRC16 with fast table based method // crc = crc16(crc, x);
crc = ((crc << 8) ^ crctable[x ^ (crc >> 8)]) & 0xffff; crc = ((crc << 8) ^ crctable[x ^ (crc >> 8)]) & 0xffff;
n = n - 1;
} }
} 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 // Read CRC16 and check
crc_exp = ((uint16_t)spi_dummy() << 8); crc_exp = ((uint16_t)spi_dummy() << 8);

View File

@ -1,4 +1,30 @@
#!/bin/bash #!/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) # Exit on any error (return code != 0)
# set -e # set -e

80
linux/sdcard/write-bytes.sh Executable file
View File

@ -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 <path/to/buildroot>] <device>" 1>&2; exit 1; }
help() {
echo "Usage: $0 [OPTIONS] <device>"
echo " -i Input text file with hex bytes."
echo " -b <path/to/buildroot> 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"

View File

@ -181,7 +181,7 @@ if {$DEBUG > 0} {
# suppress spurious warnngs about # suppress spurious warnngs about
# "Extra checking for conflicts with always_comb done at vopt time" # "Extra checking for conflicts with always_comb done at vopt time"
# because vsim will run vopt # 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" 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 vlog -permissive -lint -work ${WKDIR} {*}${INC_DIRS} {*}${FCvlog} {*}${FCdefineCOVER_EXTS} {*}${lockstepvlog} {*}${SOURCES} -suppress 2282,2583,7053,7063,2596,13286

View File

@ -126,7 +126,7 @@ module fround import cvw::*; #(parameter cvw_t P) (
3'b001: RoundUp = 0; // RZ 3'b001: RoundUp = 0; // RZ
3'b010: RoundUp = Xs & (Rp | Tp); // RN 3'b010: RoundUp = Xs & (Rp | Tp); // RN
3'b011: RoundUp = ~Xs & (Rp | Tp); // RP 3'b011: RoundUp = ~Xs & (Rp | Tp); // RP
3'b101: RoundUp = Rp; // RNTA 3'b100: RoundUp = Rp; // RNTA
default: RoundUp = 0; // should never happen default: RoundUp = 0; // should never happen
endcase endcase

View File

@ -1,7 +1,9 @@
/////////////////////////////////////////// ///////////////////////////////////////////
// spi_apb.sv // 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 // Purpose: SPI peripheral
// //
@ -13,7 +15,7 @@
// //
// A component of the Wally configurable RISC-V project. // 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 // SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
// //
@ -62,10 +64,6 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
localparam SPI_IE = 8'h70; localparam SPI_IE = 8'h70;
localparam SPI_IP = 8'h74; 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 // SPI control registers. Refer to SiFive FU540-C000 manual
logic [11:0] SckDiv; logic [11:0] SckDiv;
logic [1:0] SckMode; logic [1:0] SckMode;
@ -75,89 +73,70 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
logic [15:0] Delay0, Delay1; logic [15:0] Delay0, Delay1;
logic [4:0] Format; logic [4:0] Format;
logic [7:0] ReceiveData; logic [7:0] ReceiveData;
logic [2:0] TransmitWatermark, ReceiveWatermark;
logic [8:0] TransmitData; logic [8:0] TransmitData;
logic [2:0] TransmitWatermark, ReceiveWatermark;
logic [1:0] InterruptEnable, InterruptPending; logic [1:0] InterruptEnable, InterruptPending;
// Bus interface signals // Bus interface signals
logic [7:0] Entry; logic [7:0] Entry;
logic Memwrite; logic Memwrite;
logic [31:0] Din, Dout; logic [31:0] Din, Dout;
logic TransmitInactive; // High when there is no transmission, used as hardware interlock signal
// SPI Controller signals
logic SCLKenable;
logic EndOfFrame;
logic EndOfFrameDelay;
logic Transmitting;
logic InactiveState;
logic [3:0] FrameLength;
logic ResetSCLKenable;
logic TransmitStart;
logic TransmitStartD;
// Transmit Start State Machine Variables
typedef enum logic [1:0] {READY, START, WAIT} txState;
txState CurrState, NextState;
// FIFO FSM signals // FIFO FSM signals
// Watermark signals - TransmitReadMark = ip[0], ReceiveWriteMark = ip[1] // Watermark signals - TransmitReadMark = ip[0], ReceiveWriteMark = ip[1]
logic TransmitWriteMark, TransmitReadMark, RecieveWriteMark, RecieveReadMark; logic TransmitWriteMark, TransmitReadMark, RecieveWriteMark, RecieveReadMark;
logic TransmitFIFOWriteFull, TransmitFIFOReadEmpty; logic TransmitFIFOWriteFull, TransmitFIFOReadEmpty;
logic TransmitFIFOWriteIncrement; logic TransmitFIFOWriteIncrement;
logic ReceiveFiFoWriteInc; logic [7:0] TransmitFIFOReadData;
logic ReceiveFIFOWriteInc;
logic ReceiveFIFOReadIncrement; logic ReceiveFIFOReadIncrement;
logic ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty; logic ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty;
logic [7:0] TransmitFIFOReadData;
/* verilator lint_off UNDRIVEN */ /* verilator lint_off UNDRIVEN */
logic [2:0] TransmitWriteWatermarkLevel, ReceiveReadWatermarkLevel; // unused generic FIFO outputs logic [2:0] TransmitWriteWatermarkLevel, ReceiveReadWatermarkLevel; // unused generic FIFO outputs
/* verilator lint_off UNDRIVEN */ /* verilator lint_off UNDRIVEN */
logic [7:0] ReceiveShiftRegEndian; // Reverses ReceiveShiftReg if Format[2] set (little endian transmission) 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 // Shift reg signals
logic ShiftEdge; // Determines which edge of sck to shift from TransmitShiftReg logic ShiftEdge; // Determines which edge of sck to shift from TransmitReg
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 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 [7:0] TransmitDataEndian; // Reverses TransmitData from txFIFO if littleendian, since TransmitReg always shifts MSB
logic TransmitShiftRegLoad; // Determines when to load TransmitShiftReg logic TransmitLoad; // Determines when to load TransmitReg
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 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 // Shift stuff due to Format register?
logic ShiftIn; // Determines whether to shift from SPIIn or SPIOut (if SPI_LOOPBACK_TEST) 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 [3:0] LeftShiftAmount; // Determines left shift amount to left-align data when little endian
logic [7:0] ASR; // AlignedReceiveShiftReg logic [7:0] ASR; // AlignedReceiveShiftReg
logic ShiftEdgeSPICLK; // Changes ShiftEdge when SckDiv is 0
// CS signals // CS signals
logic [3:0] ChipSelectAuto; // Assigns ChipSelect value to selected CS signal based on CS ID 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 [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 // APB access
assign Entry = {PADDR[7:2],2'b00}; // 32-bit word-aligned accesses assign Entry = {PADDR[7:2],2'b00}; // 32-bit word-aligned accesses
assign Memwrite = PWRITE & PENABLE & PSEL; // Only write in access phase assign Memwrite = PWRITE & PENABLE & PSEL; // Only write in access phase
assign PREADY = Entry == SPI_TXDATA | Entry == SPI_RXDATA | Entry == SPI_IP | TransmitInactive; // Tie PREADY to transmission for hardware interlock // assign PREADY = Entry == SPI_TXDATA | Entry == SPI_RXDATA | Entry == SPI_IP;
assign PREADY = 1'b1;
// Account for subword read/write circuitry // Account for subword read/write circuitry
// -- Note SPI registers are 32 bits no matter what; access them with LW SW. // -- Note SPI registers are 32 bits no matter what; access them with LW SW.
@ -183,10 +162,8 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
InterruptEnable <= 2'b0; InterruptEnable <= 2'b0;
InterruptPending <= 2'b0; InterruptPending <= 2'b0;
end else begin // writes end else begin // writes
/* verilator lint_off CASEINCOMPLETE */ /* verilator lint_off CASEINCOMPLETE */
if (Memwrite & TransmitInactive) if (Memwrite)
case(Entry) // flop to sample inputs case(Entry) // flop to sample inputs
SPI_SCKDIV: SckDiv <= Din[11:0]; SPI_SCKDIV: SckDiv <= Din[11:0];
SPI_SCKMODE: SckMode <= Din[1:0]; SPI_SCKMODE: SckMode <= Din[1:0];
@ -234,227 +211,151 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
// SPI enable generation, where SCLK = PCLK/(2*(SckDiv + 1)) // 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 // 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 // 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 // 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)).
assign ZeroDiv = ~|(SckDiv[10:0]);
assign SCLKenable = ZeroDiv ? 1 : (DivCounter == SckDiv); // SPI Controller module -------------------------------------------
assign SCLKenableEarly = ((DivCounter + 12'b1) == SckDiv); // 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) always_ff @(posedge PCLK)
if (~PRESETn) DivCounter <= '0; if (~PRESETn) begin
else if (SCLKenable) DivCounter <= 12'b0; TransmitFIFOWriteIncrement <= 1'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 end else begin
if (ReceivePenultimateFrame & Active0) TransmitShiftEmpty <= 1'b1; TransmitFIFOWriteIncrement <= (Memwrite & (Entry == SPI_TXDATA) & ~TransmitFIFOWriteFull);
else TransmitShiftEmpty <= 1'b0;
end 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;
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;
// Main FSM which controls SPI transmission
typedef enum logic [2:0] {CS_INACTIVE, DELAY_0, ACTIVE_0, ACTIVE_1, DELAY_1,INTER_CS, INTER_XFR} statetype;
statetype state;
always_ff @(posedge PCLK) always_ff @(posedge PCLK)
if (~PRESETn) begin if (~PRESETn) begin
state <= CS_INACTIVE; TransmitFIFOReadIncrement <= 1'b0;
FrameCount <= 4'b0;
SPICLK <= SckMode[1];
end else if (SCLKenable) begin end else if (SCLKenable) begin
/* verilator lint_off CASEINCOMPLETE */ TransmitFIFOReadIncrement <= TransmitStartD | (EndOfFrameDelay & ~TransmitFIFOReadEmpty) ;
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 end
DELAY_0: begin
CS_SCKCount <= CS_SCKCount + 9'b1; // Check whether TransmitReg has been loaded.
if (CS_SCKCount >= (({Delay0[7:0], 1'b0}) + ImplicitDelay1)) begin // We use this signal to prevent returning to the Ready state for TransmitStart
state <= ACTIVE_0; logic TransmitRegLoaded;
SPICLK <= ~SckMode[1]; 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
end end
ACTIVE_0: begin
FrameCount <= FrameCount + 4'b1; // Setup TransmitStart state machine
SPICLK <= SckMode[1]; always_ff @(posedge PCLK) begin
state <= ACTIVE_1; if (~PRESETn) begin
CurrState <= READY;
end else begin
CurrState <= NextState;
end 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 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 endcase
/* verilator lint_off CASEINCOMPLETE */
end 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);
assign DelayMode = SckMode[0] ? (state == DELAY_1) : (state == ACTIVE_1 & ReceiveShiftFull); // Receive FIFO ----------------------------------------------------
assign ChipSelectInternal = (state == CS_INACTIVE | state == INTER_CS | DelayMode & ~|(Delay0[15:8])) ? ChipSelectDef : ~ChipSelectDef; always_ff @(posedge PCLK)
assign Active = (state == ACTIVE_0 | state == ACTIVE_1); if (~PRESETn) begin
assign SampleEdge = SckMode[0] ? (state == ACTIVE_1) : (state == ACTIVE_0); ReceiveFIFOReadIncrement <= 1'b0;
assign ZeroDelayHoldMode = ((ChipSelectMode == 2'b10) & (~|(Delay1[7:4]))); end else begin
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])))); ReceiveFIFOReadIncrement <= ((Entry == SPI_RXDATA) & ~ReceiveFIFOReadEmpty & PSEL & ~ReceiveFIFOReadIncrement);
assign Active0 = (state == ACTIVE_0); end
assign ShiftEdgeSPICLK = ZeroDiv ? ~SPICLK : SPICLK;
// Signal tracks which edge of sck to shift data always_ff @(posedge PCLK)
always_comb if (~PRESETn) begin
case(SckMode[1:0]) ReceiveFIFOWriteInc <= 1'b0;
2'b00: ShiftEdge = ShiftEdgeSPICLK & SCLKenable; end else if (SCLKenable) begin
2'b01: ShiftEdge = (~ShiftEdgeSPICLK & ~FirstFrame & (|(FrameCount) | (CS_SCKCount >= (({Delay0[7:0], 1'b0}) + ImplicitDelay1))) & SCLKenable & (FrameCount != Format[4:1]) & ~TransmitInactive); ReceiveFIFOWriteInc <= EndOfFrameDelay;
2'b10: ShiftEdge = ~ShiftEdgeSPICLK & SCLKenable; end
2'b11: ShiftEdge = (ShiftEdgeSPICLK & ~FirstFrame & (|(FrameCount) | (CS_SCKCount >= (({Delay0[7:0], 1'b0}) + ImplicitDelay1))) & SCLKenable & (FrameCount != Format[4:1]) & ~TransmitInactive);
default: ShiftEdge = ShiftEdgeSPICLK & SCLKenable; spi_fifo #(3,8) rxFIFO(PCLK, SCLKenable, 1'b1, PRESETn,
endcase ReceiveFIFOWriteInc, ReceiveFIFOReadIncrement,
ReceiveShiftRegEndian, ReceiveWatermark[2:0],
ReceiveReadWatermarkLevel,
ReceiveData[7:0],
ReceiveFIFOWriteFull,
ReceiveFIFOReadEmpty,
RecieveWriteMark, RecieveReadMark);
// Transmit shift register // 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]; assign TransmitLoad = TransmitStart | (EndOfFrameDelay & ~TransmitFIFOReadEmpty);
assign TransmitDataEndian = Format[0] ? {<<{TransmitFIFOReadData[7:0]}} : TransmitFIFOReadData[7:0];
always_ff @(posedge PCLK) always_ff @(posedge PCLK)
if(~PRESETn) TransmitShiftReg <= 8'b0; if(~PRESETn) TransmitReg <= 8'b0;
else if (TransmitShiftRegLoadSingleCycle) TransmitShiftReg <= TransmitDataEndian; else if (TransmitLoad) TransmitReg <= TransmitDataEndian;
else if (ShiftEdge & Active) TransmitShiftReg <= {TransmitShiftReg[6:0], TransmitShiftReg[0]}; else if (ShiftEdge) TransmitReg <= {TransmitReg[6:0], TransmitReg[0]};
assign SPIOut = TransmitShiftReg[7]; assign SPIOut = TransmitReg[7];
// If in loopback mode, receive shift register is connected directly to module's output pins. Else, connected to SPIIn // If in loopback mode, receive shift register is connected directly
// There are no setup/hold time issues because transmit shift register and receive shift register always shift/sample on opposite edges // 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; assign ShiftIn = P.SPI_LOOPBACK_TEST ? SPIOut : SPIIn;
// Receive shift register // Receive shift register
always_ff @(posedge PCLK) always_ff @(posedge PCLK)
if(~PRESETn) ReceiveShiftReg <= 8'b0; if(~PRESETn) begin
else if (SampleEdge & SCLKenable) begin ReceiveShiftReg <= 8'b0;
if (~Active) ReceiveShiftReg <= 8'b0; end else if (SampleEdge) begin
if (~Transmitting) ReceiveShiftReg <= 8'b0;
else ReceiveShiftReg <= {ReceiveShiftReg[6:0], ShiftIn}; else ReceiveShiftReg <= {ReceiveShiftReg[6:0], ShiftIn};
end end
// Aligns received data and reverses if little-endian // Aligns received data and reverses if little-endian
assign LeftShiftAmount = 4'h8 - Format[4:1]; assign LeftShiftAmount = 4'h8 - Format[4:1];
assign ASR = ReceiveShiftReg << LeftShiftAmount[2:0]; 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]; assign ReceiveShiftRegEndian = Format[0] ? {<<{ASR[7:0]}} : ASR[7:0];
// Interrupt logic: raise interrupt if any enabled interrupts are pending // Interrupt logic: raise interrupt if any enabled interrupts are pending
assign SPIIntr = |(InterruptPending & InterruptEnable); assign SPIIntr = |(InterruptPending & InterruptEnable);
// Chip select logic // Chip select logic
assign ChipSelectInternal = InactiveState ? ChipSelectDef : ~ChipSelectDef;
always_comb always_comb
case(ChipSelectID[1:0]) case(ChipSelectID[1:0])
2'b00: ChipSelectAuto = {ChipSelectDef[3], ChipSelectDef[2], ChipSelectDef[1], ChipSelectInternal[0]}; 2'b00: ChipSelectAuto = {ChipSelectDef[3], ChipSelectDef[2], ChipSelectDef[1], ChipSelectInternal[0]};
@ -462,6 +363,6 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
2'b10: ChipSelectAuto = {ChipSelectDef[3],ChipSelectInternal[2], ChipSelectDef[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]}; 2'b11: ChipSelectAuto = {ChipSelectInternal[3],ChipSelectDef[2], ChipSelectDef[1], ChipSelectDef[0]};
endcase endcase
assign SPICS = ChipSelectMode[0] ? ChipSelectDef : ChipSelectAuto; assign SPICS = ChipSelectMode[0] ? ChipSelectDef : ChipSelectAuto;
endmodule endmodule

View File

@ -1,9 +1,8 @@
/////////////////////////////////////////// ///////////////////////////////////////////
// spi_controller.sv // spi_controller.sv
// //
// Written: jacobpease@protonmail.com // Written: Jacob Pease jacobpease@protonmail.com
// Created: October 28th, 2024 // Created: October 28th, 2024
// Modified:
// //
// Purpose: Controller logic for SPI // Purpose: Controller logic for SPI
// //
@ -12,7 +11,7 @@
// A component of the CORE-V-WALLY configurable RISC-V project. // A component of the CORE-V-WALLY configurable RISC-V project.
// https://github.com/openhwgroup/cvw // 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 // SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
// //
@ -28,21 +27,35 @@
// and limitations under the License. // and limitations under the License.
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
module spi_controller ( module spi_controller (
input logic PCLK, input logic PCLK,
input logic PRESETn, input logic PRESETn,
// Start Transmission
input logic TransmitStart, input logic TransmitStart,
input logic TransmitStartD,
input logic ResetSCLKenable,
// Registers
input logic [11:0] SckDiv, input logic [11:0] SckDiv,
input logic [1:0] SckMode, input logic [1:0] SckMode,
input logic [1:0] CSMode, input logic [1:0] CSMode,
input logic [15:0] Delay0, input logic [15:0] Delay0,
input logic [15:0] Delay1, input logic [15:0] Delay1,
input logic [7:0] txFIFORead, input logic [3:0] FrameLength,
// Is the Transmit FIFO Empty?
input logic txFIFOReadEmpty, input logic txFIFOReadEmpty,
output logic SPICLK,
output logic SPIOUT, // Control signals
output logic CS 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 // CSMode Stuff
@ -55,36 +68,35 @@ module spi_controller (
// SCLKenable stuff // SCLKenable stuff
logic [11:0] DivCounter; logic [11:0] DivCounter;
logic SCLKenable; // logic SCLKenable;
logic SCLKenableEarly; // logic SCLKenableEarly;
logic SCLKenableLate;
logic EdgeTiming;
logic ZeroDiv; logic ZeroDiv;
logic Clock0;
logic Clock1;
logic SCK; // SUPER IMPORTANT, THIS CAN'T BE THE SAME AS SPICLK! logic SCK; // SUPER IMPORTANT, THIS CAN'T BE THE SAME AS SPICLK!
// Shift and Sample Edges // Shift and Sample Edges
logic PreShiftEdge; logic PreShiftEdge;
logic PreSampleEdge; logic PreSampleEdge;
logic ShiftEdge; // logic ShiftEdge;
logic SampleEdge; // logic SampleEdge;
logic ShiftEdgePulse;
logic SampleEdgePulse;
logic EndOfFramePulse;
// Frame stuff // Frame stuff
logic [2:0] BitNum; logic [3:0] BitNum;
logic LastBit; logic LastBit;
logic EndOfFrame; //logic EndOfFrame;
logic EndOfFrameDelay; //logic EndOfFrameDelay;
logic PhaseOneOffset; logic PhaseOneOffset;
// Transmit Stuff // Transmit Stuff
logic ContinueTransmit; logic ContinueTransmit;
// SPIOUT Stuff // SPIOUT Stuff
logic TransmitLoad; // logic TransmitLoad;
logic [7:0] TransmitReg; logic [7:0] TransmitReg;
logic Transmitting; //logic Transmitting;
logic EndTransmission; logic EndTransmission;
logic HoldMode; logic HoldMode;
@ -135,15 +147,12 @@ module spi_controller (
// SampleEdge. This makes sure that SPICLK is an output of a register // SampleEdge. This makes sure that SPICLK is an output of a register
// and it properly synchronizes signals. // and it properly synchronizes signals.
assign SCLKenableLate = DivCounter > SckDiv;
assign SCLKenable = DivCounter == SckDiv; assign SCLKenable = DivCounter == SckDiv;
assign SCLKenableEarly = (DivCounter + 1'b1) == SckDiv; // assign SCLKenableEarly = (DivCounter + 1'b1) == SckDiv;
assign LastBit = BitNum == 3'd7; assign LastBit = (BitNum == FrameLength - 4'b1);
assign EdgeTiming = SckDiv > 12'b0 ? SCLKenableEarly : SCLKenable;
//assign SPICLK = Clock0; //assign EndOfFrame = SCLKenable & LastBit & Transmitting;
assign ContinueTransmit = ~txFIFOReadEmpty & EndOfFrameDelay;
assign ContinueTransmit = ~txFIFOReadEmpty & EndOfFrame;
assign EndTransmission = txFIFOReadEmpty & EndOfFrameDelay; assign EndTransmission = txFIFOReadEmpty & EndOfFrameDelay;
always_ff @(posedge PCLK) begin always_ff @(posedge PCLK) begin
@ -151,10 +160,14 @@ module spi_controller (
DivCounter <= 12'b0; DivCounter <= 12'b0;
SPICLK <= SckMode[1]; SPICLK <= SckMode[1];
SCK <= 0; SCK <= 0;
BitNum <= 3'h0; BitNum <= 4'h0;
PreShiftEdge <= 0; PreShiftEdge <= 0;
PreSampleEdge <= 0; PreSampleEdge <= 0;
EndOfFrame <= 0; EndOfFrame <= 0;
CSSCKCounter <= 0;
SCKCSCounter <= 0;
INTERCSCounter <= 0;
INTERXFRCounter <= 0;
end else begin end else begin
// TODO: Consolidate into one delay counter since none of the // TODO: Consolidate into one delay counter since none of the
// delays happen at the same time? // delays happen at the same time?
@ -164,27 +177,27 @@ module spi_controller (
SCK <= ~SCK; SCK <= ~SCK;
end end
if ((CurrState == CSSCK) & SCK) begin if ((CurrState == CSSCK) & SCK & SCLKenable) begin
CSSCKCounter <= CSSCKCounter + 8'd1; CSSCKCounter <= CSSCKCounter + 8'd1;
end else begin end else if (SCLKenable & EndOfCSSCK) begin
CSSCKCounter <= 8'd0; CSSCKCounter <= 8'd0;
end end
if ((CurrState == SCKCS) & SCK) begin if ((CurrState == SCKCS) & SCK & SCLKenable) begin
SCKCSCounter <= SCKCSCounter + 8'd1; SCKCSCounter <= SCKCSCounter + 8'd1;
end else begin end else if (SCLKenable & EndOfSCKCS) begin
SCKCSCounter <= 8'd0; SCKCSCounter <= 8'd0;
end end
if ((CurrState == INTERCS) & SCK) begin if ((CurrState == INTERCS) & SCK & SCLKenable) begin
INTERCSCounter <= INTERCSCounter + 8'd1; INTERCSCounter <= INTERCSCounter + 8'd1;
end else begin end else if (SCLKenable & EndOfINTERCS) begin
INTERCSCounter <= 8'd0; INTERCSCounter <= 8'd0;
end end
if ((CurrState == INTERXFR) & SCK) begin if ((CurrState == INTERXFR) & SCK & SCLKenable) begin
INTERXFRCounter <= INTERXFRCounter + 8'd1; INTERXFRCounter <= INTERXFRCounter + 8'd1;
end else begin end else if (SCLKenable & EndOfINTERXFR) begin
INTERXFRCounter <= 8'd0; INTERXFRCounter <= 8'd0;
end end
@ -196,10 +209,10 @@ module spi_controller (
end end
// Reset divider // Reset divider
if (SCLKenable | TransmitStart) begin if (SCLKenable | TransmitStart | ResetSCLKenable) begin
DivCounter <= 12'b0; DivCounter <= 12'b0;
end else begin end else begin
DivCounter = DivCounter + 12'd1; DivCounter <= DivCounter + 12'd1;
end end
// EndOfFrame controller // EndOfFrame controller
@ -209,15 +222,16 @@ module spi_controller (
// EndOfFrame <= 1'b0; // EndOfFrame <= 1'b0;
// end // end
// TODO: Rename EndOfFrameDelay to EndOfFrame and remove this logic
if (~TransmitStart) begin if (~TransmitStart) begin
EndOfFrame <= (SckMode[1] ^ SckMode[0] ^ SPICLK) & SCLKenable & LastBit & Transmitting; EndOfFrame <= (SckMode[1] ^ SckMode[0] ^ SPICLK) & SCLKenable & LastBit & Transmitting;
end end
// Increment BitNum // Increment BitNum
if (ShiftEdge & Transmitting) begin if (ShiftEdge & Transmitting) begin
BitNum <= BitNum + 3'd1; BitNum <= BitNum + 4'd1;
end else if (EndOfFrameDelay) begin end else if (EndOfFrameDelay) begin
BitNum <= 3'b0; BitNum <= 4'b0;
end end
end end
end end
@ -225,6 +239,11 @@ module spi_controller (
// Delay ShiftEdge and SampleEdge by a half PCLK period // Delay ShiftEdge and SampleEdge by a half PCLK period
// Aligned EXACTLY ON THE MIDDLE of the leading and trailing edges. // Aligned EXACTLY ON THE MIDDLE of the leading and trailing edges.
// Sweeeeeeeeeet... // Sweeeeeeeeeet...
assign ShiftEdgePulse = SCLKenable & ~LastBit & Transmitting;
assign SampleEdgePulse = SCLKenable & Transmitting & ~DelayIsNext;
assign EndOfFramePulse = SCLKenable & LastBit & Transmitting;
always_ff @(posedge ~PCLK) begin always_ff @(posedge ~PCLK) begin
if (~PRESETn | TransmitStart) begin if (~PRESETn | TransmitStart) begin
ShiftEdge <= 0; ShiftEdge <= 0;
@ -232,18 +251,58 @@ module spi_controller (
SampleEdge <= 0; SampleEdge <= 0;
EndOfFrameDelay <= 0; EndOfFrameDelay <= 0;
end else begin end else begin
ShiftEdge <= ((SckMode[1] ^ SckMode[0] ^ SPICLK) & SCLKenable & ~LastBit & Transmitting) & PhaseOneOffset; PhaseOneOffset <= (PhaseOneOffset == 0) ? Transmitting & SCLKenable : ~EndOfFrameDelay;
PhaseOneOffset <= PhaseOneOffset == 0 ? Transmitting & SCLKenable : PhaseOneOffset; case(SckMode)
SampleEdge <= (SckMode[1] ^ SckMode[0] ^ ~SPICLK) & SCLKenable & Transmitting; 2'b00: begin
EndOfFrameDelay <= (SckMode[1] ^ SckMode[0] ^ SPICLK) & SCLKenable & LastBit & Transmitting; 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
end end
// typedef enum logic [2:0] {INACTIVE, CSSCK, TRANSMIT, SCKCS, HOLD, INTERCS, INTERXFR} statetype; // typedef enum logic [2:0] {INACTIVE, CSSCK, TRANSMIT, SCKCS, HOLD, INTERCS, INTERXFR} statetype;
// statetype CurrState, NextState; // statetype CurrState, NextState;
assign HoldMode = CSMode == 2'b10; assign HoldMode = CSMode == HOLDMODE;
assign TransmitLoad = TransmitStart | (EndOfFrameDelay & ~txFIFOReadEmpty); // 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 always_ff @(posedge PCLK) begin
if (~PRESETn) begin if (~PRESETn) begin
@ -255,71 +314,68 @@ module spi_controller (
always_comb begin always_comb begin
case (CurrState) case (CurrState)
INACTIVE: begin // INACTIVE case -------------------------------- INACTIVE: if (TransmitStartD) begin
if (TransmitStart) begin if (~HasCSSCK) NextState = TRANSMIT;
if (~HasCSSCK) begin else NextState = CSSCK;
NextState = TRANSMIT;
end else begin
NextState = CSSCK;
end
end else begin end else begin
NextState = INACTIVE; NextState = INACTIVE;
end end
end CSSCK: if (EndOfCSSCK) NextState = TRANSMIT;
CSSCK: begin // DELAY0 case ------------------------------------- else NextState = CSSCK;
if (EndOfCSSCK) begin
NextState = TRANSMIT;
end
end
TRANSMIT: begin // TRANSMIT case -------------------------------- TRANSMIT: begin // TRANSMIT case --------------------------------
case(CSMode) case(CSMode)
AUTOMODE: begin AUTOMODE: begin
if (EndTransmission) begin if (EndTransmission) NextState = INACTIVE;
NextState = INACTIVE; else if (EndOfFrameDelay) NextState = SCKCS;
end else if (ContinueTransmit) begin else NextState = TRANSMIT;
NextState = SCKCS;
end
end end
HOLDMODE: begin HOLDMODE: begin
if (EndTransmission) begin if (EndTransmission) NextState = HOLD;
NextState = HOLD; else if (ContinueTransmit & HasINTERXFR) NextState = INTERXFR;
end else if (ContinueTransmit) begin else NextState = TRANSMIT;
if (HasINTERXFR) NextState = INTERXFR;
end
end end
OFFMODE: begin OFFMODE: begin
if (EndTransmission) NextState = INACTIVE;
else if (ContinueTransmit & HasINTERXFR) NextState = INTERXFR;
else NextState = TRANSMIT;
end end
default: NextState = TRANSMIT;
endcase endcase
end end
SCKCS: begin // SCKCS case -------------------------------------- SCKCS: begin // SCKCS case --------------------------------------
if (EndOfSCKCS) begin if (EndOfSCKCS) begin
if (EndTransmission) begin if (~ContinueTransmitD) begin
if (CSMode == AUTOMODE) NextState = INACTIVE; // if (CSMode == AUTOMODE) NextState = INACTIVE;
else if (CSMode == HOLDMODE) NextState = HOLD; if (CSMode == HOLDMODE) NextState = HOLD;
end else if (ContinueTransmit) begin else NextState = INACTIVE;
end else begin
if (HasINTERCS) NextState = INTERCS; if (HasINTERCS) NextState = INTERCS;
else NextState = TRANSMIT; else NextState = TRANSMIT;
end end
end else begin
NextState = SCKCS;
end end
end end
HOLD: begin // HOLD mode case ----------------------------------- HOLD: begin // HOLD mode case -----------------------------------
if (CSMode == AUTOMODE) begin if (CSMode == AUTOMODE) begin
NextState = INACTIVE; 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; NextState = TRANSMIT;
end end else NextState = HOLD;
end end
INTERCS: begin // INTERCS case ---------------------------------- INTERCS: begin // INTERCS case ----------------------------------
if (EndOfINTERCS) begin if (EndOfINTERCS) begin
if (HasCSSCK) NextState = CSSCK; if (HasCSSCK) NextState = CSSCK;
else NextState = TRANSMIT; else NextState = TRANSMIT;
end else begin
NextState = INTERCS;
end end
end end
INTERXFR: begin // INTERXFR case -------------------------------- INTERXFR: begin // INTERXFR case --------------------------------
if (EndOfINTERXFR) begin if (EndOfINTERXFR) begin
NextState = TRANSMIT; NextState = TRANSMIT;
end else begin
NextState = INTERXFR;
end end
end end
default: begin default: begin
@ -330,19 +386,6 @@ module spi_controller (
assign Transmitting = CurrState == TRANSMIT; assign Transmitting = CurrState == TRANSMIT;
assign DelayIsNext = (NextState == CSSCK | NextState == SCKCS | NextState == INTERCS | NextState == INTERXFR); assign DelayIsNext = (NextState == CSSCK | NextState == SCKCS | NextState == INTERCS | NextState == INTERXFR);
assign InactiveState = CurrState == INACTIVE | CurrState == INTERCS;
//
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;
endmodule endmodule

View File

@ -72,7 +72,8 @@ string coverage64gc[] = '{
"pmpcfg2", "pmpcfg2",
"pmppriority", "pmppriority",
"pmpcbo", "pmpcbo",
"pmpadrdecs" "pmpadrdecs",
"btbthrash"
}; };
string buildroot[] = '{ string buildroot[] = '{

145
tests/coverage/btbthrash.S Normal file
View File

@ -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

View File

@ -238,46 +238,6 @@
0000001F 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 00000001 #watermark interrupts
00000000 #read mip 00000000 #read mip

View File

@ -547,108 +547,13 @@ test_cases:
#.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end #.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
#.4byte rx_data, 0x000000F0, read32_test # read rx_data #.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 watermark interrupts ===========
# Test transmit watermark interrupt (triggers when entries in tx FIFO < tx watermark) without external enables # Test transmit watermark interrupt (triggers when entries in tx FIFO < tx watermark) without external enables
SETUP_PLIC SETUP_PLIC
.4byte fmt, 0x00080000, write32_test # reset format register
.4byte delay1, 0x0000001, write32_test # reset delay1 register .4byte delay1, 0x0000001, write32_test # reset delay1 register
.4byte cs_mode, 0x00000000, write32_test # reset cs_mode .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) .4byte tx_mark, 0x00000001, write32_test # set transmit watermark to 1 (any entry turns mark off)

View File

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

View File

@ -551,94 +551,6 @@ test_cases:
#.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end #.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
#.8byte rx_data, 0x000000F0, read32_test # read rx_data #.8byte rx_data, 0x000000F0, read32_test # read rx_data
#=========== Test Hardware Interlock ================
# interlock in base case
.8byte fmt, 0x00080000, write32_test # reset fmt register
.8byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x00000062, write32_test # initiate transmission
.8byte sck_mode, 0x00000002, write32_test # flip polarity during transmission
.8byte tx_data, 0x00000026, write32_test # transmit second frame w/ control register updated
.8byte 0x0, 0x00000001, spi_data_wait
.8byte rx_data, 0x00000062, read32_test
.8byte rx_data, 0x00000026, read32_test # clear rx fifo
.8byte sck_mode, 0x00000000, write32_test # reset polarity
# interlock in case where cs_mode is auto, but there is minimal intercs delay
.8byte delay0, 0x00000001, write32_test # set sck-cs delay to 0, with sck.pha 0 there is 0 delay
.8byte tx_data, 0x000000D2, write32_test # initiate transmission
.8byte sck_mode, 0x00000002, write32_test # flip sck polarity
.8byte tx_data, 0x0000002D, write32_test # transmit second frame
.8byte 0x0, 0x00000001, spi_data_wait
.8byte rx_data, 0x000000D2, read32_test
.8byte rx_data, 0x0000002D, read32_test # clear rx fifo
.8byte sck_mode, 0x00000000, write32_test # reset polarity
# interlock in case where cs_mode = hold, 0 intercs delay
.8byte delay0, 0x00010001, write32_test # reset delay0
.8byte sck_mode, 0x00000000, write32_test # reset polarity
.8byte cs_mode, 0x00000002, write32_test # set cs_mode to hold
.8byte tx_data, 0x15263748, spi_burst_send # place 4 frames into tx fifo
.8byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame)
.8byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end
.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.8byte sck_mode, 0x00000000, write32_test # flip polarity again
.8byte 0x0, 0x00000003, spi_data_wait # wait for final frame
.8byte rx_data, 0x00000048, read32_test
.8byte rx_data, 0x00000037, read32_test
.8byte rx_data, 0x00000026, read32_test
.8byte rx_data, 0x00000015, read32_test #clear rx fifo
# interlock in case where cs_mode = hold, intercs delay
.8byte sck_mode, 0x00000000, write32_test # reset polarity
.8byte delay1, 0x00010001, write32_test # set intercs delay to 1
.8byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x51627384, spi_burst_send # place 4 frames into tx fifo
.8byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame)
.8byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end
.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.8byte sck_mode, 0x00000000, write32_test # flip polarity again
.8byte 0x0, 0x00000003, spi_data_wait # wait for final frame
.8byte rx_data, 0x00000084, read32_test
.8byte rx_data, 0x00000073, read32_test
.8byte rx_data, 0x00000062, read32_test
.8byte rx_data, 0x00000051, read32_test #clear rx fifo
# repeat previous set of tests with cs_mode = off
.8byte cs_mode, 0x00000003, write32_test # set cs_mode to hold
.8byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x13243546, spi_burst_send # place 4 frames into tx fifo
.8byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame)
.8byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end
.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.8byte sck_mode, 0x00000000, write32_test # flip polarity again
.8byte 0x0, 0x00000003, spi_data_wait # wait for final frame
.8byte rx_data, 0x00000046, read32_test
.8byte rx_data, 0x00000035, read32_test
.8byte rx_data, 0x00000024, read32_test
.8byte rx_data, 0x00000013, read32_test #clear rx fifo
# interlock in case where cs_mode = hold, intercs delay
.8byte sck_mode, 0x00000000, write32_test # reset polarity
.8byte delay1, 0x00000000, write32_test # set intercs delay to 0
.8byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x31425364, spi_burst_send # place 4 frames into tx fifo
.8byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame)
.8byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end
.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.8byte sck_mode, 0x00000000, write32_test # flip polarity again
.8byte 0x0, 0x00000003, spi_data_wait # wait for final frame
.8byte rx_data, 0x00000064, read32_test
.8byte rx_data, 0x00000053, read32_test
.8byte rx_data, 0x00000042, read32_test
.8byte rx_data, 0x00000031, read32_test #clear rx fifo
@ -652,7 +564,7 @@ test_cases:
# Test transmit watermark interrupt (triggers when entries in tx FIFO < tx watermark) without external enables # Test transmit watermark interrupt (triggers when entries in tx FIFO < tx watermark) without external enables
SETUP_PLIC SETUP_PLIC
.8byte fmt, 0x00080000, write32_test # reset format register
.8byte delay1, 0x0000001, write32_test # reset delay1 register .8byte delay1, 0x0000001, write32_test # reset delay1 register
.8byte cs_mode, 0x00000000, write32_test # reset cs_mode .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 .8byte sck_div, 0x00000100, write32_test # lower SPI clock rate so reads are done at correct time when ICACHE not supported