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

This commit is contained in:
David Harris 2023-11-03 16:04:10 -07:00
commit 4de21c206f
31 changed files with 2306 additions and 52 deletions

@ -1 +1 @@
Subproject commit 873d16e748ad60023dcdda3926144957c096e31d
Subproject commit 197179fdc9dfeeca821e848f373c897a3fdae86c

View File

@ -118,6 +118,9 @@ localparam logic [63:0] PLIC_RANGE = 64'h03FFFFFF;
localparam SDC_SUPPORTED = 1'b0;
localparam logic [63:0] SDC_BASE = 64'h00013000;
localparam logic [63:0] SDC_RANGE = 64'h0000007F;
localparam SPI_SUPPORTED = 1'b1;
localparam logic [63:0] SPI_BASE = 64'h10040000;
localparam logic [63:0] SPI_RANGE = 64'h00000FFF;
// Bus Interface width
localparam AHBW = 32'd64;
@ -126,6 +129,7 @@ localparam AHBW = 32'd64;
// Tie GPIO outputs back to inputs
localparam GPIO_LOOPBACK_TEST = 0;
localparam SPI_LOOPBACK_TEST = 0;
// Hardware configuration
localparam UART_PRESCALE = 32'd0;
@ -135,6 +139,7 @@ localparam PLIC_NUM_SRC = 32'd53;
localparam PLIC_NUM_SRC_LT_32 = (PLIC_NUM_SRC < 32);
localparam PLIC_UART_ID = 32'd10;
localparam PLIC_GPIO_ID = 32'd3;
localparam PLIC_SPI_ID = 32'd6;
localparam PLIC_SDC_ID = 32'd20;
localparam BPRED_SUPPORTED = 1;

View File

@ -135,10 +135,15 @@ localparam SDC_SUPPORTED = 1'b1;
localparam logic [63:0] SDC_BASE = 64'h00013000;
localparam logic [63:0] SDC_RANGE = 64'h0000007F;
localparam SPI_SUPPORTED = 1'b1;
localparam logic [63:0] SPI_BASE = 64'h10040000;
localparam logic [63:0] SPI_RANGE = 64'h00000FFF;
// Test modes
// Tie GPIO outputs back to inputs
localparam GPIO_LOOPBACK_TEST = 0;
localparam SPI_LOOPBACK_TEST = 0;
// Hardware configuration
localparam UART_PRESCALE = 32'd0;
@ -149,6 +154,7 @@ localparam PLIC_NUM_SRC = 32'd53;
localparam PLIC_NUM_SRC_LT_32 = (PLIC_NUM_SRC < 32);
localparam PLIC_GPIO_ID = 32'd3;
localparam PLIC_UART_ID = 32'd10;
localparam PLIC_SPI_ID = 32'd6;
localparam PLIC_SDC_ID = 32'd20;
localparam BPRED_SUPPORTED = 1;

View File

@ -119,6 +119,9 @@ localparam logic [63:0] PLIC_RANGE = 64'h03FFFFFF;
localparam SDC_SUPPORTED = 1'b0;
localparam logic [63:0] SDC_BASE = 64'h00013000;
localparam logic [63:0] SDC_RANGE = 64'h0000007F;
localparam SPI_SUPPORTED = 1'b0;
localparam logic [63:0] SPI_BASE = 64'h10040000;
localparam logic [63:0] SPI_RANGE = 64'h00000FFF;
// Bus Interface width
localparam AHBW = 32'd32;
@ -127,6 +130,7 @@ localparam AHBW = 32'd32;
// Tie GPIO outputs back to inputs
localparam GPIO_LOOPBACK_TEST = 1;
localparam SPI_LOOPBACK_TEST = 0;
// Hardware configuration
localparam UART_PRESCALE = 32'd1;
@ -137,6 +141,7 @@ localparam PLIC_NUM_SRC = 32'd10;
localparam PLIC_NUM_SRC_LT_32 = (PLIC_NUM_SRC < 32);
localparam PLIC_GPIO_ID = 32'd3;
localparam PLIC_UART_ID = 32'd10;
localparam PLIC_SPI_ID = 32'd6;
localparam PLIC_SDC_ID = 32'd9;
localparam BPRED_SUPPORTED = 0;

View File

@ -120,6 +120,9 @@ localparam logic [63:0] PLIC_RANGE = 64'h03FFFFFF;
localparam SDC_SUPPORTED = 1'b0;
localparam logic [63:0] SDC_BASE = 64'h00013000;
localparam logic [63:0] SDC_RANGE = 64'h0000007F;
localparam SPI_SUPPORTED = 1'b1;
localparam logic [63:0] SPI_BASE = 64'h10040000;
localparam logic [63:0] SPI_RANGE = 64'h00000FFF;
// Bus Interface width
localparam AHBW = 32'd32;
@ -128,6 +131,7 @@ localparam AHBW = 32'd32;
// Tie GPIO outputs back to inputs
localparam GPIO_LOOPBACK_TEST = 1;
localparam SPI_LOOPBACK_TEST = 1;
// Hardware configuration
localparam UART_PRESCALE = 32'd1;
@ -138,6 +142,7 @@ localparam PLIC_NUM_SRC = 32'd10;
localparam PLIC_NUM_SRC_LT_32 = (PLIC_NUM_SRC < 32);
localparam PLIC_GPIO_ID = 32'd3;
localparam PLIC_UART_ID = 32'd10;
localparam PLIC_SPI_ID = 32'd6;
localparam PLIC_SDC_ID = 32'd9;
localparam BPRED_SUPPORTED = 1;

View File

@ -119,6 +119,9 @@ localparam logic [63:0] PLIC_RANGE = 64'h03FFFFFF;
localparam SDC_SUPPORTED = 1'b0;
localparam logic [63:0] SDC_BASE = 64'h00013000;
localparam logic [63:0] SDC_RANGE = 64'h0000007F;
localparam SPI_SUPPORTED = 1'b0;
localparam logic [63:0] SPI_BASE = 64'h10040000;
localparam logic [63:0] SPI_RANGE = 64'h00000FFF;
// Bus Interface width
localparam AHBW = 32'd32;
@ -127,6 +130,7 @@ localparam AHBW = 32'd32;
// Tie GPIO outputs back to inputs
localparam GPIO_LOOPBACK_TEST = 1;
localparam SPI_LOOPBACK_TEST = 1;
// Hardware configuration
localparam UART_PRESCALE = 32'd1;
@ -137,6 +141,8 @@ localparam PLIC_NUM_SRC = 32'd10;
localparam PLIC_NUM_SRC_LT_32 = (PLIC_NUM_SRC < 32);
localparam PLIC_GPIO_ID = 32'd3;
localparam PLIC_UART_ID = 32'd10;
localparam PLIC_SPI_ID = 32'd6;
localparam PLIC_SDC_ID = 32'd9;
localparam BPRED_SUPPORTED = 0;

View File

@ -118,6 +118,9 @@ localparam logic [63:0] PLIC_RANGE = 64'h03FFFFFF;
localparam SDC_SUPPORTED = 1'b0;
localparam logic [63:0] SDC_BASE = 64'h00013000;
localparam logic [63:0] SDC_RANGE = 64'h0000007F;
localparam SPI_SUPPORTED = 1'b1;
localparam logic [63:0] SPI_BASE = 64'h10040000;
localparam logic [63:0] SPI_RANGE = 64'h00000FFF;
// Bus Interface width
localparam AHBW = 32'd32;
@ -126,6 +129,7 @@ localparam AHBW = 32'd32;
// Tie GPIO outputs back to inputs
localparam GPIO_LOOPBACK_TEST = 1;
localparam SPI_LOOPBACK_TEST = 1;
// Hardware configuration
localparam UART_PRESCALE = 32'd1;
@ -136,6 +140,7 @@ localparam PLIC_NUM_SRC = 32'd10;
localparam PLIC_NUM_SRC_LT_32 = (PLIC_NUM_SRC < 32);
localparam PLIC_GPIO_ID = 32'd3;
localparam PLIC_UART_ID = 32'd10;
localparam PLIC_SPI_ID = 32'd6;
localparam PLIC_SDC_ID = 32'd9;
localparam BPRED_SUPPORTED = 0;

View File

@ -124,11 +124,15 @@ localparam logic [63:0] PLIC_RANGE = 64'h03FFFFFF;
localparam SDC_SUPPORTED = 1'b0;
localparam logic [63:0] SDC_BASE = 64'h00013000;
localparam logic [63:0] SDC_RANGE = 64'h0000007F;
localparam SPI_SUPPORTED = 1'b1;
localparam logic [63:0] SPI_BASE = 64'h10040000;
localparam logic [63:0] SPI_RANGE = 64'h00000FFF;
// Test modes
// Tie GPIO outputs back to inputs
localparam GPIO_LOOPBACK_TEST = 1;
localparam SPI_LOOPBACK_TEST = 1;
// Hardware configuration
localparam UART_PRESCALE = 32'd1;
@ -139,6 +143,7 @@ localparam PLIC_NUM_SRC = 32'd10;
localparam PLIC_NUM_SRC_LT_32 = (PLIC_NUM_SRC < 32);
localparam PLIC_GPIO_ID = 32'd3;
localparam PLIC_UART_ID = 32'd10;
localparam PLIC_SPI_ID = 32'd6;
localparam PLIC_SDC_ID = 32'd9;
localparam BPRED_SUPPORTED = 1;

View File

@ -124,11 +124,15 @@ localparam logic [63:0] PLIC_RANGE = 64'h03FFFFFF;
localparam SDC_SUPPORTED = 1'b0;
localparam logic [63:0] SDC_BASE = 64'h00013000;
localparam logic [63:0] SDC_RANGE = 64'h0000007F;
localparam SPI_SUPPORTED = 1'b1;
localparam logic [63:0] SPI_BASE = 64'h10040000;
localparam logic [63:0] SPI_RANGE = 64'h00000FFF;
// Test modes
// Tie GPIO outputs back to inputs
localparam GPIO_LOOPBACK_TEST = 1;
localparam SPI_LOOPBACK_TEST = 1;
// Hardware configuration
localparam UART_PRESCALE = 32'd1;
@ -139,6 +143,7 @@ localparam PLIC_NUM_SRC = 32'd10;
localparam PLIC_NUM_SRC_LT_32 = (PLIC_NUM_SRC < 32);
localparam PLIC_GPIO_ID = 32'd3;
localparam PLIC_UART_ID = 32'd10;
localparam PLIC_SPI_ID = 32'd6;
localparam PLIC_SDC_ID = 32'd9;
localparam BPRED_SUPPORTED = 1;

View File

@ -124,11 +124,15 @@ localparam logic [63:0] PLIC_RANGE = 64'h03FFFFFF;
localparam SDC_SUPPORTED = 1'b0;
localparam logic [63:0] SDC_BASE = 64'h00013000;
localparam logic [63:0] SDC_RANGE = 64'h0000007F;
localparam SPI_SUPPORTED = 1'b0;
localparam logic [63:0] SPI_BASE = 64'h10040000;
localparam logic [63:0] SPI_RANGE = 64'h00000FFF;
// Test modes
// Tie GPIO outputs back to inputs
localparam GPIO_LOOPBACK_TEST = 1;
localparam SPI_LOOPBACK_TEST = 1;
// Hardware configuration
localparam UART_PRESCALE = 32'd1;
@ -139,6 +143,7 @@ localparam PLIC_NUM_SRC = 32'd10;
localparam PLIC_NUM_SRC_LT_32 = (PLIC_NUM_SRC < 32);
localparam PLIC_GPIO_ID = 32'd3;
localparam PLIC_UART_ID = 32'd10;
localparam PLIC_SPI_ID = 32'd6;
localparam PLIC_SDC_ID = 32'd9;
localparam BPRED_SUPPORTED = 0;

View File

@ -73,12 +73,17 @@ localparam cvw_t P = '{
SDC_SUPPORTED : SDC_SUPPORTED,
SDC_BASE : SDC_BASE,
SDC_RANGE : SDC_RANGE,
SPI_SUPPORTED : SPI_SUPPORTED,
SPI_BASE : SPI_BASE,
SPI_RANGE : SPI_RANGE,
GPIO_LOOPBACK_TEST : GPIO_LOOPBACK_TEST,
SPI_LOOPBACK_TEST : SPI_LOOPBACK_TEST,
UART_PRESCALE : UART_PRESCALE ,
PLIC_NUM_SRC : PLIC_NUM_SRC,
PLIC_NUM_SRC_LT_32 : PLIC_NUM_SRC_LT_32,
PLIC_GPIO_ID : PLIC_GPIO_ID,
PLIC_UART_ID : PLIC_UART_ID,
PLIC_SPI_ID : PLIC_SPI_ID,
PLIC_SDC_ID : PLIC_SDC_ID,
BPRED_SUPPORTED : BPRED_SUPPORTED,
/* verilator lint_off ENUMVALUE */

View File

@ -1,2 +1,2 @@
vsim -do "do wally.do rv64gc wally64priv"
vsim -do "do wally.do rv64gc wally64periph"

View File

@ -1 +1 @@
vsim -c -do "do wally-batch.do rv64gc wally64priv"
vsim -c -do "do wally-batch.do rv64gc wally64periph"

View File

