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

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

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
# "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

View File

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

View File

@ -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;
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 [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 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;
// SPI Controller signals
logic SCLKenable;
logic EndOfFrame;
logic EndOfFrameDelay;
logic Transmitting;
logic InactiveState;
logic [3:0] FrameLength;
// 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
logic ResetSCLKenable;
logic TransmitStart;
logic TransmitStartD;
// 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;
// Transmit Start State Machine Variables
typedef enum logic [1:0] {READY, START, WAIT} txState;
txState CurrState, NextState;
// 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
// 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;
// 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
logic ReceiveFIFOWriteInc;
logic ReceiveFIFOReadIncrement;
logic ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty;
// 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
/* 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)
// 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 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 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
// 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
logic DelayMode; // Determines where to place implicit half cycle delay based on sck phase for CS assertion
// 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
// 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;
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;
// 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
// 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;
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)
if (~PRESETn) begin
state <= CS_INACTIVE;
FrameCount <= 4'b0;
SPICLK <= SckMode[1];
end else if (SCLKenable) begin
/* 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
// 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;
assign SPICS = ChipSelectMode[0] ? ChipSelectDef : ChipSelectAuto;
endmodule

View File

@ -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 (
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,25 +239,70 @@ 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
@ -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

View File

@ -72,7 +72,8 @@ string coverage64gc[] = '{
"pmpcfg2",
"pmppriority",
"pmpcbo",
"pmpadrdecs"
"pmpadrdecs",
"btbthrash"
};
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
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

View File

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

View File

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

View File

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