transferred spi changes in ECA-authorized commit

This commit is contained in:
naichewa 2023-10-12 13:36:57 -07:00
parent 2f6e39defc
commit 1fa4ad90ec
26 changed files with 2324 additions and 48 deletions

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

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

@ -127,11 +127,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;
@ -142,6 +146,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

@ -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 Idempotent = (PBMemoryType == 2'b00) ? IdempotentRegion : (PBMemoryType == 2'b01);
assign IdempotentRegion = SelRegions[11] | SelRegions[10] | SelRegions[9] | SelRegions[8] | SelRegions[7];
assign Idempotent = (PBMemoryType == 2'b00) ? IdempotentRegion : (PBMemoryType == 2'b01); // exclusion-tag: unused-idempotent
// 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];
// Check if tightly integrated memories are selected
assign SelTIM = SelRegions[10] | SelRegions[9]; // exclusion-tag: unused-tim
assign SelTIM = SelRegions[11] | SelRegions[10];
// 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
);
@ -160,6 +160,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

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

@ -0,0 +1,746 @@
///////////////////////////////////////////
// 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 interlocks to ensure transfer finishes before register changes unimplemented
//TODO: change tests to reflect swizzled Delay0, Delay1, Format
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 [3:0] SPIOut,
input logic [3:0] 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 [7: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;
logic busy;
//FIFO FSM signals
logic TransmitWriteMark, TransmitReadMark, RecieveWriteMark, RecieveReadMark;
logic TransmitFIFOWriteFull, TransmitFIFOReadEmpty;
logic TransmitFIFOWriteIncrement, TransmitFIFOReadIncrement;
logic ReceiveFIFOWriteIncrement, 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 [12:0] DivCounter;
logic SCLKDuty;
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] FrameCountShifted;
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;
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; // spi never takes >1 cycle to respond (float module)
// account for subword read/write circuitry
// -- Note GPIO registers are 32 bits no matter what; access them with LW SW.
// (At least that's what I think when FE310 spec says "only naturally aligned 32-bit accesses are supported")
if (P.XLEN == 64) begin
assign Din = Entry[2] ? PWDATA[63:32] : PWDATA[31:0];
assign PRDATA = Entry[2] ? {Dout,32'b0} : {32'b0,Dout};
end else begin // 32-bit
assign Din = PWDATA[31:0];
assign PRDATA = Dout;
end
// register access
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 {8'b10000000};
TransmitData <= #1 9'b0;
//ReceiveData <= #1 9'b100000000;
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
//From spec. "Hardware interlocks ensure that the current transfer completes before mode transitions and control register updates take effect"
// Interpreting 'current transfer' as one frame
/* 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[3:0]};
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[11:0] <= #1 SckDiv;
8'h04: Dout[1:0] <= #1 SckMode;
8'h10: Dout[1:0] <= #1 ChipSelectID;
8'h14: Dout[3:0] <= #1 ChipSelectDef;
8'h18: Dout[1:0] <= #1 ChipSelectMode;
8'h28: begin
Dout[23:16] <= #1 Delay0[15:8]; // swizzle
Dout[7:0] <= #1 Delay0[7:0];
end
8'h2C: begin
Dout[23:16] <= #1 Delay1[15:8]; // swizzle
Dout[7:0] <= #1 Delay1[7:0];
end
8'h40: begin
Dout[19:16] <= #1 Format[7:4]; // swizzle
Dout[3:0] <= #1 Delay0[3:0];
end
8'h48: Dout[8:0] <= #1 {TransmitFIFOWriteFull, 8'b0};
8'h4C: Dout[8:0] <= #1 {ReceiveFIFOReadEmpty, ReceiveData[7:0]};
8'h50: Dout[2:0] <= #1 TransmitWatermark;
8'h54: Dout[2:0] <= #1 ReceiveWatermark;
8'h70: Dout[1:0] <= #1 InterruptEnable;
8'h74: Dout[1:0] <= #1 InterruptPending;
default: Dout <= #1 32'b0;
endcase
end
//SCK_CONTROL
//multiplies frame count by 2 or 4 if in dual or quad mode
always_comb
case(Format[1:0])
2'b00: FrameCountShifted = FrameCount;
2'b01: FrameCountShifted = {FrameCount[3:0], 1'b0};
2'b10: FrameCountShifted = {FrameCount[2:0], 2'b0};
default: FrameCountShifted = FrameCount;
endcase
//Calculates penultimate frame
//Frame compare doubles number of frames in dual or qyad mode to account for half-duplex communication
//FrameCompareProtocol further adjusts comparison according to dual or quad mode
always_comb
case(Format[1:0])
2'b00: begin
ReceivePenultimateFrame = 5'b00001;
FrameCompareProtocol = FrameCompare;
end
2'b01: begin
ReceivePenultimateFrame = 5'b00010;
//add 1 to count if # of bits is odd so doubled # will be correct
// for ex. 5 bits needs 3 frames, 5*2 = 10 which will be reached in 5 frames not 3*2.
FrameCompareProtocol = Format[4] ? FrameCompare + 5'b1 : FrameCompare;
end
2'b10: begin
ReceivePenultimateFrame = 5'b00100;
//if frame len =< 4, need 2 frames (one to send 1-4 bits, one to recieve)
//else, 4 < frame len =<8 8, which by same logic needs 4 frames
if (Format[7:4] > 4'b0100) FrameCompareProtocol = 5'b10000;
else FrameCompareProtocol = 5'b01000;
end
default: begin
ReceivePenultimateFrame = 5'b00001;
FrameCompareProtocol = FrameCompare;
end
endcase
//Signals that track frame count comparisons
assign FrameCompareBoolean = (FrameCountShifted < FrameCompareProtocol);
assign ReceivePenultimateFrameCount = FrameCountShifted + ReceivePenultimateFrame;
assign ReceivePenultimateFrameBoolean = (ReceivePenultimateFrameCount >= FrameCompareProtocol);
// 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}));
// double number of frames in dual or quad mode because we must wait for peripheral to send back
assign FrameCompare = (Format[0] | Format[1]) ? ({Format[7:4], 1'b0}) : {1'b0,Format[7:4]};
// Producing SCLK
// SCLK = PCLK/(2*(sclk_div + 1))
// SCLKDuty is high every half-period of SCLK
assign SCLKDuty = (DivCounter >= {1'b0,SckDiv});
always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) DivCounter <= #1 0;
else if (SCLKDuty) DivCounter <= 0;
else DivCounter <= DivCounter + 13'b1;
//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 (SCLKDuty) 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 ChipSelectInternal = SckMode[0] ? ((state == CS_INACTIVE | state == INTER_CS | (state == DELAY_1 & ~|(Delay0[15:8]))) ? ChipSelectDef : ~ChipSelectDef) : ((state == CS_INACTIVE | state == INTER_CS | (state == ACTIVE_1 & ~|(Delay0[15:8]) & ReceiveShiftFull)) ? ChipSelectDef : ~ChipSelectDef);
assign sck = (state == ACTIVE_0) ? ~SckMode[1] : SckMode[1];
assign busy = (state == DELAY_0 | state == ACTIVE_0 | ((state == ACTIVE_1) & ~((|(Delay1[15:8]) & (ChipSelectMode[1:0]) == 2'b10) & ((FrameCount << Format[1:0]) >= FrameCompare))) | state == DELAY_1);
assign Active = (state == ACTIVE_0 | state == ACTIVE_1);
assign Active0 = (state == ACTIVE_0);
assign Inactive = (state == CS_INACTIVE);
always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) HoldModeDeassert <= 0;
else if (Inactive) HoldModeDeassert <= 0;
/* verilator lint_off WIDTH */
else if (((ChipSelectMode[1:0] == 2'b10) & (Entry == (8'h18 | 8'h10) | ((Entry == 8'h14) & ((PWDATA[ChipSelectID]) != ChipSelectDef[ChipSelectID])))) & Memwrite) HoldModeDeassert <= 1;
/* verilator lint_on WIDTH */
assign TransmitFIFOWriteIncrement = (Memwrite & (Entry == 8'h48) & ~TransmitFIFOWriteFull);
always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) TransmitFIFOWriteIncrementDelay <= 0;
else TransmitFIFOWriteIncrementDelay <= TransmitFIFOWriteIncrement;
assign TransmitFIFOReadIncrement = TransmitShiftEmpty;
assign ReceiveFIFOWriteIncrement = ReceiveShiftFullDelay;
always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) ReceiveFIFOReadIncrement <= 0;
else if (~ReceiveFIFOReadIncrement) ReceiveFIFOReadIncrement <= ((Entry == 8'h4C) & ~ReceiveFIFOReadEmpty & PSEL);
else ReceiveFIFOReadIncrement <= 0;
//replace literal 9th bit of ReceiveData register with concatenation of 1 bit empty signal and 8 bits of data
//so that all resets can be handled at the same time
assign SampleEdge = SckMode[0] ? (state == ACTIVE_1) : (state == ACTIVE_0);
assign TransmitDataEndian = Format[2] ? {TransmitData[0], TransmitData[1], TransmitData[2], TransmitData[3], TransmitData[4], TransmitData[5], TransmitData[6], TransmitData[7]} : TransmitData[7:0];
TransmitFIFO #(3,8) txFIFO(PCLK, SCLKDuty, PRESETn, TransmitFIFOWriteIncrementDelay, TransmitFIFOReadIncrement, TransmitDataEndian,TransmitWriteWatermarkLevel, TransmitWatermark[2:0], TransmitFIFOReadData[7:0], TransmitFIFOWriteFull, TransmitFIFOReadEmpty, TransmitWriteMark, TransmitReadMark);
ReceiveFIFO #(3,8) rxFIFO(SCLKDuty, PCLK, PRESETn, ReceiveFIFOWriteIncrement, ReceiveFIFOReadIncrement, ReceiveShiftRegEndian, ReceiveWatermark[2:0], ReceiveReadWatermarkLevel, ReceiveData[7:0], ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty, RecieveWriteMark, RecieveReadMark);
TransmitShiftFSM TransmitShiftFSM_1 (PCLK, PRESETn, TransmitFIFOReadEmpty, ReceivePenultimateFrameBoolean, Active0, TransmitShiftEmpty);
ReceiveShiftFSM ReceiveShiftFSM_1 (PCLK, PRESETn, SCLKDuty, ReceivePenultimateFrameBoolean, SampleEdge, SckMode[0], ReceiveShiftFull);
always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) TransmitFIFOReadEmptyDelay <= 1;
else if (SCLKDuty) TransmitFIFOReadEmptyDelay <= TransmitFIFOReadEmpty;
logic SCLKDutyDelay;
always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) SCLKDutyDelay <= 0;
else SCLKDutyDelay <= SCLKDuty;
always_comb
case(SckMode[1:0])
2'b00: sckPhaseSelect = ~sck & SCLKDuty;
2'b01: sckPhaseSelect = (sck & |(FrameCount) & SCLKDuty);
2'b10: sckPhaseSelect = sck & SCLKDuty;
2'b11: sckPhaseSelect = (~sck & |(FrameCount) & SCLKDuty);
default: sckPhaseSelect = sck & SCLKDuty;
endcase
always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) ReceiveShiftFullDelay <= 0;
else if (SCLKDuty) ReceiveShiftFullDelay <= ReceiveShiftFull;
assign TransmitShiftRegLoad = ~TransmitShiftEmpty & ~Active | (((ChipSelectMode == 2'b10) & ~|(Delay1[15:8])) & ((ReceiveShiftFullDelay | ReceiveShiftFull) & ~SampleEdge & ~TransmitFIFOReadEmpty));
always_ff @(posedge PCLK, negedge PRESETn)
if(~PRESETn) begin
TransmitShiftReg <= 8'b0;
end
else if (TransmitShiftRegLoad) TransmitShiftReg <= TransmitFIFOReadData;
else if (sckPhaseSelect) begin
//if ((ChipSelectMode[1:0] == 2'b10) & ~|(Delay1[15:8]) & (~TransmitFIFOReadEmpty) & TransmitShiftEmpty) TransmitShiftReg <= TransmitFIFOReadData;
if (Active) begin
case (Format[1:0])
2'b00: TransmitShiftReg <= {TransmitShiftReg[6:0], 1'b0};
2'b01: TransmitShiftReg <= {TransmitShiftReg[5:0], 2'b0};
2'b10: TransmitShiftReg <= {TransmitShiftReg[3:0], 4'b0};
default: TransmitShiftReg <= {TransmitShiftReg[6:0], 1'b0};
endcase
end
end
always_comb
if (Active | Delay0Compare | ~TransmitShiftEmpty) begin
case(Format[1:0])
2'b00: SPIOut = {3'b0,TransmitShiftReg[7]};
2'b01: SPIOut = {2'b0,TransmitShiftReg[6], TransmitShiftReg[7]};
// assuming SPIOut[0] is first bit transmitted etc
2'b10: SPIOut = {TransmitShiftReg[3], TransmitShiftReg[2], TransmitShiftReg[1], TransmitShiftReg[0]};
default: SPIOut = {3'b0, TransmitShiftReg[7]};
endcase
end else SPIOut = 4'b0;
logic [3:0] shiftin;
assign shiftin = P.SPI_LOOPBACK_TEST ? SPIOut : SPIIn;
always_ff @(posedge PCLK, negedge PRESETn)
if(~PRESETn) ReceiveShiftReg <= 8'b0;
else if (SampleEdge & SCLKDuty) begin
if (~Active) ReceiveShiftReg <= 8'b0;
else if (~Format[3]) begin
case(Format[1:0])
2'b00: ReceiveShiftReg <= { ReceiveShiftReg[6:0], shiftin[0]};
2'b01: ReceiveShiftReg <= { ReceiveShiftReg[5:0], shiftin[0],shiftin[1]};
2'b10: ReceiveShiftReg <= { ReceiveShiftReg[3:0], shiftin[0], shiftin[1], shiftin[2], shiftin[3]};
default: ReceiveShiftReg <= { ReceiveShiftReg[6:0], shiftin[0]};
endcase
end
end
logic [7:0] ReceiveShiftRegInvert;
assign ReceiveShiftRegInvert = (Format[2]) ? {ReceiveShiftReg[0], ReceiveShiftReg[1], ReceiveShiftReg[2], ReceiveShiftReg[3], ReceiveShiftReg[4], ReceiveShiftReg[5], ReceiveShiftReg[6], ReceiveShiftReg[7]} : ReceiveShiftReg[7:0];
always_comb
if (Format[2]) begin
case(Format[7:4])
4'b0001: ReceiveShiftRegEndian = {7'b0, ReceiveShiftRegInvert[7]};
4'b0010: ReceiveShiftRegEndian = {6'b0, ReceiveShiftRegInvert[7:6]};
4'b0011: ReceiveShiftRegEndian = {5'b0, ReceiveShiftRegInvert[7:5]};
4'b0100: ReceiveShiftRegEndian = {4'b0, ReceiveShiftRegInvert[7:4]};
4'b0101: ReceiveShiftRegEndian = {3'b0, ReceiveShiftRegInvert[7:3]};
4'b0110: ReceiveShiftRegEndian = {2'b0, ReceiveShiftRegInvert[7:2]};
4'b0111: ReceiveShiftRegEndian = {1'b0, ReceiveShiftRegInvert[7:1]};
4'b1000: ReceiveShiftRegEndian = ReceiveShiftRegInvert;
default: ReceiveShiftRegEndian = ReceiveShiftRegInvert;
endcase
end else begin
case(Format[7:4])
4'b0001: ReceiveShiftRegEndian = {ReceiveShiftRegInvert[0], 7'b0};
4'b0010: ReceiveShiftRegEndian = {ReceiveShiftRegInvert[1:0], 6'b0};
4'b0011: ReceiveShiftRegEndian = {ReceiveShiftRegInvert[2:0], 5'b0};
4'b0100: ReceiveShiftRegEndian = {ReceiveShiftRegInvert[3:0], 4'b0};
4'b0101: ReceiveShiftRegEndian = {ReceiveShiftRegInvert[4:0], 3'b0};
4'b0110: ReceiveShiftRegEndian = {ReceiveShiftRegInvert[5:0], 2'b0};
4'b0111: ReceiveShiftRegEndian = {ReceiveShiftRegInvert[6:0], 1'b0};
4'b1000: ReceiveShiftRegEndian = ReceiveShiftRegInvert;
default: ReceiveShiftRegEndian = ReceiveShiftRegInvert;
endcase
end
assign SPIIntr = |(InterruptPending & InterruptEnable);
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);
)
*/
module TransmitFIFO #(parameter M = 3, N = 8)(
input logic wclk, rclk, 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] wq1_rptr, wq2_rptr, rptr;
logic [M:0] rq1_wptr, rq2_wptr, wptr;
logic [M:0] rbin, rgraynext, rbinnext;
logic [M:0] wbin, wgraynext, wbinnext;
logic rempty_val;
logic wfull_val;
logic [M:0] wq2_rptr_bin, rq2_wptr_bin;
logic [M-1:0] raddr;
logic [M-1:0] waddr;
assign rdata = mem[raddr];
always_ff @(posedge wclk)
if(winc & ~wfull) mem[waddr] <= wdata;
always_ff @(posedge wclk, negedge PRESETn)
if (~PRESETn) begin
wq2_rptr <= 0;
wq1_rptr <= 0;
end
else begin
wq2_rptr <= wq1_rptr;
wq1_rptr <= rptr;
end
always_ff @(posedge wclk, negedge PRESETn)
if (~PRESETn) begin
rq2_wptr <= 0;
rq1_wptr <= 0;
end
else if (rclk) begin
rq2_wptr <= rq1_wptr;
rq1_wptr <= wptr;
end
always_ff @(posedge wclk, negedge PRESETn)
if(~PRESETn) begin
rbin <= 0;
rptr <= 0;
end
else if (rclk) begin
rbin <= rbinnext;
rptr <= rgraynext;
end
assign rq2_wptr_bin = {rq2_wptr[3], (rq2_wptr[3]^rq2_wptr[2]),(rq2_wptr[3]^rq2_wptr[2]^rq2_wptr[1]), (rq2_wptr[3]^rq2_wptr[2]^rq2_wptr[1]^rq2_wptr[0]) };
assign rwatermark = ((rbin[M-1:0] - rq2_wptr_bin[M-1:0]) < rwatermarklevel);
assign raddr = rbin[M-1:0];
assign rbinnext = rbin + {3'b0, (rinc & ~rempty)};
assign rgraynext = (rbinnext >> 1) ^ rbinnext;
assign rempty_val = (rgraynext == rq2_wptr);
always_ff @(posedge wclk, negedge PRESETn)
if (~PRESETn) rempty <= 1'b1;
else if (rclk) rempty <= rempty_val;
always_ff @(posedge wclk, negedge PRESETn)
if (~PRESETn) begin
wbin <= 0;
wptr <= 0;
end else begin
wbin <= wbinnext;
wptr <= wgraynext;
end
assign waddr = wbin[M-1:0];
assign wq2_rptr_bin = {wq2_rptr[3], (wq2_rptr[3]^wq2_rptr[2]),(wq2_rptr[3]^wq2_rptr[2]^wq2_rptr[1]), (wq2_rptr[3]^wq2_rptr[2]^wq2_rptr[1]^wq2_rptr[0]) };
assign wwatermark = ((wbin[M-1:0] - wq2_rptr_bin[M-1:0]) > wwatermarklevel);
assign wbinnext = wbin + {3'b0, (winc & ~wfull)};
assign wgraynext = (wbinnext >> 1) ^ wbinnext;
assign wfull_val = (wgraynext == {(~wq2_rptr[M:M-1]),wq2_rptr[M-2:0]});
always_ff @(posedge wclk, negedge PRESETn)
if (~PRESETn) wfull <= 1'b0;
else wfull <= wfull_val;
endmodule
module ReceiveFIFO #(parameter M = 3, N = 8)(
input logic wclk, rclk, 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] wq1_rptr, wq2_rptr, rptr;
logic [M:0] rq1_wptr, rq2_wptr, wptr;
logic [M:0] rbin, rgraynext, rbinnext;
logic [M:0] wbin, wgraynext, wbinnext;
logic rempty_val;
logic wfull_val;
logic [M:0] wq2_rptr_bin, rq2_wptr_bin;
logic [M-1:0] raddr;
logic [M-1:0] waddr;
assign rdata = mem[raddr];
always_ff @(posedge rclk)
if(winc & ~wfull & wclk) mem[waddr] <= wdata;
always_ff @(posedge rclk, negedge PRESETn)
if (~PRESETn) begin
wq2_rptr <= 0;
wq1_rptr <= 0;
end
else if (wclk) begin
wq2_rptr <= wq1_rptr;
wq1_rptr <= rptr;
end
always_ff @(posedge rclk, negedge PRESETn)
if (~PRESETn) begin
rq2_wptr <= 0;
rq1_wptr <= 0;
end
else begin
rq2_wptr <= rq1_wptr;
rq1_wptr <= wptr;
end
always_ff @(posedge rclk, negedge PRESETn)
if(~PRESETn) begin
rbin <= 0;
rptr <= 0;
end
else begin
rbin <= rbinnext;
rptr <= rgraynext;
end
assign rq2_wptr_bin = {rq2_wptr[3], (rq2_wptr[3]^rq2_wptr[2]),(rq2_wptr[3]^rq2_wptr[2]^rq2_wptr[1]), (rq2_wptr[3]^rq2_wptr[2]^rq2_wptr[1]^rq2_wptr[0]) };
assign rwatermark = ((rbin[M-1:0] - rq2_wptr_bin[M-1:0]) < rwatermarklevel);
assign raddr = rbin[M-1:0];
assign rbinnext = rbin + {3'b0, (rinc & ~rempty)};
assign rgraynext = (rbinnext >> 1) ^ rbinnext;
assign rempty_val = (rgraynext == rq2_wptr);
always_ff @(posedge rclk, negedge PRESETn)
if (~PRESETn) rempty <= 1'b1;
else rempty <= rempty_val;
always_ff @(posedge rclk, negedge PRESETn)
if (~PRESETn) begin
wbin <= 0;
wptr <= 0;
end else if (wclk) begin
wbin <= wbinnext;
wptr <= wgraynext;
end
assign waddr = wbin[M-1:0];
assign wq2_rptr_bin = {wq2_rptr[3], (wq2_rptr[3]^wq2_rptr[2]),(wq2_rptr[3]^wq2_rptr[2]^wq2_rptr[1]), (wq2_rptr[3]^wq2_rptr[2]^wq2_rptr[1]^wq2_rptr[0]) };
assign wwatermark = ((wbin[M-1:0] - wq2_rptr_bin[M-1:0]) > wwatermarklevel);
assign wbinnext = wbin + {3'b0, (winc & ~wfull)};
assign wgraynext = (wbinnext >> 1) ^ wbinnext;
assign wfull_val = (wgraynext == {(~wq2_rptr[M:M-1]),wq2_rptr[M-2:0]});
always_ff @(posedge rclk, negedge PRESETn)
if (~PRESETn) wfull <= 1'b0;
else if (wclk) wfull <= wfull_val;
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, SCLKDuty,
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 (SCLKDuty) 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 [3:0] SPIIn,
output logic [3:0] 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,7 +54,10 @@ 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 [3:0] SPIIn, // SPI pins in
output logic [3:0] SPIOut, // SPI pins out
output logic [3:0] SPICS // SPI chip select pins
);
// Uncore signals
@ -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,7 @@ module testbench;
logic [31:0] GPIOIN, GPIOOUT, GPIOEN;
logic UARTSin, UARTSout;
logic [3:0] SPIIn, SPIOut, SPICS;
logic SDCIntr;
logic HREADY;
@ -367,6 +367,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 +398,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

@ -1974,7 +1974,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[] = '{
@ -2060,7 +2061,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

@ -57,6 +57,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
00000101 # delay 0
00000001 # delay 1
00000080 # 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, 0x00000101, 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, 0x00000080, 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, 0x0000100, 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, 0x00000105, 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, 0x00000105, 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, 0x00000501, 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, 0x00000101, 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, 0x00000501, 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, 0x0000A501, 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, 0x00000105, 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, 0x00000501, 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, 0x00000101, 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, 0x00000040, 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, 0x00000010, 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, 0x00000050, 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, 0x00000054, 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, 0x00000081, 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, 0x00000041, 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, 0x00000051, 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, 0x00000052, 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, 0x00000042, 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, 0x00000082, 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, 0x00000080, 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

@ -55,6 +55,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,194 @@
00000003 # reset tests sck_div
00000000
00000000 # sck_mode
00000000
00000000 # cs_id
00000000
0000000F # cs_def
00000000
00000000 # cs_mode
00000000
00000101 # delay 0
00000000
00000001 # delay 1
00000000
00000080 # 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
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
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,478 @@
///////////////////////////////////////////
//
// 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, 0x00000101, 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, 0x00000080, 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, 0x0000100, 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, 0x00000105, 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, 0x00000105, 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, 0x00000501, 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, 0x00000501, 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, 0x00000101, write32_test # reset delay0 register
.8byte delay1, 0x00000005, write32_test # set inter_cs delay to 5
.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 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 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, 0x00000501, 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, 0x0000A501, write32_test
.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, 0x00000105, write32_test # set cs-sck delay to 5 (should have no effect because cs is never inactive)
.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 frame format (fmt) register ===========
# Test frame length of 4
.8byte delay1, 0x00000001, write32_test # reset delay1 register
.8byte delay0, 0x00000101, 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, 0x00000040, write32_test # set frame length to 4
.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, 0x00000010, write32_test
.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, 0x00000050, write32_test # set frame length to 5, big endian
.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 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, 0x00000054, write32_test # set frame length to 5, little-endian
.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 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, 0x00000081, 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, 0x00000041, 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, 0x00000051, 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, 0x00000052, 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, 0x00000042, 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, 0x00000082, 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 watermark interrupts ===========
# Test transmit watermark interrupt (triggers when entries in tx FIFO < tx watermark) without external enables
SETUP_PLIC
.8byte fmt, 0x00000080, write32_test # reset fmt register
.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 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