@ -128,11 +128,15 @@ typedef struct packed {
logic SDC_SUPPORTED;
logic [63:0] SDC_BASE;
logic [63:0] SDC_RANGE;
logic SPI_SUPPORTED;
logic [63:0] SPI_BASE;
logic [63:0] SPI_RANGE;
// Test modes
// Tie GPIO outputs back to inputs
logic GPIO_LOOPBACK_TEST;
logic SPI_LOOPBACK_TEST;
// Hardware configuration
int UART_PRESCALE ;
@ -142,6 +146,7 @@ typedef struct packed {
logic PLIC_NUM_SRC_LT_32;
int PLIC_GPIO_ID;
int PLIC_UART_ID;
int PLIC_SPI_ID;
int PLIC_SDC_ID;
logic BPRED_SUPPORTED;

View File

@ -32,23 +32,24 @@ module adrdecs import cvw::*; #(parameter cvw_t P) (
input logic [P.PA_BITS-1:0] PhysicalAddress,
input logic AccessRW, AccessRX, AccessRWX,
input logic [1:0] Size,
output logic [10:0] SelRegions
output logic [11:0] SelRegions
);
localparam logic [3:0] SUPPORTED_SIZE = (P.LLEN == 32 ? 4'b0111 : 4'b1111);
// Determine which region of physical memory (if any) is being accessed
adrdec #(P.PA_BITS) dtimdec(PhysicalAddress, P.DTIM_BASE[P.PA_BITS-1:0], P.DTIM_RANGE[P.PA_BITS-1:0], P.DTIM_SUPPORTED, AccessRW, Size, SUPPORTED_SIZE, SelRegions[10]);
adrdec #(P.PA_BITS) iromdec(PhysicalAddress, P.IROM_BASE[P.PA_BITS-1:0], P.IROM_RANGE[P.PA_BITS-1:0], P.IROM_SUPPORTED, AccessRX, Size, SUPPORTED_SIZE, SelRegions[9]);
adrdec #(P.PA_BITS) ddr4dec(PhysicalAddress, P.EXT_MEM_BASE[P.PA_BITS-1:0], P.EXT_MEM_RANGE[P.PA_BITS-1:0], P.EXT_MEM_SUPPORTED, AccessRWX, Size, SUPPORTED_SIZE, SelRegions[8]);
adrdec #(P.PA_BITS) bootromdec(PhysicalAddress, P.BOOTROM_BASE[P.PA_BITS-1:0], P.BOOTROM_RANGE[P.PA_BITS-1:0], P.BOOTROM_SUPPORTED, AccessRX, Size, SUPPORTED_SIZE, SelRegions[7]);
adrdec #(P.PA_BITS) uncoreramdec(PhysicalAddress, P.UNCORE_RAM_BASE[P.PA_BITS-1:0], P.UNCORE_RAM_RANGE[P.PA_BITS-1:0], P.UNCORE_RAM_SUPPORTED, AccessRWX, Size, SUPPORTED_SIZE, SelRegions[6]);
adrdec #(P.PA_BITS) clintdec(PhysicalAddress, P.CLINT_BASE[P.PA_BITS-1:0], P.CLINT_RANGE[P.PA_BITS-1:0], P.CLINT_SUPPORTED, AccessRW, Size, SUPPORTED_SIZE, SelRegions[5]);
adrdec #(P.PA_BITS) gpiodec(PhysicalAddress, P.GPIO_BASE[P.PA_BITS-1:0], P.GPIO_RANGE[P.PA_BITS-1:0], P.GPIO_SUPPORTED, AccessRW, Size, 4'b0100, SelRegions[4]);
adrdec #(P.PA_BITS) uartdec(PhysicalAddress, P.UART_BASE[P.PA_BITS-1:0], P.UART_RANGE[P.PA_BITS-1:0], P.UART_SUPPORTED, AccessRW, Size, 4'b0001, SelRegions[3]);
adrdec #(P.PA_BITS) plicdec(PhysicalAddress, P.PLIC_BASE[P.PA_BITS-1:0], P.PLIC_RANGE[P.PA_BITS-1:0], P.PLIC_SUPPORTED, AccessRW, Size, 4'b0100, SelRegions[2]);
adrdec #(P.PA_BITS) sdcdec(PhysicalAddress, P.SDC_BASE[P.PA_BITS-1:0], P.SDC_RANGE[P.PA_BITS-1:0], P.SDC_SUPPORTED, AccessRW, Size, SUPPORTED_SIZE, SelRegions[1]);
adrdec #(P.PA_BITS) dtimdec(PhysicalAddress, P.DTIM_BASE[P.PA_BITS-1:0], P.DTIM_RANGE[P.PA_BITS-1:0], P.DTIM_SUPPORTED, AccessRW, Size, SUPPORTED_SIZE, SelRegions[11]);
adrdec #(P.PA_BITS) iromdec(PhysicalAddress, P.IROM_BASE[P.PA_BITS-1:0], P.IROM_RANGE[P.PA_BITS-1:0], P.IROM_SUPPORTED, AccessRX, Size, SUPPORTED_SIZE, SelRegions[10]);
adrdec #(P.PA_BITS) ddr4dec(PhysicalAddress, P.EXT_MEM_BASE[P.PA_BITS-1:0], P.EXT_MEM_RANGE[P.PA_BITS-1:0], P.EXT_MEM_SUPPORTED, AccessRWX, Size, SUPPORTED_SIZE, SelRegions[9]);
adrdec #(P.PA_BITS) bootromdec(PhysicalAddress, P.BOOTROM_BASE[P.PA_BITS-1:0], P.BOOTROM_RANGE[P.PA_BITS-1:0], P.BOOTROM_SUPPORTED, AccessRX, Size, SUPPORTED_SIZE, SelRegions[8]);
adrdec #(P.PA_BITS) uncoreramdec(PhysicalAddress, P.UNCORE_RAM_BASE[P.PA_BITS-1:0], P.UNCORE_RAM_RANGE[P.PA_BITS-1:0], P.UNCORE_RAM_SUPPORTED, AccessRWX, Size, SUPPORTED_SIZE, SelRegions[7]);
adrdec #(P.PA_BITS) clintdec(PhysicalAddress, P.CLINT_BASE[P.PA_BITS-1:0], P.CLINT_RANGE[P.PA_BITS-1:0], P.CLINT_SUPPORTED, AccessRW, Size, SUPPORTED_SIZE, SelRegions[6]);
adrdec #(P.PA_BITS) gpiodec(PhysicalAddress, P.GPIO_BASE[P.PA_BITS-1:0], P.GPIO_RANGE[P.PA_BITS-1:0], P.GPIO_SUPPORTED, AccessRW, Size, 4'b0100, SelRegions[5]);
adrdec #(P.PA_BITS) uartdec(PhysicalAddress, P.UART_BASE[P.PA_BITS-1:0], P.UART_RANGE[P.PA_BITS-1:0], P.UART_SUPPORTED, AccessRW, Size, 4'b0001, SelRegions[4]);
adrdec #(P.PA_BITS) plicdec(PhysicalAddress, P.PLIC_BASE[P.PA_BITS-1:0], P.PLIC_RANGE[P.PA_BITS-1:0], P.PLIC_SUPPORTED, AccessRW, Size, 4'b0100, SelRegions[3]);
adrdec #(P.PA_BITS) sdcdec(PhysicalAddress, P.SDC_BASE[P.PA_BITS-1:0], P.SDC_RANGE[P.PA_BITS-1:0], P.SDC_SUPPORTED, AccessRW, Size, SUPPORTED_SIZE & 4'b1100, SelRegions[2]);
adrdec #(P.PA_BITS) spidec(PhysicalAddress, P.SPI_BASE[P.PA_BITS-1:0], P.SPI_RANGE[P.PA_BITS-1:0], P.SPI_SUPPORTED, AccessRW, Size, 4'b0100, SelRegions[1]);
assign SelRegions[0] = ~|(SelRegions[10:1]); // none of the regions are selected
assign SelRegions[0] = ~|(SelRegions[11:1]); // none of the regions are selected
endmodule
// verilator lint_on UNOPTFLAT

View File

@ -44,7 +44,7 @@ module pmachecker import cvw::*; #(parameter cvw_t P) (
logic PMAAccessFault;
logic AccessRW, AccessRWX, AccessRX;
logic [10:0] SelRegions;
logic [11:0] SelRegions;
logic AtomicAllowed;
logic CacheableRegion, IdempotentRegion;
@ -57,18 +57,18 @@ module pmachecker import cvw::*; #(parameter cvw_t P) (
adrdecs #(P) adrdecs(PhysicalAddress, AccessRW, AccessRX, AccessRWX, Size, SelRegions);
// Only non-core RAM/ROM memory regions are cacheable. PBMT can override cachable; NC and IO are uncachable
assign CacheableRegion = SelRegions[8] | SelRegions[7] | SelRegions[6]; // exclusion-tag: unused-cachable
assign CacheableRegion = SelRegions[9] | SelRegions[8] | SelRegions[7]; // exclusion-tag: unused-cachable
assign Cacheable = (PBMemoryType == 2'b00) ? CacheableRegion : 0;
// Nonidemdempotent means access could have side effect and must not be done speculatively or redundantly
// I/O is nonidempotent. PBMT can override PMA; NC is idempotent and IO is non-idempotent
assign IdempotentRegion = SelRegions[10] | SelRegions[9] | SelRegions[8] | SelRegions[7] | SelRegions[6]; // exclusion-tag: unused-idempotent
assign IdempotentRegion = SelRegions[11] | SelRegions[10] | SelRegions[9] | SelRegions[8] | SelRegions[7]; // exclusion-tag: unused-idempotent
assign Idempotent = (PBMemoryType == 2'b00) ? IdempotentRegion : (PBMemoryType == 2'b01);
// Atomic operations are only allowed on RAM
assign AtomicAllowed = SelRegions[10] | SelRegions[8] | SelRegions[6]; // exclusion-tag: unused-atomic
assign AtomicAllowed = SelRegions[11] | SelRegions[9] | SelRegions[7]; // exclusion-tag: unused-idempotent
// Check if tightly integrated memories are selected
assign SelTIM = SelRegions[10] | SelRegions[9]; // exclusion-tag: unused-tim
assign SelTIM = SelRegions[11] | SelRegions[10]; // exclusion-tag: unused-idempotent
// Detect access faults
assign PMAAccessFault = (SelRegions[0]) & AccessRWX | AtomicAccessM & ~AtomicAllowed;

View File

@ -49,7 +49,7 @@ module plic_apb import cvw::*; #(parameter cvw_t P) (
input logic PENABLE,
output logic [P.XLEN-1:0] PRDATA,
output logic PREADY,
input logic UARTIntr,GPIOIntr,SDCIntr,
input logic UARTIntr,GPIOIntr, SPIIntr, SDCIntr,
output logic MExtInt, SExtInt
);
@ -156,6 +156,7 @@ module plic_apb import cvw::*; #(parameter cvw_t P) (
requests = {P.PLIC_NUM_SRC{1'b0}};
if(P.PLIC_GPIO_ID != 0) requests[P.PLIC_GPIO_ID] = GPIOIntr;
if(P.PLIC_UART_ID != 0) requests[P.PLIC_UART_ID] = UARTIntr;
if(P.PLIC_SPI_ID != 0) requests[P.PLIC_SPI_ID] = SPIIntr;
if(P.PLIC_SDC_ID !=0) requests[P.PLIC_SDC_ID] = SDCIntr;
end

516
src/uncore/spi_apb.sv Normal file
View File

@ -0,0 +1,516 @@
///////////////////////////////////////////
// spi_apb.sv
//
// Written: Naiche Whyte-Aguayo nwhyteaguayo@g.hmc.edu 11/16/2022
//
// Purpose: SPI peripheral
// See FU540-C000-v1.0 for specifications
//
// A component of the Wally configurable RISC-V project.
//
// 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.
////////////////////////////////////////////////////////////////////////////////////////////////
// Current limitations: Flash read sequencer mode not implemented, dual and quad modes untestable with current test plan.
// Hardware interlock change to busy signal
// write tests for fifo full and empty watermark edge cases
// HoldModeDeassert make sure still works
// Comment on FIFOs: watermark calculations
// Comment all interface and internal signals on the lines they are declared
// Get tabs correct so things line up
// Relook at frame compare/ Delay count logic w/o multibit
// look at ReadIncrement/WriteIncrement delay necessity
// test case for two's complement rollover on fifo watermark calculation + watermark calc redesign
/* high level explanation of architecture
SPI module is written to the specifications described in FU540-C000-v1.0. At the top level, it is consists of synchronous 8 byte transmit and recieve FIFOs connected to shift registers.
The FIFOs are connected to WALLY by an apb bus control register interface, which includes various control registers for modifying the SPI transmission along with registers for writing
to the transmit FIFO and reading from the receive FIFO. The transmissions themselves are then controlled by a finite state machine. The SPI module uses 4 tristate pins for SPI input/output,
along with a 4 bit Chip Select signal, a clock signal, and an interrupt signal to WALLY.
*/
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
);
//SPI registers
logic [11:0] SckDiv;
logic [1:0] SckMode;
logic [1:0] ChipSelectID;
logic [3:0] ChipSelectDef;
logic [1:0] ChipSelectMode;
logic [15:0] Delay0, Delay1;
logic [4:0] Format;
logic [8:0] ReceiveData;
logic [8:0] ReceiveDataPlaceholder;
logic [2:0] TransmitWatermark, ReceiveWatermark;
logic [8:0] TransmitData;
logic [1:0] InterruptEnable, InterruptPending;
//bus interface signals
logic [7:0] Entry;
logic Memwrite;
logic [31:0] Din, Dout;
//FIFO FSM signals
logic TransmitWriteMark, TransmitReadMark, RecieveWriteMark, RecieveReadMark;
logic TransmitFIFOWriteFull, TransmitFIFOReadEmpty;
logic TransmitFIFOReadIncrement;
logic TransmitFIFOWriteIncrement;
logic ReceiveFIFOReadIncrement;
logic ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty;
logic [7:0] TransmitFIFOReadData, ReceiveFIFOWriteData;
logic [2:0] TransmitWriteWatermarkLevel, ReceiveReadWatermarkLevel;
logic TransmitFIFOReadEmptyDelay;
logic [7:0] ReceiveShiftRegEndian;
//transmission signals
logic sck;
logic [11:0] DivCounter;
logic SCLKenable;
logic [8:0] Delay0Count;
logic [8:0] Delay1Count;
logic Delay0Compare;
logic Delay1Compare;
logic InterCSCompare;
logic [8:0] InterCSCount;
logic InterXFRCompare;
logic [8:0] InterXFRCount;
logic [3:0] ChipSelectInternal;
logic [4:0] FrameCount;
logic [4:0] FrameCompare;
logic FrameCompareBoolean;
logic [4:0] ReceivePenultimateFrame;
logic [4:0] ReceivePenultimateFrameCount;
logic ReceivePenultimateFrameBoolean;
logic [4:0] FrameCompareProtocol;
logic ReceiveShiftFull;
logic TransmitShiftEmpty;
logic HoldModeDeassert;
//state fsm signals
logic Active;
logic Active0;
logic Inactive;
//shift reg signals
logic TransmitFIFOWriteIncrementDelay;
logic sckPhaseSelect;
logic [7:0] TransmitShiftReg;
logic [7:0] ReceiveShiftReg;
logic SampleEdge;
logic [7:0] TransmitDataEndian;
logic TransmitShiftRegLoad;
//CS signals
logic [3:0] ChipSelectAuto, ChipSelectHold, CSoff;
logic ChipSelectHoldSingle;
logic ReceiveShiftFullDelay;
logic SCLKenableDelay;
logic shiftin;
logic [7:0] ReceiveShiftRegInvert;
logic ZeroDelayHoldMode;
logic TransmitInactive;
logic SCLKenableEarly;
logic ReceiveShiftFullDelayPCLK;
logic [3:0] LeftShiftAmount;
logic [7:0] ASR; // AlignedReceiveShiftReg
logic DelayMode;
logic [3:0] PWChipSelect;
// 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 = 1'b1; // tie high if hardware interlock solution doesn't involve bus
//assign PREADY = TransmitInactive; // tie PREADY to transmission for hardware interlock
// account for subword read/write circuitry
// -- Note 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 *** clean this up
always_ff@(posedge PCLK, negedge PRESETn)
if (~PRESETn) begin
SckDiv <= #1 12'd3;
SckMode <= #1 2'b0;
ChipSelectID <= #1 2'b0;
ChipSelectDef <= #1 4'b1111;
ChipSelectMode <= #1 0;
Delay0 <= #1 {8'b1,8'b1};
Delay1 <= #1 {8'b0,8'b1};
Format <= #1 {5'b10000};
TransmitData <= #1 9'b0;
TransmitWatermark <= #1 3'b0;
ReceiveWatermark <= #1 3'b0;
InterruptEnable <= #1 2'b0;
InterruptPending <= #1 2'b0;
end else begin //writes
//According to FU540 spec: Once interrupt is pending, it will remain set until number
//of entries in tx/rx fifo is strictly more/less than tx/rxmark
/* verilator lint_off CASEINCOMPLETE */
if (Memwrite)
case(Entry) //flop to sample inputs
8'h00: SckDiv <= Din[11:0];
8'h04: SckMode <= Din[1:0];
8'h10: ChipSelectID <= Din[1:0];
8'h14: ChipSelectDef <= Din[3:0];
8'h18: ChipSelectMode <= Din[1:0];
8'h28: Delay0 <= {Din[23:16], Din[7:0]};
8'h2C: Delay1 <= {Din[23:16], Din[7:0]};
8'h40: Format <= {Din[19:16], Din[2]};
8'h48: if (~TransmitFIFOWriteFull) TransmitData[7:0] <= Din[7:0];
8'h50: TransmitWatermark <= Din[2:0];
8'h54: ReceiveWatermark <= Din[2:0];
8'h70: InterruptEnable <= Din[1:0];
endcase
/* verilator lint_off CASEINCOMPLETE */
//interrupt clearance
InterruptPending[0] <= TransmitReadMark;
InterruptPending[1] <= RecieveWriteMark;
case(Entry) // flop to sample inputs
8'h00: Dout <= #1 {20'b0, SckDiv};
8'h04: Dout <= #1 {30'b0, SckMode};
8'h10: Dout <= #1 {30'b0, ChipSelectID};
8'h14: Dout <= #1 {28'b0, ChipSelectDef};
8'h18: Dout <= #1 {30'b0, ChipSelectMode};
8'h28: Dout <= {8'b0, Delay0[15:8], 8'b0, Delay0[7:0]};
8'h2C: Dout <= {8'b0, Delay1[15:8], 8'b0, Delay1[7:0]};
8'h40: Dout <= {12'b0, Format[4:1], 13'b0, Format[0], 2'b0};
8'h48: Dout <= #1 {23'b0, TransmitFIFOWriteFull, 8'b0};
8'h4C: Dout <= #1 {23'b0, ReceiveFIFOReadEmpty, ReceiveData[7:0]};
8'h50: Dout <= #1 {29'b0, TransmitWatermark};
8'h54: Dout <= #1 {29'b0, ReceiveWatermark};
8'h70: Dout <= #1 {30'b0, InterruptEnable};
8'h74: Dout <= #1 {30'b0, InterruptPending};
default: Dout <= #1 32'b0;
endcase
end
// SPI enable generation, where SCLK = PCLK/(2*(SckDiv + 1))
// generates a high signal at the rising and falling edge of SCLK by counting from 0 to SckDiv
assign SCLKenable = (DivCounter == SckDiv);
assign SCLKenableEarly = ((DivCounter + 12'b1) == SckDiv);
always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) DivCounter <= #1 0;
else if (SCLKenable) DivCounter <= 0;
else DivCounter <= DivCounter + 12'b1;
//Boolean logic that tracks frame progression
assign FrameCompare = {1'b0,Format[4:1]};
assign FrameCompareBoolean = (FrameCount < FrameCompare);
assign ReceivePenultimateFrameCount = FrameCount + 5'b00001;
assign ReceivePenultimateFrameBoolean = (ReceivePenultimateFrameCount >= FrameCompare);
// 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 Delay0Compare = SckMode[0] ? (Delay0Count >= ({Delay0[7:0], 1'b0})) : (Delay0Count >= ({Delay0[7:0], 1'b0} + 9'b1));
assign Delay1Compare = SckMode[0] ? (Delay1Count >= (({Delay0[15:8], 1'b0}) + 9'b1)) : (Delay1Count >= ({Delay0[15:8], 1'b0}));
assign InterCSCompare = (InterCSCount >= ({Delay1[7:0],1'b0}));
assign InterXFRCompare = (InterXFRCount >= ({Delay1[15:8], 1'b0}));
//calculate when tx/rx shift registers are full/empty
TransmitShiftFSM TransmitShiftFSM_1 (PCLK, PRESETn, TransmitFIFOReadEmpty, ReceivePenultimateFrameBoolean, Active0, TransmitShiftEmpty);
ReceiveShiftFSM ReceiveShiftFSM_1 (PCLK, PRESETn, SCLKenable, ReceivePenultimateFrameBoolean, SampleEdge, SckMode[0], ReceiveShiftFull);
//calculate tx/rx fifo write and recieve increment signals
assign TransmitFIFOWriteIncrement = (Memwrite & (Entry == 8'h48) & ~TransmitFIFOWriteFull);
always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) TransmitFIFOWriteIncrementDelay <= 0;
else TransmitFIFOWriteIncrementDelay <= TransmitFIFOWriteIncrement;
always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) ReceiveFIFOReadIncrement <= 0;
else ReceiveFIFOReadIncrement <= ((Entry == 8'h4C) & ~ReceiveFIFOReadEmpty & PSEL & ~ReceiveFIFOReadIncrement);
//tx/rx FIFOs
SynchFIFO #(3,8) txFIFO(PCLK, 1'b1, SCLKenable, PRESETn, TransmitFIFOWriteIncrementDelay, TransmitShiftEmpty, TransmitData[7:0], TransmitWriteWatermarkLevel, TransmitWatermark[2:0], TransmitFIFOReadData[7:0], TransmitFIFOWriteFull, TransmitFIFOReadEmpty, TransmitWriteMark, TransmitReadMark);
SynchFIFO #(3,8) rxFIFO(PCLK, SCLKenable, 1'b1, PRESETn, ReceiveShiftFullDelay, ReceiveFIFOReadIncrement, ReceiveShiftRegEndian, ReceiveWatermark[2:0], ReceiveReadWatermarkLevel, ReceiveData[7:0], ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty, RecieveWriteMark, RecieveReadMark);
always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) TransmitFIFOReadEmptyDelay <= 1;
else if (SCLKenable) TransmitFIFOReadEmptyDelay <= TransmitFIFOReadEmpty;
always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) ReceiveShiftFullDelay <= 0;
else if (SCLKenable) ReceiveShiftFullDelay <= ReceiveShiftFull;
always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) ReceiveShiftFullDelayPCLK <= 0;
else if (SCLKenableEarly) ReceiveShiftFullDelayPCLK <= ReceiveShiftFull;
assign TransmitShiftRegLoad = ~TransmitShiftEmpty & ~Active | (((ChipSelectMode == 2'b10) & ~|(Delay1[15:8])) & ((ReceiveShiftFullDelay | ReceiveShiftFull) & ~SampleEdge & ~TransmitFIFOReadEmpty));
//Main FSM which controls SPI transmission
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, negedge PRESETn)
if (~PRESETn) begin state <= CS_INACTIVE;
FrameCount <= 5'b0;
/* verilator lint_off CASEINCOMPLETE */
end else if (SCLKenable) begin
case (state)
CS_INACTIVE: begin
Delay0Count <= 9'b1;
Delay1Count <= 9'b10;
FrameCount <= 5'b0;
InterCSCount <= 9'b10;
InterXFRCount <= 9'b1;
if ((~TransmitFIFOReadEmpty | ~TransmitShiftEmpty) & ((|(Delay0[7:0])) | ~SckMode[0])) state <= DELAY_0;
else if ((~TransmitFIFOReadEmpty | ~TransmitShiftEmpty)) state <= ACTIVE_0;
end
DELAY_0: begin
Delay0Count <= Delay0Count + 9'b1;
if (Delay0Compare) state <= ACTIVE_0;
end
ACTIVE_0: begin
FrameCount <= FrameCount + 5'b1;
state <= ACTIVE_1;
end
ACTIVE_1: begin
InterXFRCount <= 9'b1;
if (FrameCompareBoolean) state <= ACTIVE_0;
else if (HoldModeDeassert) state <= CS_INACTIVE;
else if ((ChipSelectMode[1:0] == 2'b10) & ~|(Delay1[15:8]) & (~TransmitFIFOReadEmpty)) begin
state <= ACTIVE_0;
Delay0Count <= 9'b1;
Delay1Count <= 9'b10;
FrameCount <= 5'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
Delay1Count <= Delay1Count + 9'b1;
if (Delay1Compare) state <= INTER_CS;
end
INTER_CS: begin
InterCSCount <= InterCSCount + 9'b1;
if (InterCSCompare ) state <= CS_INACTIVE;
end
INTER_XFR: begin
Delay0Count <= 9'b1;
Delay1Count <= 9'b10;
FrameCount <= 5'b0;
InterCSCount <= 9'b10;
InterXFRCount <= InterXFRCount + 9'b1;
if (HoldModeDeassert) state <= CS_INACTIVE;
else if (InterXFRCompare & ~TransmitFIFOReadEmptyDelay) state <= ACTIVE_0;
else if (~|ChipSelectMode[1:0]) state <= CS_INACTIVE;
end
endcase
end
/* verilator lint_off CASEINCOMPLETE */
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 sck = (state == ACTIVE_0) ? ~SckMode[1] : SckMode[1];
assign Active = (state == ACTIVE_0 | state == ACTIVE_1);
assign SampleEdge = SckMode[0] ? (state == ACTIVE_1) : (state == ACTIVE_0);
assign ZeroDelayHoldMode = ((ChipSelectMode == 2'b10) & (~|(Delay1[7:4])));
assign TransmitInactive = ((state == INTER_CS) | (state == CS_INACTIVE) | (state == INTER_XFR) | (ReceiveShiftFullDelayPCLK & ZeroDelayHoldMode));
assign Active0 = (state == ACTIVE_0);
assign Inactive = (state == CS_INACTIVE);
// Ensures that when ChipSelectMode = hold, CS pin is deasserted only when a different value is written to csmode or csid or a write to csdeg changes the state
// of the selected pin
assign PWChipSelect = PWDATA[3:0];
always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) HoldModeDeassert <= 0;
else if (~Inactive & ((ChipSelectMode[1:0] == 2'b10) & (Entry == (8'h18 | 8'h10) | ((Entry == 8'h14) & (PWChipSelect[ChipSelectID] != ChipSelectDef[ChipSelectID])))) & Memwrite) HoldModeDeassert <= 1;
// Signal tracks which edge of sck to shift data
always_comb
case(SckMode[1:0])
2'b00: sckPhaseSelect = ~sck & SCLKenable;
2'b01: sckPhaseSelect = (sck & |(FrameCount) & SCLKenable);
2'b10: sckPhaseSelect = sck & SCLKenable;
2'b11: sckPhaseSelect = (~sck & |(FrameCount) & SCLKenable);
default: sckPhaseSelect = sck & SCLKenable;
endcase
//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, negedge PRESETn)
if(~PRESETn) TransmitShiftReg <= 8'b0;
else if (TransmitShiftRegLoad) TransmitShiftReg <= TransmitDataEndian;
else if (sckPhaseSelect & Active) TransmitShiftReg <= {TransmitShiftReg[6:0], 1'b0};
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, negedge PRESETn)
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]};
endcase
assign SPICS = ChipSelectMode[0] ? ChipSelectDef : ChipSelectAuto;
endmodule
module SynchFIFO #(parameter M =3 , N= 8)(
input logic PCLK, wen, ren, PRESETn,
input logic winc,rinc,
input logic [N-1:0] wdata,
input logic [M-1:0] wwatermarklevel, rwatermarklevel,
output logic [N-1:0] rdata,
output logic wfull, rempty,
output logic wwatermark, rwatermark);
logic [N-1:0] mem[2**M];
logic [M:0] rptr, wptr;
logic [M:0] rptrnext, wptrnext;
logic rempty_val;
logic wfull_val;
logic [M-1:0] raddr;
logic [M-1:0] waddr;
assign rdata = mem[raddr];
always_ff @(posedge PCLK)
if (winc & ~wfull) mem[waddr] <= wdata;
// write and read are enabled
always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) begin
rptr <= 0;
wptr <= 0;
wfull <= 1'b0;
rempty <= 1'b1;
end
else begin
if (wen) begin
wfull <= wfull_val;
wptr <= wptrnext;
end
if (ren) begin
rptr <= rptrnext;
rempty <= rempty_val;
end
end
assign raddr = rptr[M-1:0];
assign rptrnext = rptr + {3'b0, (rinc & ~rempty)};
assign rempty_val = (wptr == rptrnext);
assign rwatermark = ((raddr - waddr) < rwatermarklevel);
assign waddr = wptr[M-1:0];
assign wwatermark = ((waddr - raddr) > wwatermarklevel);
assign wptrnext = wptr + {3'b0, (winc & ~wfull)};
assign wfull_val = ({~wptrnext[M], wptrnext[M-1:0]} == rptr);
endmodule
module TransmitShiftFSM(
input logic PCLK, PRESETn,
input logic TransmitFIFOReadEmpty, ReceivePenultimateFrameBoolean, Active0,
output logic TransmitShiftEmpty);
typedef enum logic [1:0] {TransmitShiftEmptyState, TransmitShiftHoldState, TransmitShiftNotEmptyState} statetype;
statetype TransmitState, TransmitNextState;
always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) TransmitState <= TransmitShiftEmptyState;
else TransmitState <= TransmitNextState;
always_comb
case(TransmitState)
TransmitShiftEmptyState: begin
if (TransmitFIFOReadEmpty | (~TransmitFIFOReadEmpty & (ReceivePenultimateFrameBoolean & Active0))) TransmitNextState = TransmitShiftEmptyState;
else if (~TransmitFIFOReadEmpty) TransmitNextState = TransmitShiftNotEmptyState;
end
TransmitShiftNotEmptyState: begin
if (ReceivePenultimateFrameBoolean & Active0) TransmitNextState = TransmitShiftEmptyState;
else TransmitNextState = TransmitShiftNotEmptyState;
end
endcase
assign TransmitShiftEmpty = (TransmitNextState == TransmitShiftEmptyState);
endmodule
module ReceiveShiftFSM(
input logic PCLK, PRESETn, SCLKenable,
input logic ReceivePenultimateFrameBoolean, SampleEdge, SckMode,
output logic ReceiveShiftFull
);
typedef enum logic [1:0] {ReceiveShiftFullState, ReceiveShiftNotFullState, ReceiveShiftDelayState} statetype;
statetype ReceiveState, ReceiveNextState;
always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) ReceiveState <= ReceiveShiftNotFullState;
else if (SCLKenable) begin
case (ReceiveState)
ReceiveShiftFullState: ReceiveState <= ReceiveShiftNotFullState;
ReceiveShiftNotFullState: if (ReceivePenultimateFrameBoolean & (SampleEdge)) ReceiveState <= ReceiveShiftDelayState;
else ReceiveState <= ReceiveShiftNotFullState;
ReceiveShiftDelayState: ReceiveState <= ReceiveShiftFullState;
endcase
end
assign ReceiveShiftFull = SckMode ? (ReceiveState == ReceiveShiftFullState) : (ReceiveState == ReceiveShiftDelayState);
endmodule

View File

@ -54,28 +54,31 @@ module uncore import cvw::*; #(parameter cvw_t P)(
output logic [31:0] GPIOOUT, GPIOEN, // GPIO pin output value and enable
input logic UARTSin, // UART serial input
output logic UARTSout, // UART serial output
input logic SDCIntr
input logic SDCIntr,
input logic SPIIn,
output logic SPIOut,
output logic [3:0] SPICS
);
logic [P.XLEN-1:0] HREADRam, HREADSDC;
logic [10:0] HSELRegions;
logic HSELDTIM, HSELIROM, HSELRam, HSELCLINT, HSELPLIC, HSELGPIO, HSELUART, HSELSDC;
logic HSELDTIMD, HSELIROMD, HSELEXTD, HSELRamD, HSELCLINTD, HSELPLICD, HSELGPIOD, HSELUARTD;
logic [11:0] HSELRegions;
logic HSELDTIM, HSELIROM, HSELRam, HSELCLINT, HSELPLIC, HSELGPIO, HSELUART, HSELSDC, HSELSPI;
logic HSELDTIMD, HSELIROMD, HSELEXTD, HSELRamD, HSELCLINTD, HSELPLICD, HSELGPIOD, HSELUARTD, HSELSDCD, HSELSPID;
logic HRESPRam, HRESPSDC;
logic HREADYRam, HRESPSDCD;
logic [P.XLEN-1:0] HREADBootRom;
logic HSELBootRom, HSELBootRomD, HRESPBootRom, HREADYBootRom, HREADYSDC;
logic HSELNoneD;
logic UARTIntr,GPIOIntr;
logic UARTIntr,GPIOIntr, SPIIntr;
logic SDCIntM;
logic PCLK, PRESETn, PWRITE, PENABLE;
logic [3:0] PSEL, PREADY;
logic [4:0] PSEL, PREADY;
logic [31:0] PADDR;
logic [P.XLEN-1:0] PWDATA;
logic [P.XLEN/8-1:0] PSTRB;
logic [3:0][P.XLEN-1:0] PRDATA;
logic [4:0][P.XLEN-1:0] PRDATA;
logic [P.XLEN-1:0] HREADBRIDGE;
logic HRESPBRIDGE, HREADYBRIDGE, HSELBRIDGE, HSELBRIDGED;
@ -88,14 +91,14 @@ module uncore import cvw::*; #(parameter cvw_t P)(
adrdecs #(P) adrdecs(HADDR, 1'b1, 1'b1, 1'b1, HSIZE[1:0], HSELRegions);
// unswizzle HSEL signals
assign {HSELDTIM, HSELIROM, HSELEXT, HSELBootRom, HSELRam, HSELCLINT, HSELGPIO, HSELUART, HSELPLIC, HSELEXTSDC} = HSELRegions[10:1];
assign {HSELDTIM, HSELIROM, HSELEXT, HSELBootRom, HSELRam, HSELCLINT, HSELGPIO, HSELUART, HSELPLIC, HSELSDC, HSELSPI} = HSELRegions[11:1];
// AHB -> APB bridge
ahbapbbridge #(P, 4) ahbapbbridge (
.HCLK, .HRESETn, .HSEL({HSELUART, HSELPLIC, HSELCLINT, HSELGPIO}), .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HTRANS, .HREADY,
ahbapbbridge #(P, 5) ahbapbbridge (
.HCLK, .HRESETn, .HSEL({HSELSPI, HSELUART, HSELPLIC, HSELCLINT, HSELGPIO}), .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HTRANS, .HREADY,
.HRDATA(HREADBRIDGE), .HRESP(HRESPBRIDGE), .HREADYOUT(HREADYBRIDGE),
.PCLK, .PRESETn, .PSEL, .PWRITE, .PENABLE, .PADDR, .PWDATA, .PSTRB, .PREADY, .PRDATA);
assign HSELBRIDGE = HSELGPIO | HSELCLINT | HSELPLIC | HSELUART; // if any of the bridge signals are selected
assign HSELBRIDGE = HSELGPIO | HSELCLINT | HSELPLIC | HSELUART | HSELSPI; // if any of the bridge signals are selected
// on-chip RAM
if (P.UNCORE_RAM_SUPPORTED) begin : ram
@ -121,7 +124,7 @@ module uncore import cvw::*; #(parameter cvw_t P)(
if (P.PLIC_SUPPORTED == 1) begin : plic
plic_apb #(P) plic(.PCLK, .PRESETn, .PSEL(PSEL[2]), .PADDR(PADDR[27:0]), .PWDATA, .PSTRB, .PWRITE, .PENABLE,
.PRDATA(PRDATA[2]), .PREADY(PREADY[2]), .UARTIntr, .GPIOIntr, .SDCIntr, .MExtInt, .SExtInt);
.PRDATA(PRDATA[2]), .PREADY(PREADY[2]), .UARTIntr, .GPIOIntr, .SDCIntr, .SPIIntr, .MExtInt, .SExtInt);
end else begin : plic
assign MExtInt = 0;
assign SExtInt = 0;
@ -145,6 +148,14 @@ module uncore import cvw::*; #(parameter cvw_t P)(
end else begin : uart
assign UARTSout = 0; assign UARTIntr = 0;
end
if (P.SPI_SUPPORTED == 1) begin : spi
spi_apb #(P) spi (
.PCLK, .PRESETn, .PSEL(PSEL[4]), .PADDR(PADDR[7:0]), .PWDATA, .PSTRB, .PWRITE, .PENABLE,
.PREADY(PREADY[4]), .PRDATA(PRDATA[4]),
.SPIOut, .SPIIn, .SPICS, .SPIIntr);
end else begin : spi
assign SPIOut = 0; assign SPICS = 0; assign SPIIntr = 0;
end
// AHB Read Multiplexer
assign HRDATA = ({P.XLEN{HSELRamD}} & HREADRam) |
@ -168,6 +179,8 @@ module uncore import cvw::*; #(parameter cvw_t P)(
// takes more than 1 cycle to repsond it needs to hold on to the old select until the
// device is ready. Hense this register must be selectively enabled by HREADY.
// However on reset None must be seleted.
flopenl #(11) hseldelayreg(HCLK, ~HRESETn, HREADY, HSELRegions, 11'b1, {HSELDTIMD, HSELIROMD, HSELEXTD, HSELBootRomD, HSELRamD, HSELCLINTD, HSELGPIOD, HSELUARTD, HSELPLICD, HSELEXTSDCD, HSELNoneD});
flopenl #(12) hseldelayreg(HCLK, ~HRESETn, HREADY, HSELRegions, 12'b1,
{HSELDTIMD, HSELIROMD, HSELEXTD, HSELBootRomD, HSELRamD,
HSELCLINTD, HSELGPIOD, HSELUARTD, HSELPLICD, HSELEXTSDCD, HSELSPID, HSELNoneD});
flopenr #(1) hselbridgedelayreg(HCLK, ~HRESETn, HREADY, HSELBRIDGE, HSELBRIDGED);
endmodule

View File

@ -54,11 +54,14 @@ module wallypipelinedsoc import cvw::*; #(parameter cvw_t P) (
output logic [31:0] GPIOEN, // output enables for GPIO
input logic UARTSin, // UART serial data input
output logic UARTSout, // UART serial data output
input logic SDCIntr
input logic SDCIntr,
input logic SPIIn, // SPI pins in
output logic SPIOut, // SPI pins out
output logic [3:0] SPICS // SPI chip select pins
);
// Uncore signals
logic [P.AHBW-1:0] HRDATA; // from AHB mux in uncore
logic [P.AHBW-1:0] HRDATA; // from AHB mux in uncore
logic HRESP; // response from AHB
logic MTimerInt, MSwInt;// timer and software interrupts from CLINT
logic [63:0] MTIME_CLINT; // from CLINT to CSRs
@ -80,7 +83,7 @@ module wallypipelinedsoc import cvw::*; #(parameter cvw_t P) (
.HADDR, .HWDATA, .HWSTRB, .HWRITE, .HSIZE, .HBURST, .HPROT, .HTRANS, .HMASTLOCK, .HRDATAEXT,
.HREADYEXT, .HRESPEXT, .HRDATA, .HREADY, .HRESP, .HSELEXT, .HSELEXTSDC,
.MTimerInt, .MSwInt, .MExtInt, .SExtInt, .GPIOIN, .GPIOOUT, .GPIOEN, .UARTSin,
.UARTSout, .MTIME_CLINT, .SDCIntr);
.UARTSout, .MTIME_CLINT, .SDCIntr, .SPIIn, .SPIOut, .SPICS);
end
endmodule

View File

@ -64,7 +64,8 @@ module testbench;
logic [31:0] GPIOIN, GPIOOUT, GPIOEN;
logic UARTSin, UARTSout;
logic SPIIn, SPIOut;
logic [3:0] SPICS;
logic SDCIntr;
logic HREADY;
@ -367,6 +368,7 @@ module testbench;
// instantiate device to be tested
assign GPIOIN = 0;
assign UARTSin = 1;
assign SPIIn = 0;
if(P.EXT_MEM_SUPPORTED) begin
ram_ahb #(.BASE(P.EXT_MEM_BASE), .RANGE(P.EXT_MEM_RANGE))
@ -397,7 +399,7 @@ module testbench;
wallypipelinedsoc #(P) dut(.clk, .reset_ext, .reset, .HRDATAEXT, .HREADYEXT, .HRESPEXT, .HSELEXT, .HSELEXTSDC,
.HCLK, .HRESETn, .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HSIZE, .HBURST, .HPROT,
.HTRANS, .HMASTLOCK, .HREADY, .TIMECLK(1'b0), .GPIOIN, .GPIOOUT, .GPIOEN,
.UARTSin, .UARTSout, .SDCIntr);
.UARTSin, .UARTSout, .SDCIntr, .SPIIn, .SPIOut, .SPICS);
// generate clock to sequence tests
always begin

View File

@ -2009,7 +2009,8 @@ string arch64zbs[] = '{
"rv64i_m/privilege/src/WALLY-gpio-01.S",
"rv64i_m/privilege/src/WALLY-plic-01.S",
"rv64i_m/privilege/src/WALLY-plic-s-01.S",
"rv64i_m/privilege/src/WALLY-uart-01.S"
"rv64i_m/privilege/src/WALLY-uart-01.S",
"rv64i_m/privilege/src/WALLY-spi-01.S"
};
string wally32e[] = '{
@ -2095,7 +2096,8 @@ string arch64zbs[] = '{
"rv32i_m/privilege/src/WALLY-clint-01.S",
"rv32i_m/privilege/src/WALLY-uart-01.S",
"rv32i_m/privilege/src/WALLY-plic-01.S",
"rv32i_m/privilege/src/WALLY-plic-s-01.S"
"rv32i_m/privilege/src/WALLY-plic-s-01.S",
"rv32i_m/privilege/src/WALLY-spi-01.S"
};

View File

@ -51,6 +51,8 @@ module wallywrapper;
logic [31:0] GPIOIN, GPIOOUT, GPIOEN;
logic UARTSin, UARTSout;
logic SPIIn, SPIOut;
logic [3:0] SPICS;
logic SDCIntr;
logic HREADY;
@ -70,6 +72,6 @@ module wallywrapper;
wallypipelinedsoc #(P) dut(.clk, .reset_ext, .reset, .HRDATAEXT,.HREADYEXT, .HRESPEXT,.HSELEXT, .HSELEXTSDC,
.HCLK, .HRESETn, .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HSIZE, .HBURST, .HPROT,
.HTRANS, .HMASTLOCK, .HREADY, .TIMECLK(1'b0), .GPIOIN, .GPIOOUT, .GPIOEN,
.UARTSin, .UARTSout, .SDCIntr);
.UARTSin, .UARTSout, .SPIIn, .SPIOut, .SPICS, .SDCIntr);
endmodule

View File

@ -56,6 +56,7 @@ target_tests_nosim = \
WALLY-clint-01 \
WALLY-plic-01 \
WALLY-uart-01 \
WALLY-spi-01 \
WALLY-cbom-01 \
WALLY-cboz-01 \

View File

@ -0,0 +1,193 @@
00000003 # reset tests sck_div
00000000 # sck_mode
00000000 # cs_id
0000000F # cs_def
00000000 # cs_mode
00010001 # delay 0
00000001 # delay 1
00080000 # fmt
00000000 # tx_data
00000000 # tx_mark
00000000 # rx_mark
00000000 # ie reset
00000000 # ip reset
00000011 #basic read write
000000FF
000000A0
0000000B
00000079
00000000
000000C0
00000011
00000020 #delay registers
00000032
00000048
000000AF
00000050
0000006B
00000011
00000015
00000011 #delay1
00000022
00000033
00000044
0000007B
00000021
00000032
00000043
00000054
00000066
00000077
00000088
00000099
00000066
00000077
00000088
00000099
00000065
00000076
00000087
00000098
00000048
000000DD
000000CC
000000BB
000000AA
000000DE
000000CD
000000BC
000000AB
000000F0 #fmt register
00000000
00000080
00000000
00000080
000000A8
000000F8
00000048
00000070
00000000
00000008
00000003
00000017
0000000F
0000001F
00000001 #watermark interrupts
00000000 #read mip
00000000 #read tx ip
00000022 #clear 1 frame from rx fifo
00000000 # read recieve ip
00000002 #read recieve ip
00000000 #read mip
00000033 #clear frame
00000000 # read receive ip
00000044 #clear frame
00000055 #clear frame
00000001 #read tx ip
00000800 #read mip 11
00000000 #read tx wm 10
00000000 #read mip 91 9
00000022 #clear frame 8
00000000 #read rx ip 7
00000000 #read mip 94 6
00000002 #read rx ip 5
00000800 #read mip 4
00000033 #clear frame 3
00000000 #read rx wm 2
00000000 #read mip 99 1

View File

@ -865,6 +865,7 @@ trap_handler_end_\MODE\(): // place to jump to so we can skip the trap handler a
.equ PLIC_INTPRI_GPIO, 0x0C00000C # GPIO is interrupt 3
.equ PLIC_INTPRI_UART, 0x0C000028 # UART is interrupt 10
.equ PLIC_INTPRI_SPI, 0x0C000018 # SPI in interrupt 6
.equ PLIC_INTPENDING0, 0x0C001000 # intPending0 register
.equ PLIC_INTEN00, 0x0C002000 # interrupt enables for context 0 (machine mode) sources 31:1
.equ PLIC_INTEN10, 0x0C002080 # interrupt enables for context 1 (supervisor mode) sources 31:1
@ -877,6 +878,7 @@ trap_handler_end_\MODE\(): // place to jump to so we can skip the trap handler a
.4byte PLIC_THRESH1, 7, write32_test # Set PLIC supervisor mode interrupt threshold to 7 to accept no interrupts
.4byte PLIC_INTPRI_GPIO, 7, write32_test # Set GPIO to high priority
.4byte PLIC_INTPRI_UART, 7, write32_test # Set UART to high priority
.4byte PLIC_INTPRI_SPI, 7, write32_test # Set UART to high priority
.4byte PLIC_INTEN00, 0xFFFFFFFF, write32_test # Enable all interrupt sources for machine mode
.4byte PLIC_INTEN10, 0x00000000, write32_test # Disable all interrupt sources for supervisor mode
.endm
@ -1028,6 +1030,12 @@ claim_m_plic_interrupts: // clears one non-pending PLIC interrupt
sw t3, 0(t2)
sw t4, -4(sp)
addi sp, sp, -4
li t2, 0x0C000018 // SPI priority
li t3, 7
lw t4, 0(t2)
sw t3, 0(t2)
sw t4, -4(sp)
addi sp, sp, -4
li t2, 0x0C002000
li t3, 0x0C200004
li t4, 0xFFF
@ -1038,11 +1046,14 @@ claim_m_plic_interrupts: // clears one non-pending PLIC interrupt
sw t6, 0(t2) // restore saved enable status
li t2, 0x0C00000C // GPIO priority
li t3, 0x0C000028 // UART priority
lw t4, 4(sp) // load stored GPIO and UART priority
lw t5, 0(sp)
addi sp, sp, 8 // restore stack pointer
sw t4, 0(t2)
sw t5, 0(t3)
li t6, 0x0C000018 // SPI priority
lw a4, 8(sp) // load stored GPIO prioroty
lw t4, 4(sp) // load stored UART priority
lw t5, 0(sp) // load stored SPI priority
addi sp, sp, 12 // restore stack pointer
sw a4, 0(t2)
sw t4, 0(t3)
sw t5, 0(t6)
j test_loop
claim_s_plic_interrupts: // clears one non-pending PLIC interrupt
@ -1128,6 +1139,34 @@ uart_clearmodemintr:
lb t2, 0(t2)
j test_loop
spi_data_wait:
li t2, 0x10040054
sw t4, 0(t2) // set rx watermark level
li t2, 0x10040074
lw t3, 0(t2) //read ip (interrupt pending register)
slli t3, t3, 28
srli t3, t3, 28
li t2, 0x00000002
bge t3, t2, spi_data_ready //branch to done if transmission complete
j spi_data_wait //else check again
spi_data_ready:
li t2, 0x10040070
li t3, 0x00000000
sw t3, 0(t2) //disable rx watermark interrupt
j test_loop
spi_burst_send: //function for loading multiple frames at once to test delays without returning to test loop
mv t2, t4
sw t2, 0(t3)
srli t2, t2, 8
sw t2, 0(t3)
srli t2, t2, 8
sw t2, 0(t3)
srli t2, t2, 8
sw t2, 0(t3)
j test_loop
goto_s_mode:
// return to address in t3,
li a0, 3 // Trap handler behavior (go to supervisor mode)

View File

@ -0,0 +1,511 @@
///////////////////////////////////////////
//
// WALLY-spi
//
// Author: David_Harris@hmc.edu and Naiche Whyte-Aguayo
//
// Created 2023-02-01
//
// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
// OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
///////////////////////////////////////////
#include "WALLY-TEST-LIB-32.h"
RVTEST_ISA("RV32I_Zicsr_Zifencei")
RVTEST_CASE(0,"//check ISA:=regex(.*32.*);check ISA:=regex(.*I.*); def Drvtest_mtrap_routine=True;def TEST_CASE_1=True;def NO_SAIL=True;",spi)
INIT_TESTS
TRAP_HANDLER m
j run_test_loop // begin test loop/table tests instead of executing inline code.
INIT_TEST_TABLE
END_TESTS
TEST_STACK_AND_DATA
.align 2
test_cases:
# ---------------------------------------------------------------------------------------------
# Test Contents
#
# Here is where the actual tests are held, or rather, what the actual tests do.
# each entry consists of 3 values that will be read in as follows:
#
# '.4byte [x28 Value], [x29 Value], [x30 value]'
# or
# '.4byte [address], [value], [test type]'
#
# The encoding for x30 test type values can be found in the test handler in the framework file
# ---------------------------------------------------------------------------------------------
.equ SPI, 0x10040000
.equ sck_div, (SPI+0x00)
.equ sck_mode, (SPI+0x04)
.equ cs_id, (SPI+0x10)
.equ cs_def, (SPI+0x14)
.equ cs_mode, (SPI+0x18)
.equ delay0, (SPI+0x28)
.equ delay1, (SPI+0x2C)
.equ fmt, (SPI+0x40)
.equ tx_data, (SPI+0x48)
.equ rx_data, (SPI+0x4C)
.equ tx_mark, (SPI+0x50)
.equ rx_mark, (SPI+0x54)
.equ ie, (SPI+0x70)
.equ ip, (SPI+0x74)
test_cases:
# ---------------------------------------------------------------------------------------------
# Test Contents
#
# Here is where the actual tests are held, or rather, what the actual tests do.
# each entry consists of 3 values that will be read in as follows:
#
# '.4byte [x28 Value], [x29 Value], [x30 value]'
# or
# '.4byte [address], [value], [test type]'
#
# The encoding for x30 test type values can be found in the test handler in the framework file
# ---------------------------------------------------------------------------------------------
.equ SPI, 0x10040000
.equ sck_div, (SPI+0x00)
.equ sck_mode, (SPI+0x04)
.equ cs_id, (SPI+0x10)
.equ cs_def, (SPI+0x14)
.equ cs_mode, (SPI+0x18)
.equ delay0, (SPI+0x28)
.equ delay1, (SPI+0x2C)
.equ fmt, (SPI+0x40)
.equ tx_data, (SPI+0x48)
.equ rx_data, (SPI+0x4C)
.equ tx_mark, (SPI+0x50)
.equ rx_mark, (SPI+0x54)
.equ ie, (SPI+0x70)
.equ ip, (SPI+0x74)
# =========== Verify all registers reset to correct values ===========
.4byte sck_div, 0x00000003, read32_test # sck_div reset to 0x3
.4byte sck_mode, 0x00000000, read32_test # sck_mode reset to 0x0
.4byte cs_id, 0x00000000, read32_test # cs_id reset to 0x0
.4byte cs_def, 0x0000000F, read32_test # cs_def reset to 0x1
.4byte cs_mode, 0x00000000, read32_test # cs_mode reset to 0x0
.4byte delay0, 0x00010001, read32_test # delay0 reset to [31:24] 0x0, [23:16] 0x1, [15:8] 0x0, [7:0] 0x1
.4byte delay1, 0x00000001, read32_test # delay1 reset to 0x1
.4byte fmt, 0x00080000, read32_test # fmt reset to [31:20] 0x0, [19:16] 0x8, [15:0] 0x0 for non-flash enabled SPI controllers
.4byte tx_data, 0x00000000, read32_test # tx_data [30:0] reset to 0x0, [31] read only
.4byte tx_mark, 0x00000000, read32_test # tx_mark reset to 0x0 for non-flash enabled controllers
.4byte rx_mark, 0x00000000, read32_test # rx_mark reset to 0x0
.4byte ie, 0x00000000, read32_test # ie reset to 0x0
.4byte ip, 0x00000000, read32_test # ip reset to 0x0
# =========== Basic read-write ===========
.4byte tx_data, 0x000000011, write32_test # place 8'h11 into tx_data
.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.4byte rx_data, 0x00000011, read32_test # read rx_data
# =========== Different cs_mode, sck_mode, cs_def, sck_div ===========
# Test sck_div
.4byte sck_div, 0x00000101, write32_test # set sck_div to 0x101
.4byte tx_data, 0x000000FF, write32_test # place 8'h11 into tx_data
.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.4byte rx_data, 0x000000FF, read32_test # read rx_data
# Test phase
.4byte sck_div, 0x00000003, write32_test # reset sck_div to 0x03 so only sck_mode is different
.4byte sck_mode, 0x00000001, write32_test # change phase to falling edge
.4byte tx_data, 0x000000A0, write32_test # place 8'h11 into tx_data
.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.4byte rx_data, 0x000000A0, read32_test # read rx_data
# Test polarity
.4byte sck_mode, 0x00000000, write32_test # reset sck phase to rising edge
.4byte sck_mode, 0x00000002, write32_test # set sck polarity active low
.4byte tx_data, 0x0000000B, write32_test # place 8'h11 into tx_data
.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.4byte rx_data, 0x0000000B, read32_test # read rx_data
# Test chip select polarity
.4byte sck_mode, 0x00000000, write32_test # reset sck polarity to active high
.4byte cs_def, 0x0000000E, write32_test # set cs[0] to inactive low
.4byte tx_data, 0x00000079, write32_test # place 8'h11 into tx_data
.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.4byte rx_data, 0x00000079, read32_test # read rx_data
# Test chip id
.4byte cs_def, 0x0000000F, write32_test # reset all cs to active low
.4byte cs_id, 0x00000001, write32_test # select cs[1]
.4byte tx_data, 0x00000000, write32_test # place 8'h11 into tx_data
.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.4byte rx_data, 0x00000000, read32_test # read rx_data
# Test cs hold mode
.4byte cs_id, 0x00000000, write32_test # select cs[0]
.4byte cs_mode, 0x00000002, write32_test # set cs_mode to HOLD
.4byte tx_data, 0x000000C0, write32_test # place 8'h11 into tx_data
.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.4byte rx_data, 0x000000C0, read32_test # read rx_data
# Test cs OFF mode
.4byte cs_mode, 0x00000003, write32_test # set cs_mode to OFF
.4byte tx_data, 0x00000011, write32_test # place 8'h11 into tx_data
.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.4byte rx_data, 0x00000011, read32_test # read rx_data
# =========== Test delay0 register ===========
# Test cs-sck delay of 0 with sck phase = 0 (implicit half cycle delay)
.4byte cs_mode, 0x00000000, write32_test # reset cs_mode to auto, all cs and sck mode settings should be defualt
.4byte delay0, 0x00010000, write32_test # set cs-sck delay to 0
.4byte tx_data, 0x00000020, write32_test # place 8'h11 into tx_data
.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.4byte rx_data, 0x00000020, read32_test # read rx_data
# Test cs-sck delay of 0 with sck phase 1 (no delay)
.4byte sck_mode, 0x00000001, write32_test # set sck_mode[0] to 1 (sck phase = 1)
.4byte tx_data, 0x00000032, write32_test # place 8'h11 into tx_data
.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.4byte rx_data, 0x00000032, read32_test # read rx_data
# Test arbitrary cs-sck delay (sck phase 1)
.4byte delay0, 0x00010005, write32_test # set cs-sck delay to 5 cycles
.4byte tx_data, 0x00000048, write32_test # place 8'h11 into tx_data
.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.4byte rx_data, 0x00000048, read32_test # read rx_data
# Test arbitrary cs-sck delay (sck phase 0)
.4byte sck_mode, 0x00000000, write32_test # set sck phase to 0
.4byte delay0, 0x00010005, write32_test # set cs-sck delay to AF cycles
.4byte tx_data, 0x000000AF, write32_test # place 8'h11 into tx_data
.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.4byte rx_data, 0x000000AF, read32_test # read rx_data
# Test sck-cs delay of 0 with sck phase = 0 (no delay)
.4byte delay0, 0x00000001, write32_test # set cs-sck delay to 0
.4byte tx_data, 0x00000050, write32_test # place 8'h11 into tx_data
.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.4byte rx_data, 0x00000050, read32_test # read rx_data
# Test sck-cs delay of 0 with sck phase 1 (implicit half cycle delay)
.4byte sck_mode, 0x00000001, write32_test # set sck_mode[0] to 1 (sck phase = 1)
.4byte tx_data, 0x0000006B, write32_test # place 8'h11 into tx_data
.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.4byte rx_data, 0x0000006B, read32_test # read rx_data
# Test arbitrary sck-cs delay (sck phase 1)
.4byte delay0, 0x00000501, write32_test # set cs-sck delay to A5 cycles
.4byte tx_data, 0x00000011, write32_test # place 8'h11 into tx_data
.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.4byte rx_data, 0x00000011, read32_test # read rx_data
# Test arbitrary sck-cs delay (sck phase 0)
.4byte sck_mode, 0x00000000, write32_test # set sck phase to 0
.4byte delay0, 0x00050001, write32_test # set cs-sck delay to 5 cycles
.4byte tx_data, 0x00000015, write32_test # place 8'h11 into tx_data
.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.4byte rx_data, 0x00000015, read32_test # read rx_data
# =========== Test delay1 register ===========
# Test inter cs delay
.4byte delay0, 0x00010001, write32_test # reset delay0 register
.4byte delay1, 0x00000005, write32_test # set inter_cs delay to 5
.4byte tx_data, 0x44332211, spi_burst_send
.4byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end
.4byte rx_data, 0x00000011, read32_test
.4byte rx_data, 0x00000022, read32_test
.4byte rx_data, 0x00000033, read32_test
.4byte rx_data, 0x00000044, read32_test
#test long inter_cs delay
.4byte delay1, 0x000000A5, write32_test
.4byte tx_data, 0x0000007B, write32_test
.4byte 0x0, 0x00000000, spi_data_wait
.4byte rx_data, 0x0000007B, read32_test
# Test inter_cs delay set to 0
.4byte delay1, 0x00000000, write32_test # set inter_cs delay to 5
.4byte tx_data, 0x54433221, spi_burst_send
.4byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end
.4byte rx_data, 0x00000021, read32_test
.4byte rx_data, 0x00000032, read32_test
.4byte rx_data, 0x00000043, read32_test
.4byte rx_data, 0x00000054, read32_test
# Test inter_xfr delay of 0 (maybe change behavior to half-period instead of period)
.4byte delay1, 0x00000001, write32_test # reset inter_cs delay to 1
.4byte cs_mode, 0x00000002, write32_test # set cs_mode to HOLD
.4byte tx_data, 0x99887766, spi_burst_send
.4byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end
.4byte rx_data, 0x00000066, read32_test
.4byte rx_data, 0x00000077, read32_test
.4byte rx_data, 0x00000088, read32_test
.4byte rx_data, 0x00000099, read32_test
# Test inter_xfr delay 0 with phase = 1
.4byte sck_mode, 0x00000001, write32_test
.4byte tx_data, 0x99887766, spi_burst_send
.4byte 0x0, 0x00000003, spi_data_wait
.4byte rx_data, 0x00000066, read32_test
.4byte rx_data, 0x00000077, read32_test
.4byte rx_data, 0x00000088, read32_test
.4byte rx_data, 0x00000099, read32_test
# Test arbitrary inter_xfr delay
.4byte delay1, 0x00050001, write32_test # set inter_xfr delay to 5
.4byte sck_mode, 0x00000001, write32_test
.4byte tx_data, 0x98877665, spi_burst_send
.4byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end
.4byte rx_data, 0x00000065, read32_test
.4byte rx_data, 0x00000076, read32_test
.4byte rx_data, 0x00000087, read32_test
.4byte rx_data, 0x00000098, read32_test
# test long inter_xfr delay
.4byte delay1, 0x00A50001, write32_test
.4byte tx_data, 0x00000048, write32_test
.4byte 0x0, 0x00000000, spi_data_wait
.4byte rx_data, 0x00000048, read32_test
# Test cs-sck delay with cs_mode = HOLD
.4byte delay1, 0x00000001, write32_test # set inter_xfr delay to 0
.4byte delay0, 0x00010005, write32_test # set cs-sck delay to 5 (should have no effect because cs is never inactive)
.4byte tx_data, 0xAABBCCDD, spi_burst_send
.4byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end
.4byte rx_data, 0x000000DD, read32_test # read rx_data
.4byte rx_data, 0x000000CC, read32_test
.4byte rx_data, 0x000000BB, read32_test
.4byte rx_data, 0x000000AA, read32_test
# Test sck-cs delay cs_mode = HOLD
.4byte delay0, 0x00050001, write32_test # set sck-cs delay to 5 (should have no effect because cs is never inactive)
.4byte tx_data, 0xABBCCDDE, spi_burst_send # place 8'h11 into tx_data
.4byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end
.4byte rx_data, 0x000000DE, read32_test # read rx_data
.4byte rx_data, 0x000000CD, read32_test
.4byte rx_data, 0x000000BC, read32_test
.4byte rx_data, 0x000000AB, read32_test
# =========== Test frame format (fmt) register ===========
# Test frame length of 4
.4byte delay1, 0x00000001, write32_test # reset delay1 register
.4byte delay0, 0x00010001, write32_test # reset delay0 register
.4byte sck_mode, 0x00000000, write32_test #reset sckmode register
.4byte cs_mode, 0x00000000, write32_test # set cs_mode to AUTO
.4byte fmt, 0x00040000, write32_test # set frame length to 4
.4byte tx_data, 0x000000F0, write32_test # place 8'h11 into tx_data
.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.4byte rx_data, 0x000000F0, read32_test # read rx_data
# Test frame length of 0
#.4byte fmt, 0x00000000, write32_test # set frame length to 4
#.4byte tx_data, 0x00000077, write32_test # place 8'h11 into tx_data
#.4byte 0x0, 0x0101, spi_data_wait # wait for transmission to end
#.4byte rx_data, 0x00000077, read32_test # read rx_data
# test frame length 1 burst
.4byte fmt, 0x00010000, write32_test
.4byte tx_data, 0x80008000, spi_burst_send
.4byte 0x0, 0x00000003, spi_data_wait
.4byte rx_data, 0x00000000, read32_test
.4byte rx_data, 0x00000080, read32_test
.4byte rx_data, 0x00000000, read32_test
.4byte rx_data, 0x00000080, read32_test
# Test big endian with frame length = 5
.4byte fmt, 0x00050000, write32_test # set frame length to 5, big endian
.4byte tx_data, 0x000000A8, write32_test # place 8'h11 into tx_data
.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.4byte rx_data, 0x000000A8, read32_test # read rx_data
# Test big endian burst with frame length = 5
.4byte tx_data, 0x03774FFF, spi_burst_send
.4byte 0x0, 0x00000003, spi_data_wait
.4byte rx_data, 0x000000F8, read32_test
.4byte rx_data, 0x00000048, read32_test
.4byte rx_data, 0x00000070, read32_test
.4byte rx_data, 0x00000000, read32_test
# Test little endian with frame length = 5
.4byte fmt, 0x00050004, write32_test # set frame length to 5, little-endian
.4byte tx_data, 0x000000A8, write32_test # place 8'h11 into tx_data
.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.4byte rx_data, 0x00000008, read32_test # read rx_data -> 08
#test little endian burst with frame length = 5
.4byte tx_data, 0xFF4F7703, spi_burst_send
.4byte 0x0, 0x00000003, spi_data_wait
.4byte rx_data, 0x00000003, read32_test #03
.4byte rx_data, 0x00000017, read32_test #17
.4byte rx_data, 0x0000000F, read32_test #0F
.4byte rx_data, 0x0000001F, read32_test #1F
# Test dual SPI protocol, frame length = 8, big endian
#.4byte fmt, 0x00080001, write32_test # set frame length to 8, big-endian, dual SPI
#.4byte tx_data, 0x000000C8, write32_test # place 8'h11 into tx_data
#.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
#.4byte rx_data, 0x00000000, read32_test # read rx_data
# Test dual SPI protocol, frame length = 4
#.4byte fmt, 0x00040001, write32_test # set frame length to 8, big-endian, dual SPI
#.4byte tx_data, 0x000000A2, write32_test # place 8'h11 into tx_data
#.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
#.4byte rx_data, 0x000000A0, read32_test # read rx_data
# Test dual SPI protocol, frame length = 5
#.4byte fmt, 0x00050001, write32_test # set frame length to 8, big-endian, dual SPI
#.4byte tx_data, 0x00000075, write32_test # place 8'h11 into tx_data
#.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
#.4byte rx_data, 0x00000074, read32_test # read rx_data
# Test dual SPI protocol burst, frame length = 5
#.4byte tx_data, 0x30733FFF, spi_burst_send
#.4byte 0x0, 0x00000003, spi_data_wait
#.4byte rx_data, 0x000000FC, read32_test
#.4byte rx_data, 0x0000003C, read32_test
#.4byte rx_data, 0x00000070, read32_test
#.4byte rx_data, 0x00000030, read32_test
# Test quad SPI protocol, frame length = 5
#.4byte fmt, 0x00050002, write32_test # set frame length to 8, big-endian, dual SPI
#.4byte tx_data, 0x0000003F, write32_test # place 8'h11 into tx_data
#.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
#.4byte rx_data, 0x0000003F, read32_test # read rx_data
# Test quad SPI protocol, frame length = 4
#.4byte fmt, 0x00040002, write32_test # set frame length to 8, big-endian, dual SPI
#.4byte tx_data, 0x0000000F, write32_test # place 8'h11 into tx_data
#.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
#.4byte rx_data, 0x00000000, read32_test # read rx_data
# Test quad SPI protocol, frame length = 8
#.4byte fmt, 0x00080002, write32_test # set frame length to 8, big-endian, dual SPI
#.4byte tx_data, 0x000000F0, write32_test # place 8'h11 into tx_data
#.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
#.4byte rx_data, 0x000000F0, read32_test # read rx_data
# =========== Test watermark interrupts ===========
# Test transmit watermark interrupt (triggers when entries in tx FIFO < tx watermark) without external enables
# rx fifo > rx mark
SETUP_PLIC
.4byte fmt, 0x00080000, write32_test # reset fmt register
.4byte tx_mark, 0x00000004, write32_test # set transmit watermark to 4
#.4byte ie, 0x00000000, write32_test # enable transmit interrupt
.4byte ip, 0x00000001, read32_test # tx watermark interupt should be pending
.4byte 0x0, 0x00000000, readmip_test
.4byte tx_data, 0x55443322, spi_burst_send # place 4 entries in transmit fifo
.4byte ip, 0x00000000, read32_test # tx watermark interupt should be off
.4byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end
# test recieve watermark interrupt (triggers when entries in rx FIFO > rx watermark)
.4byte tx_mark, 0x00000000, write32_test # set tx_mark to 0
.4byte rx_data, 0x00000022, read32_test # clear one entry from rx FIFO
.4byte rx_mark, 0x00000003, write32_test # set recieve watermark to 3
#.4byte ie, 0x0000002, write32_test # enable receive interrupts
.4byte ip, 0x00000000, read32_test # rx interrupts should be low (rx FIFO has 3 entries)
.4byte rx_mark, 0x00000002, write32_test # set recieve watermark to 2
.4byte ip, 0x00000002, read32_test # recieve interrupt should be high
.4byte 0x0, 0x00000000, readmip_test
.4byte rx_data, 0x00000033, read32_test # clear one more entry from recieve FIFO (2 entries)
.4byte ip, 0x00000000, read32_test # receive interrupt should be low
.4byte rx_data, 0x00000044, read32_test
.4byte rx_data, 0x00000055, read32_test # clear rx fifo
.4byte tx_mark, 0x00000004, write32_test # set transmit watermark to 4
.4byte ie, 0x00000001, write32_test # enable transmit interrupt
.4byte ip, 0x00000001, read32_test # tx watermark interupt should be pending
.4byte 0x0, 0x00000800, readmip_test
.4byte ie, 0x00000000, write32_test #turn off tx mark
.4byte 0x0, 0x00000000, claim_m_plic_interrupts
.4byte tx_data, 0x55443322, spi_burst_send # place 4 entries in transmit fifo
.4byte ie, 0x00000001, write32_test #turn tx mark back on
.4byte tx_mark, 0x00000001, write32_test
.4byte ip, 0x00000000, read32_test # tx watermark interupt should be off
.4byte 0x0, 0x00000000, readmip_test
.4byte ie, 0x00000000, write32_test # disable tx intr
.4byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end
# test recieve watermark interrupt (triggers when entries in rx FIFO > rx watermark)
.4byte tx_mark, 0x00000000, write32_test
.4byte rx_data, 0x00000022, read32_test # clear one entry from rx FIFO
.4byte rx_mark, 0x00000003, write32_test # set recieve watermark to 3
.4byte ie, 0x0000002, write32_test # enable receive interrupts
.4byte ip, 0x00000000, read32_test # rx interrupts should be low (rx FIFO has 3 entries)
.4byte 0x0, 0x00000000, readmip_test
.4byte rx_mark, 0x00000002, write32_test # set recieve watermark to 2
.4byte ip, 0x00000002, read32_test # recieve interrupt should be high
.4byte 0x0, 0x00000800, readmip_test
.4byte rx_data, 0x00000033, read32_test # clear one more entry from recieve FIFO (2 entries)
.4byte 0x0, 0x00000000, claim_m_plic_interrupts
.4byte ip, 0x00000000, read32_test # receive interrupt should be low
.4byte 0x0, 0x00000000, readmip_test
.4byte 0x0, 0x0, terminate_test

View File

@ -54,6 +54,9 @@ target_tests_nosim = \
WALLY-trap-s-01 \
WALLY-trap-u-01 \
WALLY-status-fp-enabled-01 \
WALLY-spi-01 \
WALLY-gpio-01 \
WALLY-uart-01 \
WALLY-wfi-01 \
WALLY-cbom-01 \
WALLY-cboz-01 \

View File

@ -0,0 +1,253 @@
00000003 # reset tests sck_div
00000000
00000000 # sck_mode
00000000
00000000 # cs_id
00000000
0000000F # cs_def
00000000
00000000 # cs_mode
00000000
00010001 # delay 0
00000000
00000001 # delay 1
00000000
00080000 # fmt
00000000
00000000 # tx_data
00000000
00000000 # tx_mark
00000000
00000000 # rx_mark
00000000
00000000 # ie reset
00000000
00000000 # ip reset
00000000
00000011 #basic read write
00000000
000000FF
00000000
000000A0
00000000
0000000B
00000000
00000079
00000000
00000000
00000000
000000C0
00000000
00000011
00000000
00000020 #delay registers
00000000
00000032
00000000
00000048
00000000
000000AF
00000000
00000050
00000000
0000006B
00000000
00000011
00000000
00000015
00000000
00000011 #delay1
00000000
00000022
00000000
00000033
00000000
00000044
00000000
0000007B
00000000
00000021
00000000
00000032
00000000
00000043
00000000
00000054
00000000
00000066
00000000
00000077
00000000
00000088
00000000
00000099
00000000
00000066
00000000
00000077
00000000
00000088
00000000
00000099
00000000
00000065
00000000
00000076
00000000
00000087
00000000
00000098
00000000
00000048
00000000
000000DD
00000000
000000CC
00000000
000000BB
00000000
000000AA
00000000
000000DE
00000000
000000CD
00000000
000000BC
00000000
000000AB
00000000
#000000CE hold mode deassert
#00000000
#00000002 #fifo edge case
#00000000
#000000D1
#00000000
#000000C1
#00000000
#000000B1
#00000000
#000000A1
#0000001B
#00000000
#0000001A
#00000000
#000000F1
#00000000
#000000E1
#00000000
000000F0 #fmt register
00000000
00000000
00000000
00000080
00000000
00000000
00000000
00000080
00000000
000000A8
00000000
000000F8
00000000
00000048
00000000
00000070
00000000
00000000
00000000
00000008
00000000
00000003
00000000
00000017
00000000
0000000F
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
00000000
00000000 #read tx ip
00000000
00000022 #clear 1 frame from rx fifo
00000000
00000000 # read recieve ip
00000000
00000002 #read recieve ip
00000000
00000000 #read mip
00000000
00000033 #clear frame
00000000
00000000 # read receive ip
00000000
00000044 #clear frame
00000000
00000055 #clear frame
00000000
00000001 #read tx ip
00000000
00000800 #read mip
00000000
00000000 #read tx wm
00000000
00000000 #read mip 91
00000000
00000022 #clear frame
00000000
00000000 #read rx ip
00000000
00000000 #read mip 94
00000000
00000002 #read rx ip
00000000
00000800 #read mip
00000000
00000033 #clear frame
00000000
00000000 #read rx wm
00000000
00000000 #read mip 99
00000000

View File

@ -884,6 +884,7 @@ trap_handler_end_\MODE\(): // place to jump to so we can skip the trap handler a
.equ PLIC_INTPRI_GPIO, 0x0C00000C # GPIO is interrupt 3
.equ PLIC_INTPRI_UART, 0x0C000028 # UART is interrupt 10
.equ PLIC_INTPRI_SPI, 0x0C000018 # SPI in interrupt 6
.equ PLIC_INTPENDING0, 0x0C001000 # intPending0 register
.equ PLIC_INTEN00, 0x0C002000 # interrupt enables for context 0 (machine mode) sources 31:1
.equ PLIC_INTEN10, 0x0C002080 # interrupt enables for context 1 (supervisor mode) sources 31:1
@ -896,6 +897,7 @@ trap_handler_end_\MODE\(): // place to jump to so we can skip the trap handler a
.8byte PLIC_THRESH1, 7, write32_test # Set PLIC supervisor mode interrupt threshold to 7 to accept no interrupts
.8byte PLIC_INTPRI_GPIO, 7, write32_test # Set GPIO to high priority
.8byte PLIC_INTPRI_UART, 7, write32_test # Set UART to high priority
.8byte PLIC_INTPRI_SPI, 7, write32_test # Set SPI to high priority
.8byte PLIC_INTEN00, 0xFFFFFFFF, write32_test # Enable all interrupt sources for machine mode
.8byte PLIC_INTEN10, 0x00000000, write32_test # Disable all interrupt sources for supervisor mode
.endm
@ -1065,6 +1067,12 @@ claim_m_plic_interrupts: // clears one non-pending PLIC interrupt
sw t3, 0(t2)
sw t4, -4(sp)
addi sp, sp, -4
li t2, 0x0C000018 // SPI priority
li t3, 7
lw t4, 0(t2)
sw t3, 0(t2)
sw t4, -4(sp)
addi sp, sp, -4
li t2, 0x0C002000
li t3, 0x0C200004
li t4, 0xFFF
@ -1075,11 +1083,14 @@ claim_m_plic_interrupts: // clears one non-pending PLIC interrupt
sw t6, 0(t2) // restore saved enable status
li t2, 0x0C00000C // GPIO priority
li t3, 0x0C000028 // UART priority
lw t4, 4(sp) // load stored GPIO and UART priority
lw t5, 0(sp)
addi sp, sp, 8 // restore stack pointer
sw t4, 0(t2)
sw t5, 0(t3)
li t6, 0x0C000018 // SPI priority
lw a4, 8(sp) // load stored GPIO prioroty
lw t4, 4(sp) // load stored UART priority
lw t5, 0(sp) // load stored SPI priority
addi sp, sp, 12 // restore stack pointer
sw a4, 0(t2)
sw t4, 0(t3)
sw t5, 0(t6)
j test_loop
claim_s_plic_interrupts: // clears one non-pending PLIC interrupt
@ -1165,6 +1176,34 @@ uart_clearmodemintr:
lb t2, 0(t2)
j test_loop
spi_data_wait:
li t2, 0x10040054
sw t4, 0(t2) // set rx watermark level
li t2, 0x10040074
lw t3, 0(t2) //read ip (interrupt pending register)
slli t3, t3, 56
srli t3, t3, 56
li t2, 0x00000002
bge t3, t2, spi_data_ready //branch to done if transmission complete
j spi_data_wait //else check again
spi_data_ready:
li t2, 0x10040070
li t3, 0x00000000
sw t3, 0(t2) //disable rx watermark interrupt
j test_loop
spi_burst_send: //function for loading multiple frames at once to test delays without returning to test loop
mv t2, t4
sw t2, 0(t3)
srli t2, t2, 8
sw t2, 0(t3)
srli t2, t2, 8
sw t2, 0(t3)
srli t2, t2, 8
sw t2, 0(t3)
j test_loop
goto_s_mode:
// return to address in t3,
li a0, 3 // Trap handler behavior (go to supervisor mode)

View File

@ -0,0 +1,618 @@
///////////////////////////////////////////
//
// WALLY-spi
//
// Author: David_Harris@hmc.edu and Naiche Whyte-Aguayo
//
// Created 2023-02-01
//
// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
// OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
///////////////////////////////////////////
#include "WALLY-TEST-LIB-64.h"
RVTEST_ISA("RV64I_Zicsr_Zifencei")
RVTEST_CASE(0,"//check ISA:=regex(.*64.*);check ISA:=regex(.*I.*); def Drvtest_mtrap_routine=True;def TEST_CASE_1=True;def NO_SAIL=True;",spi)
INIT_TESTS
TRAP_HANDLER m
j run_test_loop // begin test loop/table tests instead of executing inline code.
INIT_TEST_TABLE
END_TESTS
TEST_STACK_AND_DATA
.align 3
test_cases:
# ---------------------------------------------------------------------------------------------
# Test Contents
#
# Here is where the actual tests are held, or rather, what the actual tests do.
# each entry consists of 3 values that will be read in as follows:
#
# '.8byte [x28 Value], [x29 Value], [x30 value]'
# or
# '.8byte [address], [value], [test type]'
#
# The encoding for x30 test type values can be found in the test handler in the framework file
# ---------------------------------------------------------------------------------------------
.equ SPI, 0x10040000
.equ sck_div, (SPI+0x00)
.equ sck_mode, (SPI+0x04)
.equ cs_id, (SPI+0x10)
.equ cs_def, (SPI+0x14)
.equ cs_mode, (SPI+0x18)
.equ delay0, (SPI+0x28)
.equ delay1, (SPI+0x2C)
.equ fmt, (SPI+0x40)
.equ tx_data, (SPI+0x48)
.equ rx_data, (SPI+0x4C)
.equ tx_mark, (SPI+0x50)
.equ rx_mark, (SPI+0x54)
.equ ie, (SPI+0x70)
.equ ip, (SPI+0x74)
# =========== Verify all registers reset to correct values ===========
.8byte sck_div, 0x00000003, read32_test # sck_div reset to 0x3
.8byte sck_mode, 0x00000000, read32_test # sck_mode reset to 0x0
.8byte cs_id, 0x00000000, read32_test # cs_id reset to 0x0
.8byte cs_def, 0x0000000F, read32_test # cs_def reset to 0x1
.8byte cs_mode, 0x00000000, read32_test # cs_mode reset to 0x0
.8byte delay0, 0x00010001, read32_test # delay0 reset to [31:24] 0x0, [23:16] 0x1, [15:8] 0x0, [7:0] 0x1
.8byte delay1, 0x00000001, read32_test # delay1 reset to 0x1
.8byte fmt, 0x00080000, read32_test # fmt reset to [31:20] 0x0, [19:16] 0x8, [15:0] 0x0 for non-flash enabled SPI controllers
.8byte tx_data, 0x00000000, read32_test # tx_data [30:0] reset to 0x0, [31] read only
.8byte tx_mark, 0x00000000, read32_test # tx_mark reset to 0x0 for non-flash enabled controllers
.8byte rx_mark, 0x00000000, read32_test # rx_mark reset to 0x0
.8byte ie, 0x00000000, read32_test # ie reset to 0x0
.8byte ip, 0x00000000, read32_test # ip reset to 0x0
# =========== Basic read-write ===========
.8byte tx_data, 0x000000011, write32_test # place 8'h11 into tx_data
.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x00000011, read32_test # read rx_data
# =========== Different cs_mode, sck_mode, cs_def, sck_div ===========
# Test sck_div
.8byte sck_div, 0x00000101, write32_test # set sck_div to 0x101
.8byte tx_data, 0x000000FF, write32_test # place 8'h11 into tx_data
.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x000000FF, read32_test # read rx_data
# Test phase
.8byte sck_div, 0x00000003, write32_test # reset sck_div to 0x03 so only sck_mode is different
.8byte sck_mode, 0x00000001, write32_test # change phase to falling edge
.8byte tx_data, 0x000000A0, write32_test # place 8'h11 into tx_data
.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x000000A0, read32_test # read rx_data
# Test polarity
.8byte sck_mode, 0x00000000, write32_test # reset sck phase to rising edge
.8byte sck_mode, 0x00000002, write32_test # set sck polarity active low
.8byte tx_data, 0x0000000B, write32_test # place 8'h11 into tx_data
.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x0000000B, read32_test # read rx_data
# Test chip select polarity
.8byte sck_mode, 0x00000000, write32_test # reset sck polarity to active high
.8byte cs_def, 0x0000000E, write32_test # set cs[0] to inactive low
.8byte tx_data, 0x00000079, write32_test # place 8'h11 into tx_data
.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x00000079, read32_test # read rx_data
# Test chip id
.8byte cs_def, 0x0000000F, write32_test # reset all cs to active low
.8byte cs_id, 0x00000001, write32_test # select cs[1]
.8byte tx_data, 0x00000000, write32_test # place 8'h11 into tx_data
.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x00000000, read32_test # read rx_data
# Test cs hold mode
.8byte cs_id, 0x00000000, write32_test # select cs[0]
.8byte cs_mode, 0x00000002, write32_test # set cs_mode to HOLD
.8byte tx_data, 0x000000C0, write32_test # place 8'h11 into tx_data
.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x000000C0, read32_test # read rx_data
# Test cs OFF mode
.8byte cs_mode, 0x00000003, write32_test # set cs_mode to OFF
.8byte tx_data, 0x00000011, write32_test # place 8'h11 into tx_data
.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x00000011, read32_test # read rx_data
# =========== Test delay0 register ===========
# Test cs-sck delay of 0 with sck phase = 0 (implicit half cycle delay)
.8byte cs_mode, 0x00000000, write32_test # reset cs_mode to auto, all cs and sck mode settings should be defualt
.8byte delay0, 0x00010000, write32_test # set cs-sck delay to 0
.8byte tx_data, 0x00000020, write32_test # place 8'h11 into tx_data
.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x00000020, read32_test # read rx_data
# Test cs-sck delay of 0 with sck phase 1 (no delay)
.8byte sck_mode, 0x00000001, write32_test # set sck_mode[0] to 1 (sck phase = 1)
.8byte tx_data, 0x00000032, write32_test # place 8'h11 into tx_data
.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x00000032, read32_test # read rx_data
# Test arbitrary cs-sck delay (sck phase 1)
.8byte delay0, 0x00010005, write32_test # set cs-sck delay to 5 cycles
.8byte tx_data, 0x00000048, write32_test # place 8'h11 into tx_data
.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x00000048, read32_test # read rx_data
# Test arbitrary cs-sck delay (sck phase 0)
.8byte sck_mode, 0x00000000, write32_test # set sck phase to 0
.8byte delay0, 0x00010005, write32_test # set cs-sck delay to AF cycles
.8byte tx_data, 0x000000AF, write32_test # place 8'h11 into tx_data
.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x000000AF, read32_test # read rx_data
# Test sck-cs delay of 0 with sck phase = 0 (no delay)
.8byte delay0, 0x00000001, write32_test # set cs-sck delay to 0
.8byte tx_data, 0x00000050, write32_test # place 8'h11 into tx_data
.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x00000050, read32_test # read rx_data
# Test sck-cs delay of 0 with sck phase 1 (implicit half cycle delay)
.8byte sck_mode, 0x00000001, write32_test # set sck_mode[0] to 1 (sck phase = 1)
.8byte tx_data, 0x0000006B, write32_test # place 8'h11 into tx_data
.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x0000006B, read32_test # read rx_data
# Test arbitrary sck-cs delay (sck phase 1)
.8byte delay0, 0x00050001, write32_test # set cs-sck delay to A5 cycles
.8byte tx_data, 0x00000011, write32_test # place 8'h11 into tx_data
.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x00000011, read32_test # read rx_data
# Test arbitrary sck-cs delay (sck phase 0)
.8byte sck_mode, 0x00000000, write32_test # set sck phase to 0
.8byte delay0, 0x00050001, write32_test # set cs-sck delay to 5 cycles
.8byte tx_data, 0x00000015, write32_test # place 8'h11 into tx_data
.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x00000015, read32_test # read rx_data
# =========== Test delay1 register ===========
# Test inter cs delay
.8byte delay0, 0x00010001, write32_test # reset delay0 register
.8byte delay1, 0x00000005, write32_test # set inter_cs delay to 5
.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x44332211, spi_burst_send
.8byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x00000011, read32_test
.8byte rx_data, 0x00000022, read32_test
.8byte rx_data, 0x00000033, read32_test
.8byte rx_data, 0x00000044, read32_test
#test long inter_cs delay
.8byte delay1, 0x000000A5, write32_test
.8byte rx_mark, 0x0000000, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x0000007B, write32_test
.8byte 0x0, 0x00000000, spi_data_wait
.8byte rx_data, 0x0000007B, read32_test
# Test inter_cs delay set to 0
.8byte delay1, 0x00000000, write32_test # set inter_cs delay to 5
.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x54433221, spi_burst_send
.8byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x00000021, read32_test
.8byte rx_data, 0x00000032, read32_test
.8byte rx_data, 0x00000043, read32_test
.8byte rx_data, 0x00000054, read32_test
# Test inter_xfr delay of 0 (maybe change behavior to half-period instead of period)
.8byte delay1, 0x00000001, write32_test # reset inter_cs delay to 1
.8byte cs_mode, 0x00000002, write32_test # set cs_mode to HOLD
.8byte tx_data, 0x99887766, spi_burst_send
.8byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x00000066, read32_test
.8byte rx_data, 0x00000077, read32_test
.8byte rx_data, 0x00000088, read32_test
.8byte rx_data, 0x00000099, read32_test
# Test inter_xfr delay 0 with phase = 1
.8byte sck_mode, 0x00000001, write32_test
.8byte tx_data, 0x99887766, spi_burst_send
.8byte 0x0, 0x00000003, spi_data_wait
.8byte rx_data, 0x00000066, read32_test
.8byte rx_data, 0x00000077, read32_test
.8byte rx_data, 0x00000088, read32_test
.8byte rx_data, 0x00000099, read32_test
# Test arbitrary inter_xfr delay
.8byte delay1, 0x00050001, write32_test # set inter_xfr delay to 5
.8byte sck_mode, 0x00000001, write32_test
.8byte tx_data, 0x98877665, spi_burst_send
.8byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x00000065, read32_test
.8byte rx_data, 0x00000076, read32_test
.8byte rx_data, 0x00000087, read32_test
.8byte rx_data, 0x00000098, read32_test
# test long inter_xfr delay
.8byte delay1, 0x00A50001, write32_test
.8byte rx_mark, 0x0000000, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x00000048, write32_test
.8byte 0x0, 0x00000000, spi_data_wait
.8byte rx_data, 0x00000048, read32_test
# Test cs-sck delay with cs_mode = HOLD
.8byte delay1, 0x00000001, write32_test # set inter_xfr delay to 0
.8byte delay0, 0x00010005, write32_test # set cs-sck delay to 5 (should have no effect because cs is never inactive)
.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0xAABBCCDD, spi_burst_send
.8byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x000000DD, read32_test # read rx_data
.8byte rx_data, 0x000000CC, read32_test
.8byte rx_data, 0x000000BB, read32_test
.8byte rx_data, 0x000000AA, read32_test
# Test sck-cs delay cs_mode = HOLD
.8byte delay0, 0x00000501, write32_test # set sck-cs delay to 5 (should have no effect because cs is never inactive)
.8byte tx_data, 0xABBCCDDE, spi_burst_send # place 8'h11 into tx_data
.8byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x000000DE, read32_test # read rx_data
.8byte rx_data, 0x000000CD, read32_test
.8byte rx_data, 0x000000BC, read32_test
.8byte rx_data, 0x000000AB, read32_test
# Test hold mode deassert conditions
#.8byte delay1, 0x00000001, write32_test # reset delay1 register
#.8byte delay0, 0x00010001, write32_test # reset delay0 register
#.8byte cs_mode, 0x00000002, write32_test # set cs_mode to hold
#.8byte tx_data, 0x000000CE, write32_test # place data into tx_data
#.8byte cs_id, 0x00000001, write32_test #change selected cs pin. should deassert cs[0] in hold mode
#.8byte cs_def, 0x00001101, write32_test # change selected cs pins def value. should deassert cs[1]
#.8byte cs_def, 0x00001111, write32_test # reset cs_def
#.8byte cs_mode, 0x00000000, write32_test # change cs_mode to auto, should deassert cs[1], have now gone through all deassertion conditions
#.8byte rx_data, 0x000000CE, read32_test # clear rx_fifo
# Test transmit and receive fifo full edge cases
#.8byte rx_mark, 0x00000007, write32_test #set rx watermark to 7 (only high when full)
#.8byte tx_data, 0xA1B1C1D1, spi_burst_send #fill rx fifo
#.8byte tx_data, 0xE1F11A1B, spi_burst_send
#.8byte 0x0, 0x00000007, spi_data_wait #wait for rx fifo to fill
#.8byte ip, 0x00000002, read32_test #rxmark ip should be high
#.8byte rx_data, 0x000000D1, read32_test #clear rx fifo
#.8byte rx_data, 0x000000C1, read32_test
#.8byte rx_data, 0x000000B1, read32_test
#.8byte rx_data, 0x000000A1, read32_test
#.8byte rx_data, 0x0000001B, read32_test
#.8byte rx_data, 0x0000001A, read32_test
#.8byte rx_data, 0x000000F1, read32_test
#.8byte rx_data, 0x000000E1, read32_test
#test fifo watermark edge cases (wrap arounds, 2s complement)
# =========== Test frame format (fmt) register ===========
# Test frame length of 4
.8byte delay1, 0x00000001, write32_test # reset delay1 register
.8byte delay0, 0x00010001, write32_test # reset delay0 register
.8byte sck_mode, 0x00000000, write32_test #reset sckmode register
.8byte cs_mode, 0x00000000, write32_test # set cs_mode to AUTO
.8byte fmt, 0x00040000, write32_test # set frame length to 4
.8byte rx_mark, 0x0000000, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x000000F0, write32_test # place 8'h11 into tx_data
.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x000000F0, read32_test # read rx_data
# Test frame length of 0
#.8byte fmt, 0x00000000, write32_test # set frame length to 4
#.8byte tx_data, 0x00000077, write32_test # place 8'h11 into tx_data
#.8byte 0x0, 0x0101, spi_data_wait # wait for transmission to end
#.8byte rx_data, 0x00000077, read32_test # read rx_data
# test frame length 1 burst
.8byte fmt, 0x00010000, write32_test
.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x80008000, spi_burst_send
.8byte 0x0, 0x00000003, spi_data_wait
.8byte rx_data, 0x00000000, read32_test
.8byte rx_data, 0x00000080, read32_test
.8byte rx_data, 0x00000000, read32_test
.8byte rx_data, 0x00000080, read32_test
# Test big endian with frame length = 5
.8byte fmt, 0x00050000, write32_test # set frame length to 5, big endian
.8byte rx_mark, 0x0000000, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x000000A8, write32_test # place 8'h11 into tx_data
.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x000000A8, read32_test # read rx_data
# Test big endian burst with frame length = 5
.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x03774FFF, spi_burst_send
.8byte 0x0, 0x00000003, spi_data_wait
.8byte rx_data, 0x000000F8, read32_test
.8byte rx_data, 0x00000048, read32_test
.8byte rx_data, 0x00000070, read32_test
.8byte rx_data, 0x00000000, read32_test
# Test little endian with frame length = 5
.8byte fmt, 0x00050004, write32_test # set frame length to 5, little-endian
.8byte rx_mark, 0x0000000, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x000000A8, write32_test # place 8'h11 into tx_data
.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
.8byte rx_data, 0x00000008, read32_test # read rx_data -> 08
#test little endian burst with frame length = 5
.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0xFF4F7703, spi_burst_send
.8byte 0x0, 0x00000003, spi_data_wait
.8byte rx_data, 0x00000003, read32_test #03
.8byte rx_data, 0x00000017, read32_test #17
.8byte rx_data, 0x0000000F, read32_test #0F
.8byte rx_data, 0x0000001F, read32_test #1F
# Test dual SPI protocol, frame length = 8, big endian
#.8byte fmt, 0x00080001, write32_test # set frame length to 8, big-endian, dual SPI
#.8byte tx_data, 0x000000C8, write32_test # place 8'h11 into tx_data
#.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
#.8byte rx_data, 0x00000000, read32_test # read rx_data
# Test dual SPI protocol, frame length = 4
#.8byte fmt, 0x00040001, write32_test # set frame length to 8, big-endian, dual SPI
#.8byte tx_data, 0x000000A2, write32_test # place 8'h11 into tx_data
#.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
#.8byte rx_data, 0x000000A0, read32_test # read rx_data
# Test dual SPI protocol, frame length = 5
#.8byte fmt, 0x00050001, write32_test # set frame length to 8, big-endian, dual SPI
#.8byte tx_data, 0x00000075, write32_test # place 8'h11 into tx_data
#.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
#.8byte rx_data, 0x00000074, read32_test # read rx_data
# Test dual SPI protocol burst, frame length = 5
#.8byte tx_data, 0x30733FFF, spi_burst_send
#.8byte 0x0, 0x00000003, spi_data_wait
#.8byte rx_data, 0x000000FC, read32_test
#.8byte rx_data, 0x0000003C, read32_test
#.8byte rx_data, 0x00000070, read32_test
#.8byte rx_data, 0x00000030, read32_test
# Test quad SPI protocol, frame length = 5
#.8byte fmt, 0x00050002, write32_test # set frame length to 8, big-endian, dual SPI
#.8byte tx_data, 0x0000003F, write32_test # place 8'h11 into tx_data
#.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
#.8byte rx_data, 0x0000003F, read32_test # read rx_data
# Test quad SPI protocol, frame length = 4
#.8byte fmt, 0x00040002, write32_test # set frame length to 8, big-endian, dual SPI
#.8byte tx_data, 0x0000000F, write32_test # place 8'h11 into tx_data
#.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
#.8byte rx_data, 0x00000000, read32_test # read rx_data
# Test quad SPI protocol, frame length = 8
#.8byte fmt, 0x00080002, write32_test # set frame length to 8, big-endian, dual SPI
#.8byte tx_data, 0x000000F0, write32_test # place 8'h11 into tx_data
#.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end
#.8byte rx_data, 0x000000F0, read32_test # read rx_data
#=========== Test Hardware Interlock ================
# interlock in base case
.8byte fmt, 0x00080000, write32_test # reset fmt register
.8byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x00000062, write32_test # initiate transmission
.8byte sck_mode, 0x00000002, write32_test # flip polarity during transmission
.8byte tx_data, 0x00000026, write32_test # transmit second frame w/ control register updated
.8byte 0x0, 0x00000001, spi_data_wait
.8byte rx_data, 0x00000062, read32_test
.8byte rx_data, 0x00000026, read32_test # clear rx fifo
.8byte sck_mode, 0x00000000, write32_test # reset polarity
# interlock in case where cs_mode is auto, but there is minimal intercs delay
.8byte delay0, 0x00000001, write32_test # set sck-cs delay to 0, with sck.pha 0 there is 0 delay
.8byte tx_data, 0x000000D2, write32_test # initiate transmission
.8byte sck_mode, 0x00000002, write32_test # flip sck polarity
.8byte tx_data, 0x0000002D, write32_test # transmit second frame
.8byte 0x0, 0x00000001, spi_data_wait
.8byte rx_data, 0x000000D2, read32_test
.8byte rx_data, 0x0000002D, read32_test # clear rx fifo
.8byte sck_mode, 0x00000000, write32_test # reset polarity
# interlock in case where cs_mode = hold, 0 intercs delay
.8byte delay0, 0x00010001, write32_test # reset delay0
.8byte sck_mode, 0x00000000, write32_test # reset polarity
.8byte cs_mode, 0x00000002, write32_test # set cs_mode to hold
.8byte tx_data, 0x15263748, spi_burst_send # place 4 frames into tx fifo
.8byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame)
.8byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end
.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.8byte sck_mode, 0x00000000, write32_test # flip polarity again
.8byte 0x0, 0x00000003, spi_data_wait # wait for final frame
.8byte rx_data, 0x00000048, read32_test
.8byte rx_data, 0x00000037, read32_test
.8byte rx_data, 0x00000026, read32_test
.8byte rx_data, 0x00000015, read32_test #clear rx fifo
# interlock in case where cs_mode = hold, intercs delay
.8byte sck_mode, 0x00000000, write32_test # reset polarity
.8byte delay1, 0x00010001, write32_test # set intercs delay to 1
.8byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x51627384, spi_burst_send # place 4 frames into tx fifo
.8byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame)
.8byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end
.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.8byte sck_mode, 0x00000000, write32_test # flip polarity again
.8byte 0x0, 0x00000003, spi_data_wait # wait for final frame
.8byte rx_data, 0x00000084, read32_test
.8byte rx_data, 0x00000073, read32_test
.8byte rx_data, 0x00000062, read32_test
.8byte rx_data, 0x00000051, read32_test #clear rx fifo
# repeat previous set of tests with cs_mode = off
.8byte cs_mode, 0x00000003, write32_test # set cs_mode to hold
.8byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x13243546, spi_burst_send # place 4 frames into tx fifo
.8byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame)
.8byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end
.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.8byte sck_mode, 0x00000000, write32_test # flip polarity again
.8byte 0x0, 0x00000003, spi_data_wait # wait for final frame
.8byte rx_data, 0x00000046, read32_test
.8byte rx_data, 0x00000035, read32_test
.8byte rx_data, 0x00000024, read32_test
.8byte rx_data, 0x00000013, read32_test #clear rx fifo
# interlock in case where cs_mode = hold, intercs delay
.8byte sck_mode, 0x00000000, write32_test # reset polarity
.8byte delay1, 0x00000000, write32_test # set intercs delay to 0
.8byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock
.8byte tx_data, 0x31425364, spi_burst_send # place 4 frames into tx fifo
.8byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame)
.8byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end
.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock
.8byte sck_mode, 0x00000000, write32_test # flip polarity again
.8byte 0x0, 0x00000003, spi_data_wait # wait for final frame
.8byte rx_data, 0x00000064, read32_test
.8byte rx_data, 0x00000053, read32_test
.8byte rx_data, 0x00000042, read32_test
.8byte rx_data, 0x00000031, read32_test #clear rx fifo
# =========== Test watermark interrupts ===========
# Test transmit watermark interrupt (triggers when entries in tx FIFO < tx watermark) without external enables
SETUP_PLIC
.8byte delay1, 0x0000001, write32_test # reset delay1 register
.8byte cs_mode, 0x00000000, write32_test # reset cs_mode
.8byte tx_mark, 0x00000004, write32_test # set transmit watermark to 4
#.8byte ie, 0x00000000, write32_test # enable transmit interrupt
.8byte ip, 0x00000001, read32_test # tx watermark interupt should be pending
.8byte 0x0, 0x00000000, readmip_test
.8byte tx_data, 0x55443322, spi_burst_send # place 4 entries in transmit fifo
.8byte ip, 0x00000000, read32_test # tx watermark interupt should be off
.8byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end
# test recieve watermark interrupt (triggers when entries in rx FIFO > rx watermark)
.8byte tx_mark, 0x00000000, write32_test # set tx_mark to 0
.8byte rx_data, 0x00000022, read32_test # clear one entry from rx FIFO
.8byte rx_mark, 0x00000003, write32_test # set recieve watermark to 3
#.8byte ie, 0x0000002, write32_test # enable receive interrupts
.8byte ip, 0x00000000, read32_test # rx interrupts should be low (rx FIFO has 3 entries)
.8byte rx_mark, 0x00000002, write32_test # set recieve watermark to 2
.8byte ip, 0x00000002, read32_test # recieve interrupt should be high
.8byte 0x0, 0x00000000, readmip_test
.8byte rx_data, 0x00000033, read32_test # clear one more entry from recieve FIFO (2 entries)
.8byte ip, 0x00000000, read32_test # receive interrupt should be low
.8byte rx_data, 0x00000044, read32_test
.8byte rx_data, 0x00000055, read32_test # clear rx fifo
.8byte tx_mark, 0x00000004, write32_test # set transmit watermark to 4
.8byte ie, 0x00000001, write32_test # enable transmit interrupt
.8byte ip, 0x00000001, read32_test # tx watermark interupt should be pending
.8byte 0x0, 0x00000800, readmip_test
.8byte tx_data, 0x55443322, spi_burst_send # place 4 entries in transmit fifo
.8byte tx_mark, 0x00000001, write32_test
.8byte 0x0, 0x00000000, claim_m_plic_interrupts
.8byte ip, 0x00000000, read32_test # tx watermark interupt should be off
.8byte 0x0, 0x00000000, readmip_test
.8byte ie, 0x00000000, write32_test # disable tx intr
.8byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end
# test recieve watermark interrupt (triggers when entries in rx FIFO > rx watermark)
.8byte tx_mark, 0x00000000, write32_test
.8byte 0x0, 0x00000000, claim_m_plic_interrupts
.8byte rx_data, 0x00000022, read32_test # clear one entry from rx FIFO
.8byte rx_mark, 0x00000003, write32_test # set recieve watermark to 3
.8byte ie, 0x0000002, write32_test # enable receive interrupts
.8byte ip, 0x00000000, read32_test # rx interrupts should be low (rx FIFO has 3 entries)
.8byte 0x0, 0x00000000, readmip_test
.8byte rx_mark, 0x00000002, write32_test # set recieve watermark to 2
.8byte ip, 0x00000002, read32_test # recieve interrupt should be high
.8byte 0x0, 0x00000800, readmip_test
.8byte rx_data, 0x00000033, read32_test # clear one more entry from recieve FIFO (2 entries)
.8byte 0x0, 0x00000000, claim_m_plic_interrupts
.8byte ip, 0x00000000, read32_test # receive interrupt should be low
.8byte 0x0, 0x00000000, readmip_test
.8byte 0x0, 0x0, terminate_test