From d5d4f9d044e4402a90fd81ca76dbf5a702c01e56 Mon Sep 17 00:00:00 2001 From: naichewa Date: Thu, 12 Oct 2023 13:36:57 -0700 Subject: [PATCH 01/12] transferred spi changes in ECA-authorized commit --- config/buildroot/config.vh | 5 + config/rv32e/config.vh | 5 + config/rv32gc/config.vh | 5 + config/rv32i/config.vh | 6 + config/rv32imc/config.vh | 5 + config/rv64fpquad/config.vh | 5 + config/rv64gc/config.vh | 5 + config/rv64i/config.vh | 5 + config/shared/parameter-defs.vh | 5 + src/cvw.sv | 5 + src/mmu/adrdecs.sv | 25 +- src/mmu/pmachecker.sv | 12 +- src/uncore/plic_apb.sv | 3 +- src/uncore/spi_apb.sv | 746 ++++++++++++++++++ src/uncore/uncore.sv | 39 +- src/wally/wallypipelinedsoc.sv | 7 +- testbench/testbench.sv | 5 +- testbench/tests.vh | 6 +- .../rv32i_m/privilege/Makefrag | 1 + .../references/WALLY-spi-01.reference_output | 193 +++++ .../rv32i_m/privilege/src/WALLY-TEST-LIB-32.h | 49 +- .../rv32i_m/privilege/src/WALLY-spi-01.S | 511 ++++++++++++ .../rv64i_m/privilege/Makefrag | 3 + .../references/WALLY-spi-01.reference_output | 194 +++++ .../rv64i_m/privilege/src/WALLY-TEST-LIB-64.h | 49 +- .../rv64i_m/privilege/src/WALLY-spi-01.S | 478 +++++++++++ 26 files changed, 2324 insertions(+), 48 deletions(-) create mode 100644 src/uncore/spi_apb.sv create mode 100644 tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/references/WALLY-spi-01.reference_output create mode 100644 tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-spi-01.S create mode 100644 tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-spi-01.reference_output create mode 100644 tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S diff --git a/config/buildroot/config.vh b/config/buildroot/config.vh index b25e8fe9c..92ef21103 100644 --- a/config/buildroot/config.vh +++ b/config/buildroot/config.vh @@ -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; diff --git a/config/rv32e/config.vh b/config/rv32e/config.vh index 35e85003d..ad6e7f119 100644 --- a/config/rv32e/config.vh +++ b/config/rv32e/config.vh @@ -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; diff --git a/config/rv32gc/config.vh b/config/rv32gc/config.vh index 06be2e01b..461048952 100644 --- a/config/rv32gc/config.vh +++ b/config/rv32gc/config.vh @@ -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; diff --git a/config/rv32i/config.vh b/config/rv32i/config.vh index 5e03d3e93..ffaf50d2c 100644 --- a/config/rv32i/config.vh +++ b/config/rv32i/config.vh @@ -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; diff --git a/config/rv32imc/config.vh b/config/rv32imc/config.vh index cb031d2db..823b2c766 100644 --- a/config/rv32imc/config.vh +++ b/config/rv32imc/config.vh @@ -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; diff --git a/config/rv64fpquad/config.vh b/config/rv64fpquad/config.vh index 63a35c7f5..16b9b7016 100644 --- a/config/rv64fpquad/config.vh +++ b/config/rv64fpquad/config.vh @@ -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; diff --git a/config/rv64gc/config.vh b/config/rv64gc/config.vh index f17761e33..47b24ec6c 100644 --- a/config/rv64gc/config.vh +++ b/config/rv64gc/config.vh @@ -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; diff --git a/config/rv64i/config.vh b/config/rv64i/config.vh index d87708c18..dd6b645e1 100644 --- a/config/rv64i/config.vh +++ b/config/rv64i/config.vh @@ -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; diff --git a/config/shared/parameter-defs.vh b/config/shared/parameter-defs.vh index f3f216062..b24be045e 100644 --- a/config/shared/parameter-defs.vh +++ b/config/shared/parameter-defs.vh @@ -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 */ diff --git a/src/cvw.sv b/src/cvw.sv index 01e0d6376..4283172b3 100644 --- a/src/cvw.sv +++ b/src/cvw.sv @@ -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; diff --git a/src/mmu/adrdecs.sv b/src/mmu/adrdecs.sv index f3017ec54..3ee9c23d5 100644 --- a/src/mmu/adrdecs.sv +++ b/src/mmu/adrdecs.sv @@ -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 diff --git a/src/mmu/pmachecker.sv b/src/mmu/pmachecker.sv index 119e88d8c..cd47eadfe 100644 --- a/src/mmu/pmachecker.sv +++ b/src/mmu/pmachecker.sv @@ -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; diff --git a/src/uncore/plic_apb.sv b/src/uncore/plic_apb.sv index f2a643101..f9a2f6240 100644 --- a/src/uncore/plic_apb.sv +++ b/src/uncore/plic_apb.sv @@ -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 diff --git a/src/uncore/spi_apb.sv b/src/uncore/spi_apb.sv new file mode 100644 index 000000000..e1bfdb264 --- /dev/null +++ b/src/uncore/spi_apb.sv @@ -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 + + + + + + diff --git a/src/uncore/uncore.sv b/src/uncore/uncore.sv index d5822c914..3f9aae238 100644 --- a/src/uncore/uncore.sv +++ b/src/uncore/uncore.sv @@ -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 diff --git a/src/wally/wallypipelinedsoc.sv b/src/wally/wallypipelinedsoc.sv index 2764d55f3..336bb7a6a 100644 --- a/src/wally/wallypipelinedsoc.sv +++ b/src/wally/wallypipelinedsoc.sv @@ -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 diff --git a/testbench/testbench.sv b/testbench/testbench.sv index 74077e547..f58136b97 100644 --- a/testbench/testbench.sv +++ b/testbench/testbench.sv @@ -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 diff --git a/testbench/tests.vh b/testbench/tests.vh index 8ba4ce8d1..461b21cee 100644 --- a/testbench/tests.vh +++ b/testbench/tests.vh @@ -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" }; diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/Makefrag b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/Makefrag index 837668c3c..905dd0d25 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/Makefrag +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/Makefrag @@ -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 \ diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/references/WALLY-spi-01.reference_output b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/references/WALLY-spi-01.reference_output new file mode 100644 index 000000000..17f854a4b --- /dev/null +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/references/WALLY-spi-01.reference_output @@ -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 diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-TEST-LIB-32.h b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-TEST-LIB-32.h index b6304fbc6..abbfbaf56 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-TEST-LIB-32.h +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-TEST-LIB-32.h @@ -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) diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-spi-01.S b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-spi-01.S new file mode 100644 index 000000000..df5198473 --- /dev/null +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-spi-01.S @@ -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 \ No newline at end of file diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/Makefrag b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/Makefrag index bc5f454bb..3da637565 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/Makefrag +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/Makefrag @@ -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 \ diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-spi-01.reference_output b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-spi-01.reference_output new file mode 100644 index 000000000..eb9c02256 --- /dev/null +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-spi-01.reference_output @@ -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 \ No newline at end of file diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-TEST-LIB-64.h b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-TEST-LIB-64.h index 23f105cbc..9e1dcb264 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-TEST-LIB-64.h +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-TEST-LIB-64.h @@ -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) diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S new file mode 100644 index 000000000..ae4eb581d --- /dev/null +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S @@ -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 \ No newline at end of file From f231c3d3a37755694903134cde1268796aa01839 Mon Sep 17 00:00:00 2001 From: naichewa Date: Thu, 12 Oct 2023 15:13:23 -0700 Subject: [PATCH 02/12] correct delay0, fmt register test entries --- .../rv32i_m/privilege/src/WALLY-spi-01.S | 46 +++++++++---------- .../rv64i_m/privilege/src/WALLY-spi-01.S | 44 +++++++++--------- 2 files changed, 45 insertions(+), 45 deletions(-) diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-spi-01.S b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-spi-01.S index df5198473..ad2501909 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-spi-01.S +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-spi-01.S @@ -106,9 +106,9 @@ test_cases: .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 delay0, 0x00010001, read32_test # delay0 reset to [31:24] 0x0, [23:16] 0x1, [15:8] 0x0, [7:0] 0x1 .4byte delay1, 0x00000001, read32_test # delay1 reset to 0x1 -.4byte fmt, 0x00000080, read32_test # fmt reset to [31:20] 0x0, [19:16] 0x8, [15:0] 0x0 for non-flash enabled SPI controllers +.4byte fmt, 0x00080000, read32_test # fmt reset to [31:20] 0x0, [19:16] 0x8, [15:0] 0x0 for non-flash enabled SPI controllers .4byte tx_data, 0x00000000, read32_test # tx_data [30:0] reset to 0x0, [31] read only .4byte tx_mark, 0x00000000, read32_test # tx_mark reset to 0x0 for non-flash enabled controllers .4byte rx_mark, 0x00000000, read32_test # rx_mark reset to 0x0 @@ -182,7 +182,7 @@ test_cases: # 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 delay0, 0x00010000, write32_test # set cs-sck delay to 0 .4byte tx_data, 0x00000020, write32_test # place 8'h11 into tx_data .4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end .4byte rx_data, 0x00000020, read32_test # read rx_data @@ -196,7 +196,7 @@ test_cases: # Test arbitrary cs-sck delay (sck phase 1) -.4byte delay0, 0x00000105, write32_test # set cs-sck delay to 5 cycles +.4byte delay0, 0x00010005, write32_test # set cs-sck delay to 5 cycles .4byte tx_data, 0x00000048, write32_test # place 8'h11 into tx_data .4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end .4byte rx_data, 0x00000048, read32_test # read rx_data @@ -204,7 +204,7 @@ test_cases: # 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 delay0, 0x00010005, write32_test # set cs-sck delay to AF cycles .4byte tx_data, 0x000000AF, write32_test # place 8'h11 into tx_data .4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end .4byte rx_data, 0x000000AF, read32_test # read rx_data @@ -234,7 +234,7 @@ test_cases: # 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 delay0, 0x00050001, write32_test # set cs-sck delay to 5 cycles .4byte tx_data, 0x00000015, write32_test # place 8'h11 into tx_data .4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end .4byte rx_data, 0x00000015, read32_test # read rx_data @@ -244,7 +244,7 @@ test_cases: # Test inter cs delay -.4byte delay0, 0x00000101, write32_test # reset delay0 register +.4byte delay0, 0x00010001, write32_test # reset delay0 register .4byte delay1, 0x00000005, write32_test # set inter_cs delay to 5 .4byte tx_data, 0x44332211, spi_burst_send .4byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end @@ -295,7 +295,7 @@ test_cases: # Test arbitrary inter_xfr delay -.4byte delay1, 0x00000501, write32_test # set inter_xfr delay to 5 +.4byte delay1, 0x00050001, write32_test # set inter_xfr delay to 5 .4byte sck_mode, 0x00000001, write32_test .4byte tx_data, 0x98877665, spi_burst_send .4byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end @@ -305,7 +305,7 @@ test_cases: .4byte rx_data, 0x00000098, read32_test # test long inter_xfr delay -.4byte delay1, 0x0000A501, write32_test +.4byte delay1, 0x00A50001, write32_test .4byte tx_data, 0x00000048, write32_test .4byte 0x0, 0x00000000, spi_data_wait .4byte rx_data, 0x00000048, read32_test @@ -313,7 +313,7 @@ test_cases: # 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 delay0, 0x00010005, write32_test # set cs-sck delay to 5 (should have no effect because cs is never inactive) .4byte tx_data, 0xAABBCCDD, spi_burst_send .4byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end .4byte rx_data, 0x000000DD, read32_test # read rx_data @@ -323,7 +323,7 @@ test_cases: # 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 delay0, 0x00050001, write32_test # set sck-cs delay to 5 (should have no effect because cs is never inactive) .4byte tx_data, 0xABBCCDDE, spi_burst_send # place 8'h11 into tx_data .4byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end .4byte rx_data, 0x000000DE, read32_test # read rx_data @@ -336,10 +336,10 @@ test_cases: # Test frame length of 4 .4byte delay1, 0x00000001, write32_test # reset delay1 register -.4byte delay0, 0x00000101, write32_test # reset delay0 register +.4byte delay0, 0x00010001, write32_test # reset delay0 register .4byte sck_mode, 0x00000000, write32_test #reset sckmode register .4byte cs_mode, 0x00000000, write32_test # set cs_mode to AUTO -.4byte fmt, 0x00000040, write32_test # set frame length to 4 +.4byte fmt, 0x00040000, write32_test # set frame length to 4 .4byte tx_data, 0x000000F0, write32_test # place 8'h11 into tx_data .4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end .4byte rx_data, 0x000000F0, read32_test # read rx_data @@ -352,7 +352,7 @@ test_cases: #.4byte rx_data, 0x00000077, read32_test # read rx_data # test frame length 1 burst -.4byte fmt, 0x00000010, write32_test +.4byte fmt, 0x00010000, write32_test .4byte tx_data, 0x80008000, spi_burst_send .4byte 0x0, 0x00000003, spi_data_wait .4byte rx_data, 0x00000000, read32_test @@ -363,7 +363,7 @@ test_cases: # Test big endian with frame length = 5 -.4byte fmt, 0x00000050, write32_test # set frame length to 5, big endian +.4byte fmt, 0x00050000, write32_test # set frame length to 5, big endian .4byte tx_data, 0x000000A8, write32_test # place 8'h11 into tx_data .4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end .4byte rx_data, 0x000000A8, read32_test # read rx_data @@ -382,7 +382,7 @@ test_cases: # Test little endian with frame length = 5 -.4byte fmt, 0x00000054, write32_test # set frame length to 5, little-endian +.4byte fmt, 0x00050004, write32_test # set frame length to 5, little-endian .4byte tx_data, 0x000000A8, write32_test # place 8'h11 into tx_data .4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end .4byte rx_data, 0x00000008, read32_test # read rx_data -> 08 @@ -398,21 +398,21 @@ test_cases: # Test dual SPI protocol, frame length = 8, big endian -#.4byte fmt, 0x00000081, write32_test # set frame length to 8, big-endian, dual SPI +#.4byte fmt, 0x00080001, write32_test # set frame length to 8, big-endian, dual SPI #.4byte tx_data, 0x000000C8, write32_test # place 8'h11 into tx_data #.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end #.4byte rx_data, 0x00000000, read32_test # read rx_data # Test dual SPI protocol, frame length = 4 -#.4byte fmt, 0x00000041, write32_test # set frame length to 8, big-endian, dual SPI +#.4byte fmt, 0x00040001, write32_test # set frame length to 8, big-endian, dual SPI #.4byte tx_data, 0x000000A2, write32_test # place 8'h11 into tx_data #.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end #.4byte rx_data, 0x000000A0, read32_test # read rx_data # Test dual SPI protocol, frame length = 5 -#.4byte fmt, 0x00000051, write32_test # set frame length to 8, big-endian, dual SPI +#.4byte fmt, 0x00050001, write32_test # set frame length to 8, big-endian, dual SPI #.4byte tx_data, 0x00000075, write32_test # place 8'h11 into tx_data #.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end #.4byte rx_data, 0x00000074, read32_test # read rx_data @@ -427,21 +427,21 @@ test_cases: # Test quad SPI protocol, frame length = 5 -#.4byte fmt, 0x00000052, write32_test # set frame length to 8, big-endian, dual SPI +#.4byte fmt, 0x00050002, write32_test # set frame length to 8, big-endian, dual SPI #.4byte tx_data, 0x0000003F, write32_test # place 8'h11 into tx_data #.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end #.4byte rx_data, 0x0000003F, read32_test # read rx_data # Test quad SPI protocol, frame length = 4 -#.4byte fmt, 0x00000042, write32_test # set frame length to 8, big-endian, dual SPI +#.4byte fmt, 0x00040002, write32_test # set frame length to 8, big-endian, dual SPI #.4byte tx_data, 0x0000000F, write32_test # place 8'h11 into tx_data #.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end #.4byte rx_data, 0x00000000, read32_test # read rx_data # Test quad SPI protocol, frame length = 8 -#.4byte fmt, 0x00000082, write32_test # set frame length to 8, big-endian, dual SPI +#.4byte fmt, 0x00080002, write32_test # set frame length to 8, big-endian, dual SPI #.4byte tx_data, 0x000000F0, write32_test # place 8'h11 into tx_data #.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end #.4byte rx_data, 0x000000F0, read32_test # read rx_data @@ -453,7 +453,7 @@ test_cases: SETUP_PLIC -.4byte fmt, 0x00000080, write32_test # reset fmt register +.4byte fmt, 0x00080000, write32_test # reset fmt register .4byte tx_mark, 0x00000004, write32_test # set transmit watermark to 4 #.4byte ie, 0x00000000, write32_test # enable transmit interrupt .4byte ip, 0x00000001, read32_test # tx watermark interupt should be pending diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S index ae4eb581d..85c0f4d4c 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S @@ -76,9 +76,9 @@ test_cases: .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 delay0, 0x00010001, read32_test # delay0 reset to [31:24] 0x0, [23:16] 0x1, [15:8] 0x0, [7:0] 0x1 .8byte delay1, 0x00000001, read32_test # delay1 reset to 0x1 -.8byte fmt, 0x00000080, read32_test # fmt reset to [31:20] 0x0, [19:16] 0x8, [15:0] 0x0 for non-flash enabled SPI controllers +.8byte fmt, 0x00080000, read32_test # fmt reset to [31:20] 0x0, [19:16] 0x8, [15:0] 0x0 for non-flash enabled SPI controllers .8byte tx_data, 0x00000000, read32_test # tx_data [30:0] reset to 0x0, [31] read only .8byte tx_mark, 0x00000000, read32_test # tx_mark reset to 0x0 for non-flash enabled controllers .8byte rx_mark, 0x00000000, read32_test # rx_mark reset to 0x0 @@ -152,7 +152,7 @@ test_cases: # 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 delay0, 0x00010000, write32_test # set cs-sck delay to 0 .8byte tx_data, 0x00000020, write32_test # place 8'h11 into tx_data .8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end .8byte rx_data, 0x00000020, read32_test # read rx_data @@ -174,7 +174,7 @@ test_cases: # 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 delay0, 0x00010005, write32_test # set cs-sck delay to AF cycles .8byte tx_data, 0x000000AF, write32_test # place 8'h11 into tx_data .8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end .8byte rx_data, 0x000000AF, read32_test # read rx_data @@ -196,7 +196,7 @@ test_cases: # Test arbitrary sck-cs delay (sck phase 1) -.8byte delay0, 0x00000501, write32_test # set cs-sck delay to A5 cycles +.8byte delay0, 0x00050001, write32_test # set cs-sck delay to A5 cycles .8byte tx_data, 0x00000011, write32_test # place 8'h11 into tx_data .8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end .8byte rx_data, 0x00000011, read32_test # read rx_data @@ -204,7 +204,7 @@ test_cases: # 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 delay0, 0x00050001, write32_test # set cs-sck delay to 5 cycles .8byte tx_data, 0x00000015, write32_test # place 8'h11 into tx_data .8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end .8byte rx_data, 0x00000015, read32_test # read rx_data @@ -214,7 +214,7 @@ test_cases: # Test inter cs delay -.8byte delay0, 0x00000101, write32_test # reset delay0 register +.8byte delay0, 0x00010001, 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 @@ -265,7 +265,7 @@ test_cases: # Test arbitrary inter_xfr delay -.8byte delay1, 0x00000501, write32_test # set inter_xfr delay to 5 +.8byte delay1, 0x00050001, write32_test # set inter_xfr delay to 5 .8byte sck_mode, 0x00000001, write32_test .8byte tx_data, 0x98877665, spi_burst_send .8byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end @@ -275,7 +275,7 @@ test_cases: .8byte rx_data, 0x00000098, read32_test # test long inter_xfr delay -.8byte delay1, 0x0000A501, write32_test +.8byte delay1, 0x00A50001, write32_test .8byte tx_data, 0x00000048, write32_test .8byte 0x0, 0x00000000, spi_data_wait .8byte rx_data, 0x00000048, read32_test @@ -283,7 +283,7 @@ test_cases: # 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 delay0, 0x00010005, 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 @@ -306,10 +306,10 @@ test_cases: # Test frame length of 4 .8byte delay1, 0x00000001, write32_test # reset delay1 register -.8byte delay0, 0x00000101, write32_test # reset delay0 register +.8byte delay0, 0x00010001, write32_test # reset delay0 register .8byte sck_mode, 0x00000000, write32_test #reset sckmode register .8byte cs_mode, 0x00000000, write32_test # set cs_mode to AUTO -.8byte fmt, 0x00000040, write32_test # set frame length to 4 +.8byte fmt, 0x00040000, 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 @@ -322,7 +322,7 @@ test_cases: #.8byte rx_data, 0x00000077, read32_test # read rx_data # test frame length 1 burst -.8byte fmt, 0x00000010, write32_test +.8byte fmt, 0x00010000, write32_test .8byte tx_data, 0x80008000, spi_burst_send .8byte 0x0, 0x00000003, spi_data_wait .8byte rx_data, 0x00000000, read32_test @@ -333,7 +333,7 @@ test_cases: # Test big endian with frame length = 5 -.8byte fmt, 0x00000050, write32_test # set frame length to 5, big endian +.8byte fmt, 0x00050000, 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 @@ -352,7 +352,7 @@ test_cases: # Test little endian with frame length = 5 -.8byte fmt, 0x00000054, write32_test # set frame length to 5, little-endian +.8byte fmt, 0x00050004, 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 @@ -368,21 +368,21 @@ test_cases: # Test dual SPI protocol, frame length = 8, big endian -#.8byte fmt, 0x00000081, write32_test # set frame length to 8, big-endian, dual SPI +#.8byte fmt, 0x00080001, write32_test # set frame length to 8, big-endian, dual SPI #.8byte tx_data, 0x000000C8, write32_test # place 8'h11 into tx_data #.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end #.8byte rx_data, 0x00000000, read32_test # read rx_data # Test dual SPI protocol, frame length = 4 -#.8byte fmt, 0x00000041, write32_test # set frame length to 8, big-endian, dual SPI +#.8byte fmt, 0x00040001, write32_test # set frame length to 8, big-endian, dual SPI #.8byte tx_data, 0x000000A2, write32_test # place 8'h11 into tx_data #.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end #.8byte rx_data, 0x000000A0, read32_test # read rx_data # Test dual SPI protocol, frame length = 5 -#.8byte fmt, 0x00000051, write32_test # set frame length to 8, big-endian, dual SPI +#.8byte fmt, 0x00050001, write32_test # set frame length to 8, big-endian, dual SPI #.8byte tx_data, 0x00000075, write32_test # place 8'h11 into tx_data #.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end #.8byte rx_data, 0x00000074, read32_test # read rx_data @@ -397,21 +397,21 @@ test_cases: # Test quad SPI protocol, frame length = 5 -#.8byte fmt, 0x00000052, write32_test # set frame length to 8, big-endian, dual SPI +#.8byte fmt, 0x00050002, write32_test # set frame length to 8, big-endian, dual SPI #.8byte tx_data, 0x0000003F, write32_test # place 8'h11 into tx_data #.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end #.8byte rx_data, 0x0000003F, read32_test # read rx_data # Test quad SPI protocol, frame length = 4 -#.8byte fmt, 0x00000042, write32_test # set frame length to 8, big-endian, dual SPI +#.8byte fmt, 0x00040002, write32_test # set frame length to 8, big-endian, dual SPI #.8byte tx_data, 0x0000000F, write32_test # place 8'h11 into tx_data #.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end #.8byte rx_data, 0x00000000, read32_test # read rx_data # Test quad SPI protocol, frame length = 8 -#.8byte fmt, 0x00000082, write32_test # set frame length to 8, big-endian, dual SPI +#.8byte fmt, 0x00080002, write32_test # set frame length to 8, big-endian, dual SPI #.8byte tx_data, 0x000000F0, write32_test # place 8'h11 into tx_data #.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end #.8byte rx_data, 0x000000F0, read32_test # read rx_data @@ -422,7 +422,7 @@ test_cases: SETUP_PLIC -.8byte fmt, 0x00000080, write32_test # reset fmt register +.8byte fmt, 0x00080000, 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 From aa5abfc8e8d0e5f00e41ecab4861d2913337fa31 Mon Sep 17 00:00:00 2001 From: naichewa Date: Fri, 13 Oct 2023 14:22:32 -0700 Subject: [PATCH 03/12] always working after reg bit swizzle changes --- src/uncore/spi_apb.sv | 55 +++++++++++-------- .../references/WALLY-spi-01.reference_output | 4 +- .../references/WALLY-spi-01.reference_output | 4 +- 3 files changed, 35 insertions(+), 28 deletions(-) diff --git a/src/uncore/spi_apb.sv b/src/uncore/spi_apb.sv index e1bfdb264..ffd02e52b 100644 --- a/src/uncore/spi_apb.sv +++ b/src/uncore/spi_apb.sv @@ -191,29 +191,20 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( 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; + 8'h00: Dout <= #1 {20'b0, SckDiv}; + 8'h04: Dout <= #1 {30'b0, SckMode}; + 8'h10: Dout <= #1 {30'b0, ChipSelectID}; + 8'h14: Dout <= #1 {28'b0, ChipSelectDef}; + 8'h18: Dout <= #1 {30'b0, ChipSelectMode}; + 8'h28: Dout <= {8'b0, Delay0[15:8], 8'b0, Delay0[7:0]}; + 8'h2C: Dout <= {8'b0, Delay1[15:8], 8'b0, Delay1[7:0]}; + 8'h40: Dout <= {12'b0, Format[7:4], 12'b0, Format[3:0]}; + 8'h48: Dout <= #1 {23'b0, TransmitFIFOWriteFull, 8'b0}; + 8'h4C: Dout <= #1 {23'b0, ReceiveFIFOReadEmpty, ReceiveData[7:0]}; + 8'h50: Dout <= #1 {29'b0, TransmitWatermark}; + 8'h54: Dout <= #1 {29'b0, ReceiveWatermark}; + 8'h70: Dout <= #1 {30'b0, InterruptEnable}; + 8'h74: Dout <= #1 {30'b0, InterruptPending}; default: Dout <= #1 32'b0; endcase end @@ -507,7 +498,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( endmodule /* -module synchFIFO #(parameter M =3 , N= 8( +module TransmitSynchFIFO #(parameter M =3 , N= 8( input logic PCLK, wen, ren, PRESETn, input logic winc,rinc, input logic [N-1:0] wdata, @@ -515,6 +506,22 @@ module synchFIFO #(parameter M =3 , N= 8( output logic [N-1:0] rdata, output logic wfull, rempty, output logic wwatermark, rwatermark); + + logic [N-1:0] mem[2**M]; + logic [M:0] rptr, wptr; + logic [M:0] wbin, wbinnext; + logic [M:0] rbin, rbinnext; + logic rempty_val; + logic wfull_val; + logic [M-1:0] raddr; + logic [M-1:0] waddr; + + assign rdata = mem[raddr]; + + always_ff @(posedge wclkc, negedge PRESETn) + if (~PRESETn) begin + + ) */ diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/references/WALLY-spi-01.reference_output b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/references/WALLY-spi-01.reference_output index 17f854a4b..246e5d46a 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/references/WALLY-spi-01.reference_output +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/references/WALLY-spi-01.reference_output @@ -8,11 +8,11 @@ 00000000 # cs_mode -00000101 # delay 0 +00010001 # delay 0 00000001 # delay 1 -00000080 # fmt +00080000 # fmt 00000000 # tx_data diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-spi-01.reference_output b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-spi-01.reference_output index eb9c02256..e8e10dc90 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-spi-01.reference_output +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-spi-01.reference_output @@ -8,11 +8,11 @@ 00000000 00000000 # cs_mode 00000000 -00000101 # delay 0 +00010001 # delay 0 00000000 00000001 # delay 1 00000000 -00000080 # fmt +00080000 # fmt 00000000 00000000 # tx_data 00000000 From 4941fe1769dea0600e92600862b1e8c1f1552acb Mon Sep 17 00:00:00 2001 From: naichewa Date: Mon, 16 Oct 2023 22:57:02 -0700 Subject: [PATCH 04/12] sync fifo passes --- sim/sim-wally | 2 +- src/uncore/spi_apb.sv | 103 ++++++++++++++++++++++++++++++++++++----- testbench/testbench.sv | 2 +- testbench/tests.vh | 12 ++--- 4 files changed, 99 insertions(+), 20 deletions(-) diff --git a/sim/sim-wally b/sim/sim-wally index 410cc5406..78558c7f1 100755 --- a/sim/sim-wally +++ b/sim/sim-wally @@ -1,2 +1,2 @@ -vsim -do "do wally.do rv64gc arch64d" +vsim -do "do wally.do rv64gc wally64periph" diff --git a/src/uncore/spi_apb.sv b/src/uncore/spi_apb.sv index ffd02e52b..deaccc346 100644 --- a/src/uncore/spi_apb.sv +++ b/src/uncore/spi_apb.sv @@ -380,8 +380,10 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( 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); + //TransmitFIFO #(3,8) txFIFO(PCLK, SCLKDuty, PRESETn, TransmitFIFOWriteIncrementDelay, TransmitFIFOReadIncrement, TransmitDataEndian,TransmitWriteWatermarkLevel, TransmitWatermark[2:0], TransmitFIFOReadData[7:0], TransmitFIFOWriteFull, TransmitFIFOReadEmpty, TransmitWriteMark, TransmitReadMark); + TransmitSynchFIFO #(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); + ReceiveSynchFIFO #(3,8) rxFIFO(PCLK, SCLKDuty, 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); @@ -497,9 +499,9 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( endmodule -/* -module TransmitSynchFIFO #(parameter M =3 , N= 8( - input logic PCLK, wen, ren, PRESETn, + +module TransmitSynchFIFO #(parameter M =3 , N= 8)( + input logic PCLK, ren, PRESETn, input logic winc,rinc, input logic [N-1:0] wdata, input logic [M-1:0] wwatermarklevel, rwatermarklevel, @@ -509,22 +511,99 @@ module TransmitSynchFIFO #(parameter M =3 , N= 8( logic [N-1:0] mem[2**M]; logic [M:0] rptr, wptr; - logic [M:0] wbin, wbinnext; - logic [M:0] rbin, rbinnext; + logic [M:0] rptrnext, wptrnext; logic rempty_val; logic wfull_val; logic [M-1:0] raddr; logic [M-1:0] waddr; assign rdata = mem[raddr]; + always_ff @(posedge PCLK) + if (winc & ~wfull) mem[waddr] <= wdata; + + always_ff @(posedge PCLK, negedge PRESETn) + if (~PRESETn) rptr <= 0; + else if (ren) rptr <= rptrnext; + + + assign raddr = rptr[M-1:0]; + assign rptrnext = rptr + {3'b0, (rinc & ~rempty)}; - always_ff @(posedge wclkc, negedge PRESETn) - if (~PRESETn) begin - -) -*/ + always_ff @(posedge PCLK, negedge PRESETn) + if (~PRESETn) wptr <= 0; + else wptr <= wptrnext; + + assign waddr = wptr[M-1:0]; + assign wwatermark = ((wptr[M-1:0] - rptr[M-1:0]) > wwatermarklevel); + assign wptrnext = wptr + {3'b0, (winc & ~wfull)}; + + assign rempty_val = (wptr == rptrnext); + assign wfull_val = ({~wptrnext[M], wptrnext[M-1:0]} == rptr); + + assign rwatermark = ((rptr[M-1:0] - wptr[M-1:0]) < rwatermarklevel); + + always_ff @(posedge PCLK, negedge PRESETn) + if (~PRESETn) wfull <= 1'b0; + else wfull <= wfull_val; + + always_ff @(posedge PCLK, negedge PRESETn) + if (~PRESETn) rempty <= 1'b1; + else if (ren) rempty <= rempty_val; + + +endmodule + + +module ReceiveSynchFIFO #(parameter M =3 , N= 8)( + input logic PCLK, ren, PRESETn, + input logic winc,rinc, + input logic [N-1:0] wdata, + input logic [M-1:0] wwatermarklevel, rwatermarklevel, + output logic [N-1:0] rdata, + output logic wfull, rempty, + output logic wwatermark, rwatermark); + + logic [N-1:0] mem[2**M]; + logic [M:0] rptr, wptr; + logic [M:0] rptrnext, wptrnext; + logic rempty_val; + logic wfull_val; + logic [M-1:0] raddr; + logic [M-1:0] waddr; + + assign rdata = mem[raddr]; + always_ff @(posedge PCLK) + if(winc & ~wfull & PCLK) mem[waddr] <= wdata; + always_ff @(posedge PCLK, negedge PRESETn) + if (~PRESETn) rptr <= 0; + else rptr <= rptrnext; + assign rwatermark = ((rptr[M-1:0] - wptr[M-1:0]) < rwatermarklevel); + assign raddr = rptr[M-1:0]; + assign rptrnext = rptr + {3'b0, (rinc & ~rempty)}; + assign rempty_val = (wptr == rptrnext); + + always_ff @(posedge PCLK, negedge PRESETn) + if (~PRESETn) rempty <= 1'b1; + else rempty <= rempty_val; + + always_ff @(posedge PCLK, negedge PRESETn) + if (~PRESETn) wptr <= 0; + else if (ren) wptr <= wptrnext; + + assign waddr = wptr[M-1:0]; + assign wwatermark = ((wptr[M-1:0] - rptr[M-1:0]) > wwatermarklevel); + assign wptrnext = wptr + {3'b0, (winc & ~wfull)}; + + assign wfull_val = ({~wptrnext[M], wptrnext[M-1:0]} == rptr); + + always_ff @(posedge PCLK, negedge PRESETn) + if (~PRESETn) wfull <= 1'b0; + else if (ren) wfull <= wfull_val; + +endmodule + module TransmitFIFO #(parameter M = 3, N = 8)( input logic wclk, rclk, PRESETn, input logic winc,rinc, diff --git a/testbench/testbench.sv b/testbench/testbench.sv index f58136b97..89e0d085a 100644 --- a/testbench/testbench.sv +++ b/testbench/testbench.sv @@ -156,7 +156,7 @@ module testbench; end if (tests.size() == 0) begin $display("TEST %s not supported in this configuration", TEST); - $stop; + //$stop; end end // initial begin diff --git a/testbench/tests.vh b/testbench/tests.vh index 461b21cee..65b0f6040 100644 --- a/testbench/tests.vh +++ b/testbench/tests.vh @@ -1969,12 +1969,12 @@ string arch64zbs[] = '{ string wally64periph[] = '{ `WALLYTEST, - "rv64i_m/privilege/src/WALLY-periph-01.S", - "rv64i_m/privilege/src/WALLY-clint-01.S", - "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-periph-01.S", + //"rv64i_m/privilege/src/WALLY-clint-01.S", + //"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-spi-01.S" }; From 2330f4ee63fe8d6b0a046bc82f3652888c6140a8 Mon Sep 17 00:00:00 2001 From: naichewa Date: Mon, 30 Oct 2023 17:00:20 -0700 Subject: [PATCH 05/12] hardware interlock --- sim/sim-wally | 2 +- src/uncore/spi_apb.sv | 209 +++++++++++------- testbench/testbench.sv | 2 +- .../references/WALLY-spi-01.reference_output | 40 ++++ .../rv64i_m/privilege/src/WALLY-spi-01.S | 115 +++++++++- 5 files changed, 286 insertions(+), 82 deletions(-) diff --git a/sim/sim-wally b/sim/sim-wally index 6ffc3ca4f..78558c7f1 100755 --- a/sim/sim-wally +++ b/sim/sim-wally @@ -1,2 +1,2 @@ -vsim -do "do wally.do rv64gc wally64priv" +vsim -do "do wally.do rv64gc wally64periph" diff --git a/src/uncore/spi_apb.sv b/src/uncore/spi_apb.sv index deaccc346..9fab982ce 100644 --- a/src/uncore/spi_apb.sv +++ b/src/uncore/spi_apb.sv @@ -26,8 +26,11 @@ //////////////////////////////////////////////////////////////////////////////////////////////// // 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 +// Hardware interlock cs_mode hold interaction +// relook at fifo empty full logic; might be that watermark level is low when full + + + @@ -52,18 +55,18 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( //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 [11:0] SckDiv, HISckDiv; + logic [1:0] SckMode, HISckMode; + logic [1:0] ChipSelectID, HIChipSelectID; + logic [3:0] ChipSelectDef, HIChipSelectDef; + logic [1:0] ChipSelectMode, HIChipSelectMode; + logic [15:0] Delay0, Delay1, HIDelay0, HIDelay1; + logic [7:0] Format, HIFormat; logic [8:0] ReceiveData; logic [8:0] ReceiveDataPlaceholder; - logic [2:0] TransmitWatermark, ReceiveWatermark; + logic [2:0] TransmitWatermark, ReceiveWatermark, HITransmitWatermark, HIReceiveWatermark; logic [8:0] TransmitData; - logic [1:0] InterruptEnable, InterruptPending; + logic [1:0] InterruptEnable, InterruptPending, HIInterruptEnable; //bus interface signals logic [7:0] Entry; @@ -87,7 +90,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( //transmission signals logic sck; logic [12:0] DivCounter; - logic SCLKDuty; + logic SCLKenable; logic [8:0] Delay0Count; logic [8:0] Delay1Count; logic Delay0Compare; @@ -131,10 +134,22 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( logic ReceiveShiftFullDelay; + logic SCLKenableDelay; + logic [3:0] shiftin; + logic [7:0] ReceiveShiftRegInvert; + logic ZeroDelayHoldMode; + logic TransmitInactive; + logic SCLKenableEarly; + logic ReceiveShiftFullDelayPCLK; + 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) + assign PREADY = 1'b1; // tie high if hardware interlock solution doesn't involve bus + //assign PREADY = TransmitInactive; // tie PREADY to transmission for hardware interlock + + + // account for subword read/write circuitry // -- Note GPIO registers are 32 bits no matter what; access them with LW SW. @@ -164,6 +179,17 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( ReceiveWatermark <= #1 3'b0; InterruptEnable <= #1 2'b0; InterruptPending <= #1 2'b0; + HISckDiv <= #1 12'd3; + HISckMode <= #1 2'b0; + HIChipSelectID <= #1 2'b0; + HIChipSelectDef <= #1 4'b1111; + HIChipSelectMode <= #1 0; + HIDelay0 <= #1 {8'b1,8'b1}; + HIDelay1 <= #1 {8'b0,8'b1}; + HIFormat <= #1 {8'b10000000}; + HITransmitWatermark <= #1 3'b0; + HIReceiveWatermark <= #1 3'b0; + HIInterruptEnable <= #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 @@ -173,19 +199,32 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( /* 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'h00: HISckDiv <= Din[11:0]; + 8'h04: HISckMode <= Din[1:0]; + 8'h10: HIChipSelectID <= Din[1:0]; + 8'h14: HIChipSelectDef <= Din[3:0]; + 8'h18: HIChipSelectMode <= Din[1:0]; + 8'h28: HIDelay0 <= {Din[23:16], Din[7:0]}; + 8'h2C: HIDelay1 <= {Din[23:16], Din[7:0]}; + 8'h40: HIFormat <= {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]; + 8'h50: HITransmitWatermark <= Din[2:0]; + 8'h54: HIReceiveWatermark <= Din[2:0]; + 8'h70: HIInterruptEnable <= Din[1:0]; endcase + if (TransmitInactive) begin + SckDiv <= HISckDiv; + SckMode <= HISckMode; + ChipSelectID <= HIChipSelectID; + ChipSelectDef <= HIChipSelectDef; + ChipSelectMode <= HIChipSelectMode; + Delay0 <= HIDelay0; + Delay1 <= HIDelay1; + Format <= HIFormat; + TransmitWatermark <= HITransmitWatermark; + ReceiveWatermark <= HIReceiveWatermark; + InterruptEnable <= HIInterruptEnable; + end /* verilator lint_off CASEINCOMPLETE */ //interrupt clearance InterruptPending[0] <= TransmitReadMark; @@ -208,6 +247,23 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( default: Dout <= #1 32'b0; endcase end + + + + + assign SCLKenable = (DivCounter >= {1'b0,SckDiv}); + assign SCLKenableEarly = ((DivCounter + 13'b1) >= {1'b0, SckDiv}); + + always_ff @(posedge PCLK, negedge PRESETn) + if (~PRESETn) DivCounter <= #1 0; + else if (SCLKenable) DivCounter <= 0; + else DivCounter <= DivCounter + 13'b1; + + + always_ff @(posedge PCLK, negedge PRESETn) + if (~PRESETn) SCLKenableDelay <= 0; + else SCLKenableDelay <= SCLKenable; + //SCK_CONTROL //multiplies frame count by 2 or 4 if in dual or quad mode @@ -269,18 +325,46 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( // 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]}; + // Transmit and Receive FIFOs + //calculate when tx/rx shift registers are full/empty + TransmitShiftFSM TransmitShiftFSM_1 (PCLK, PRESETn, TransmitFIFOReadEmpty, ReceivePenultimateFrameBoolean, Active0, TransmitShiftEmpty); + ReceiveShiftFSM ReceiveShiftFSM_1 (PCLK, PRESETn, SCLKenable, ReceivePenultimateFrameBoolean, SampleEdge, SckMode[0], ReceiveShiftFull); - // Producing SCLK - // SCLK = PCLK/(2*(sclk_div + 1)) - // SCLKDuty is high every half-period of SCLK - - assign SCLKDuty = (DivCounter >= {1'b0,SckDiv}); + //calculate tx/rx fifo write and recieve increment signals + assign TransmitFIFOWriteIncrement = (Memwrite & (Entry == 8'h48) & ~TransmitFIFOWriteFull); always_ff @(posedge PCLK, negedge PRESETn) - if (~PRESETn) DivCounter <= #1 0; - else if (SCLKDuty) DivCounter <= 0; - else DivCounter <= DivCounter + 13'b1; + 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; + + + assign TransmitDataEndian = Format[2] ? {TransmitData[0], TransmitData[1], TransmitData[2], TransmitData[3], TransmitData[4], TransmitData[5], TransmitData[6], TransmitData[7]} : TransmitData[7:0]; + + TransmitSynchFIFO #(3,8) txFIFO(PCLK, SCLKenable, PRESETn, TransmitFIFOWriteIncrementDelay, TransmitFIFOReadIncrement, TransmitDataEndian, TransmitWriteWatermarkLevel, TransmitWatermark[2:0], TransmitFIFOReadData[7:0], TransmitFIFOWriteFull, TransmitFIFOReadEmpty, TransmitWriteMark, TransmitReadMark); + ReceiveSynchFIFO #(3,8) rxFIFO(PCLK, SCLKenable, PRESETn, ReceiveFIFOWriteIncrement, ReceiveFIFOReadIncrement, ReceiveShiftRegEndian, ReceiveWatermark[2:0], ReceiveReadWatermarkLevel, ReceiveData[7:0], ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty, RecieveWriteMark, RecieveReadMark); + + always_ff @(posedge PCLK, negedge PRESETn) + if (~PRESETn) TransmitFIFOReadEmptyDelay <= 1; + else if (SCLKenable) TransmitFIFOReadEmptyDelay <= TransmitFIFOReadEmpty; + + + always_ff @(posedge PCLK, negedge PRESETn) + if (~PRESETn) ReceiveShiftFullDelay <= 0; + else if (SCLKenable) ReceiveShiftFullDelay <= ReceiveShiftFull; + always_ff @(posedge PCLK, negedge PRESETn) + if (~PRESETn) ReceiveShiftFullDelayPCLK <= 0; + else if (SCLKenableEarly) ReceiveShiftFullDelayPCLK <= ReceiveShiftFull; + + assign TransmitShiftRegLoad = ~TransmitShiftEmpty & ~Active | (((ChipSelectMode == 2'b10) & ~|(Delay1[15:8])) & ((ReceiveShiftFullDelay | ReceiveShiftFull) & ~SampleEdge & ~TransmitFIFOReadEmpty)); //Main FSM which controls SPI transmission @@ -292,7 +376,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( FrameCount <= 5'b0; /* verilator lint_off CASEINCOMPLETE */ - end else if (SCLKDuty) begin + end else if (SCLKenable) begin case (state) CS_INACTIVE: begin Delay0Count <= 9'b1; @@ -346,6 +430,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( end endcase end + /* verilator lint_off CASEINCOMPLETE */ @@ -353,7 +438,9 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( 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 SampleEdge = SckMode[0] ? (state == ACTIVE_1) : (state == ACTIVE_0); + assign ZeroDelayHoldMode = ((ChipSelectMode == 2'b10) & (~|(Delay1[7:4]))); + assign TransmitInactive = ((state == INTER_CS) | (state == CS_INACTIVE) | (state == INTER_XFR) | (ReceiveShiftFullDelayPCLK & ZeroDelayHoldMode)); assign Active0 = (state == ACTIVE_0); assign Inactive = (state == CS_INACTIVE); @@ -363,54 +450,20 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( /* 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); - TransmitSynchFIFO #(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); - ReceiveSynchFIFO #(3,8) rxFIFO(PCLK, SCLKDuty, 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; + 2'b00: sckPhaseSelect = ~sck & SCLKenable; + 2'b01: sckPhaseSelect = (sck & |(FrameCount) & SCLKenable); + 2'b10: sckPhaseSelect = sck & SCLKenable; + 2'b11: sckPhaseSelect = (~sck & |(FrameCount) & SCLKenable); + default: sckPhaseSelect = sck & SCLKenable; endcase - 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; @@ -437,11 +490,11 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( 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 + else if (SampleEdge & SCLKenable) begin if (~Active) ReceiveShiftReg <= 8'b0; else if (~Format[3]) begin case(Format[1:0]) @@ -452,7 +505,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( 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 @@ -805,7 +858,7 @@ module TransmitShiftFSM( endmodule module ReceiveShiftFSM( - input logic PCLK, PRESETn, SCLKDuty, + input logic PCLK, PRESETn, SCLKenable, input logic ReceivePenultimateFrameBoolean, SampleEdge, SckMode, output logic ReceiveShiftFull ); @@ -813,7 +866,7 @@ module ReceiveShiftFSM( statetype ReceiveState, ReceiveNextState; always_ff @(posedge PCLK, negedge PRESETn) if (~PRESETn) ReceiveState <= ReceiveShiftNotFullState; - else if (SCLKDuty) begin + else if (SCLKenable) begin case (ReceiveState) ReceiveShiftFullState: ReceiveState <= ReceiveShiftNotFullState; ReceiveShiftNotFullState: if (ReceivePenultimateFrameBoolean & (SampleEdge)) ReceiveState <= ReceiveShiftDelayState; diff --git a/testbench/testbench.sv b/testbench/testbench.sv index 8d1fdff50..a417e4075 100644 --- a/testbench/testbench.sv +++ b/testbench/testbench.sv @@ -510,7 +510,7 @@ module testbench; errors = errors+1; $display(" Error on test %s result %d: adr = %h sim (D$) %h sim (DTIM_SUPPORTED) = %h, signature = %h", TestName, i, (testadr+i)*(P.XLEN/8), testbench.DCacheFlushFSM.ShadowRAM[testadr+i], sig, signature[i]); - $stop; //***debug + //$stop; //***debug end i = i + 1; end diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-spi-01.reference_output b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-spi-01.reference_output index e8e10dc90..520908265 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-spi-01.reference_output +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-spi-01.reference_output @@ -146,6 +146,46 @@ 00000000 0000001F 00000000 +00000062 # hardware interlock +00000000 +00000026 +00000000 +000000D2 +00000000 +0000002D +00000000 +00000048 +00000000 +00000037 +00000000 +00000026 +00000000 +00000015 +00000000 +00000084 +00000000 +00000073 +00000000 +00000062 +00000000 +00000051 +00000000 +00000046 +00000000 +00000035 +00000000 +00000024 +00000000 +00000013 +00000000 +00000064 +00000000 +00000053 +00000000 +00000042 +00000000 +00000031 +00000000 00000001 #watermark interrupts 00000000 00000000 #read mip diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S index 85c0f4d4c..c76843ef0 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S @@ -166,7 +166,7 @@ test_cases: # Test arbitrary cs-sck delay (sck phase 1) -.8byte delay0, 0x00000105, write32_test # set cs-sck delay to 5 cycles +.8byte delay0, 0x00010005, write32_test # set cs-sck delay to 5 cycles .8byte tx_data, 0x00000048, write32_test # place 8'h11 into tx_data .8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end .8byte rx_data, 0x00000048, read32_test # read rx_data @@ -216,6 +216,7 @@ test_cases: .8byte delay0, 0x00010001, write32_test # reset delay0 register .8byte delay1, 0x00000005, write32_test # set inter_cs delay to 5 +.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock .8byte tx_data, 0x44332211, spi_burst_send .8byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end .8byte rx_data, 0x00000011, read32_test @@ -226,6 +227,7 @@ test_cases: #test long inter_cs delay .8byte delay1, 0x000000A5, write32_test +.8byte rx_mark, 0x0000000, write32_test # preset rx watermark b/c of hardware interlock .8byte tx_data, 0x0000007B, write32_test .8byte 0x0, 0x00000000, spi_data_wait .8byte rx_data, 0x0000007B, read32_test @@ -234,6 +236,7 @@ test_cases: # Test inter_cs delay set to 0 .8byte delay1, 0x00000000, write32_test # set inter_cs delay to 5 +.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock .8byte tx_data, 0x54433221, spi_burst_send .8byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end .8byte rx_data, 0x00000021, read32_test @@ -276,6 +279,7 @@ test_cases: # test long inter_xfr delay .8byte delay1, 0x00A50001, write32_test +.8byte rx_mark, 0x0000000, write32_test # preset rx watermark b/c of hardware interlock .8byte tx_data, 0x00000048, write32_test .8byte 0x0, 0x00000000, spi_data_wait .8byte rx_data, 0x00000048, read32_test @@ -284,6 +288,7 @@ test_cases: .8byte delay1, 0x00000001, write32_test # set inter_xfr delay to 0 .8byte delay0, 0x00010005, write32_test # set cs-sck delay to 5 (should have no effect because cs is never inactive) +.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock .8byte tx_data, 0xAABBCCDD, spi_burst_send .8byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end .8byte rx_data, 0x000000DD, read32_test # read rx_data @@ -310,6 +315,7 @@ test_cases: .8byte sck_mode, 0x00000000, write32_test #reset sckmode register .8byte cs_mode, 0x00000000, write32_test # set cs_mode to AUTO .8byte fmt, 0x00040000, write32_test # set frame length to 4 +.8byte rx_mark, 0x0000000, write32_test # preset rx watermark b/c of hardware interlock .8byte tx_data, 0x000000F0, write32_test # place 8'h11 into tx_data .8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end .8byte rx_data, 0x000000F0, read32_test # read rx_data @@ -323,6 +329,7 @@ test_cases: # test frame length 1 burst .8byte fmt, 0x00010000, write32_test +.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock .8byte tx_data, 0x80008000, spi_burst_send .8byte 0x0, 0x00000003, spi_data_wait .8byte rx_data, 0x00000000, read32_test @@ -334,12 +341,14 @@ test_cases: # Test big endian with frame length = 5 .8byte fmt, 0x00050000, write32_test # set frame length to 5, big endian +.8byte rx_mark, 0x0000000, write32_test # preset rx watermark b/c of hardware interlock .8byte tx_data, 0x000000A8, write32_test # place 8'h11 into tx_data .8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end .8byte rx_data, 0x000000A8, read32_test # read rx_data # Test big endian burst with frame length = 5 +.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock .8byte tx_data, 0x03774FFF, spi_burst_send .8byte 0x0, 0x00000003, spi_data_wait .8byte rx_data, 0x000000F8, read32_test @@ -353,12 +362,14 @@ test_cases: # Test little endian with frame length = 5 .8byte fmt, 0x00050004, write32_test # set frame length to 5, little-endian +.8byte rx_mark, 0x0000000, write32_test # preset rx watermark b/c of hardware interlock .8byte tx_data, 0x000000A8, write32_test # place 8'h11 into tx_data .8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end .8byte rx_data, 0x00000008, read32_test # read rx_data -> 08 #test little endian burst with frame length = 5 +.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock .8byte tx_data, 0xFF4F7703, spi_burst_send .8byte 0x0, 0x00000003, spi_data_wait .8byte rx_data, 0x00000003, read32_test #03 @@ -416,13 +427,110 @@ test_cases: #.8byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end #.8byte rx_data, 0x000000F0, read32_test # read rx_data +#=========== Test Hardware Interlock ================ + +# interlock in base case + +.8byte fmt, 0x00080000, write32_test # reset fmt register +.8byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock +.8byte tx_data, 0x00000062, write32_test # initiate transmission +.8byte sck_mode, 0x00000002, write32_test # flip polarity during transmission +.8byte tx_data, 0x00000026, write32_test # transmit second frame w/ control register updated +.8byte 0x0, 0x00000001, spi_data_wait +.8byte rx_data, 0x00000062, read32_test +.8byte rx_data, 0x00000026, read32_test # clear rx fifo +.8byte sck_mode, 0x00000000, write32_test # reset polarity + +# interlock in case where cs_mode is auto, but there is minimal intercs delay + +.8byte delay0, 0x00000001, write32_test # set sck-cs delay to 0, with sck.pha 0 there is 0 delay +.8byte tx_data, 0x000000D2, write32_test # initiate transmission +.8byte sck_mode, 0x00000002, write32_test # flip sck polarity +.8byte tx_data, 0x0000002D, write32_test # transmit second frame +.8byte 0x0, 0x00000001, spi_data_wait +.8byte rx_data, 0x000000D2, read32_test +.8byte rx_data, 0x0000002D, read32_test # clear rx fifo +.8byte sck_mode, 0x00000000, write32_test # reset polarity + +# interlock in case where cs_mode = hold, 0 intercs delay +.8byte delay0, 0x00010001, write32_test # reset delay0 +.8byte sck_mode, 0x00000000, write32_test # reset polarity +.8byte cs_mode, 0x00000002, write32_test # set cs_mode to hold +.8byte tx_data, 0x15263748, spi_burst_send # place 4 frames into tx fifo +.8byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame) +.8byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end +.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock +.8byte sck_mode, 0x00000000, write32_test # flip polarity again +.8byte 0x0, 0x00000003, spi_data_wait # wait for final frame +.8byte rx_data, 0x00000048, read32_test +.8byte rx_data, 0x00000037, read32_test +.8byte rx_data, 0x00000026, read32_test +.8byte rx_data, 0x00000015, read32_test #clear rx fifo + +# interlock in case where cs_mode = hold, intercs delay + +.8byte sck_mode, 0x00000000, write32_test # reset polarity +.8byte delay1, 0x00010001, write32_test # set intercs delay to 1 +.8byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock +.8byte tx_data, 0x51627384, spi_burst_send # place 4 frames into tx fifo +.8byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame) +.8byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end +.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock +.8byte sck_mode, 0x00000000, write32_test # flip polarity again +.8byte 0x0, 0x00000003, spi_data_wait # wait for final frame +.8byte rx_data, 0x00000084, read32_test +.8byte rx_data, 0x00000073, read32_test +.8byte rx_data, 0x00000062, read32_test +.8byte rx_data, 0x00000051, read32_test #clear rx fifo + +# repeat previous set of tests with cs_mode = off + +.8byte cs_mode, 0x00000003, write32_test # set cs_mode to hold +.8byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock +.8byte tx_data, 0x13243546, spi_burst_send # place 4 frames into tx fifo +.8byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame) +.8byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end +.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock +.8byte sck_mode, 0x00000000, write32_test # flip polarity again +.8byte 0x0, 0x00000003, spi_data_wait # wait for final frame +.8byte rx_data, 0x00000046, read32_test +.8byte rx_data, 0x00000035, read32_test +.8byte rx_data, 0x00000024, read32_test +.8byte rx_data, 0x00000013, read32_test #clear rx fifo + +# interlock in case where cs_mode = hold, intercs delay + +.8byte sck_mode, 0x00000000, write32_test # reset polarity +.8byte delay1, 0x00000000, write32_test # set intercs delay to 0 +.8byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock +.8byte tx_data, 0x31425364, spi_burst_send # place 4 frames into tx fifo +.8byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame) +.8byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end +.8byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock +.8byte sck_mode, 0x00000000, write32_test # flip polarity again +.8byte 0x0, 0x00000003, spi_data_wait # wait for final frame +.8byte rx_data, 0x00000064, read32_test +.8byte rx_data, 0x00000053, read32_test +.8byte rx_data, 0x00000042, read32_test +.8byte rx_data, 0x00000031, read32_test #clear rx fifo + + + + + + + + + + # =========== Test watermark interrupts =========== # Test transmit watermark interrupt (triggers when entries in tx FIFO < tx watermark) without external enables SETUP_PLIC -.8byte fmt, 0x00080000, write32_test # reset fmt register +.8byte delay1, 0x0000001, write32_test # reset delay1 register +.8byte cs_mode, 0x00000000, write32_test # reset cs_mode .8byte tx_mark, 0x00000004, write32_test # set transmit watermark to 4 #.8byte ie, 0x00000000, write32_test # enable transmit interrupt .8byte ip, 0x00000001, read32_test # tx watermark interupt should be pending @@ -462,6 +570,7 @@ SETUP_PLIC # test recieve watermark interrupt (triggers when entries in rx FIFO > rx watermark) .8byte tx_mark, 0x00000000, write32_test +.8byte 0x0, 0x00000000, claim_m_plic_interrupts .8byte rx_data, 0x00000022, read32_test # clear one entry from rx FIFO .8byte rx_mark, 0x00000003, write32_test # set recieve watermark to 3 .8byte ie, 0x0000002, write32_test # enable receive interrupts @@ -475,4 +584,6 @@ SETUP_PLIC .8byte ip, 0x00000000, read32_test # receive interrupt should be low .8byte 0x0, 0x00000000, readmip_test + + .8byte 0x0, 0x0, terminate_test \ No newline at end of file From fefb5adb8f96664461e6dce825c567d669b8b30e Mon Sep 17 00:00:00 2001 From: naichewa Date: Tue, 31 Oct 2023 12:27:41 -0700 Subject: [PATCH 06/12] code review harris --- sim/sim-wally-batch | 2 +- src/uncore/spi_apb.sv | 58 ++++++++++++++++--------------------------- 2 files changed, 23 insertions(+), 37 deletions(-) diff --git a/sim/sim-wally-batch b/sim/sim-wally-batch index f2c2a3c30..38caa95f3 100755 --- a/sim/sim-wally-batch +++ b/sim/sim-wally-batch @@ -1 +1 @@ -vsim -c -do "do wally-batch.do rv64gc wally64priv" +vsim -c -do "do wally-batch.do rv64gc wally64periph" diff --git a/src/uncore/spi_apb.sv b/src/uncore/spi_apb.sv index 9fab982ce..90777e2a8 100644 --- a/src/uncore/spi_apb.sv +++ b/src/uncore/spi_apb.sv @@ -26,8 +26,16 @@ //////////////////////////////////////////////////////////////////////////////////////////////// // Current limitations: Flash read sequencer mode not implemented, dual and quad modes untestable with current test plan. -// Hardware interlock cs_mode hold interaction +// Hardware interlock change to busy signal // relook at fifo empty full logic; might be that watermark level is low when full +// ChipSelectInternal boolean logic simplification (Harris suggestion) +// document timing on loopback testing +// change SCLKenable comparison to equals if possible +// Explain how sck divider gets to correct value +// HoldModeDeassert verilater lint +// Comment on FIFOs: readenable, watermark calculations +/* high level explanation of architecture +*/ @@ -141,6 +149,8 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( logic TransmitInactive; logic SCLKenableEarly; logic ReceiveShiftFullDelayPCLK; + logic [2:0] LeftShiftAmount; + logic [7:0] ASR; // AlignedReceiveShiftReg assign Entry = {PADDR[7:2],2'b00}; // 32-bit word-aligned accesses @@ -253,7 +263,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( assign SCLKenable = (DivCounter >= {1'b0,SckDiv}); assign SCLKenableEarly = ((DivCounter + 13'b1) >= {1'b0, SckDiv}); - + // always_ff @(posedge PCLK, negedge PRESETn) if (~PRESETn) DivCounter <= #1 0; else if (SCLKenable) DivCounter <= 0; @@ -481,6 +491,8 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( end end always_comb + + //Transmit shift register if (Active | Delay0Compare | ~TransmitShiftEmpty) begin case(Format[1:0]) 2'b00: SPIOut = {3'b0,TransmitShiftReg[7]}; @@ -492,6 +504,8 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( end else SPIOut = 4'b0; assign shiftin = P.SPI_LOOPBACK_TEST ? SPIOut : SPIIn; + + // Receive shift register always_ff @(posedge PCLK, negedge PRESETn) if(~PRESETn) ReceiveShiftReg <= 8'b0; else if (SampleEdge & SCLKenable) begin @@ -505,49 +519,23 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( endcase end end - - 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 + // Aligns received data and reverses if little-endian + assign LeftShiftAmount = 8 - Format[7:4]; + assign ASR = ReceiveShiftReg << LeftShiftAmount; + assign ReceiveShiftRegEndian = Format[2] ? {ASR[0], ASR[1], ASR[2], ASR[3], ASR[4], ASR[5], ASR[6], ASR[7]} : ASR[7:0]; + // Interrupt logic: raise interrupt if any enabled interrupts are pending assign SPIIntr = |(InterruptPending & InterruptEnable); + // Chip select logic always_comb case(ChipSelectID[1:0]) 2'b00: ChipSelectAuto = {ChipSelectDef[3], ChipSelectDef[2], ChipSelectDef[1], ChipSelectInternal[0]}; - 2'b01: ChipSelectAuto = {ChipSelectDef[3],ChipSelectDef[2], ChipSelectInternal[1], ChipSelectDef[0]}; - 2'b10: ChipSelectAuto = {ChipSelectDef[3],ChipSelectInternal[2], ChipSelectDef[1], ChipSelectDef[0]}; - 2'b11: ChipSelectAuto = {ChipSelectInternal[3],ChipSelectDef[2], ChipSelectDef[1], ChipSelectDef[0]}; endcase - assign SPICS = ChipSelectMode[0] ? ChipSelectDef : ChipSelectAuto; @@ -582,8 +570,6 @@ module TransmitSynchFIFO #(parameter M =3 , N= 8)( assign raddr = rptr[M-1:0]; assign rptrnext = rptr + {3'b0, (rinc & ~rempty)}; - - always_ff @(posedge PCLK, negedge PRESETn) if (~PRESETn) wptr <= 0; else wptr <= wptrnext; From 9aa8a7af3eac762ac22d54600dd88026919af600 Mon Sep 17 00:00:00 2001 From: naichewa Date: Wed, 1 Nov 2023 01:26:34 -0700 Subject: [PATCH 07/12] comments, more test cases --- src/uncore/spi_apb.sv | 206 ++++++++---------- .../rv64i_m/privilege/src/WALLY-spi-01.S | 18 +- 2 files changed, 103 insertions(+), 121 deletions(-) diff --git a/src/uncore/spi_apb.sv b/src/uncore/spi_apb.sv index 90777e2a8..d86974500 100644 --- a/src/uncore/spi_apb.sv +++ b/src/uncore/spi_apb.sv @@ -27,23 +27,16 @@ // Current limitations: Flash read sequencer mode not implemented, dual and quad modes untestable with current test plan. // Hardware interlock change to busy signal -// relook at fifo empty full logic; might be that watermark level is low when full -// ChipSelectInternal boolean logic simplification (Harris suggestion) -// document timing on loopback testing -// change SCLKenable comparison to equals if possible -// Explain how sck divider gets to correct value -// HoldModeDeassert verilater lint -// Comment on FIFOs: readenable, watermark calculations +// write tests for fifo full and empty watermark edge cases +// HoldModeDeassert verilater lint, relook in general +// Comment on FIFOs: watermark calculations /* high level explanation of architecture +SPI module is written to the specifications described in FU540-C000-v1.0. At the top level, it is consists of synchronous 8 byte transmit and recieve FIFOs connected to shift registers. +The FIFOs are connected to WALLY by an apb bus control register interface, which includes various control registers for modifying the SPI transmission along with registers for writing +to the transmit FIFO and reading from the receive FIFO. The transmissions themselves are then controlled by a finite state machine. The SPI module uses 4 tristate pins for SPI input/output, +along with a 4 bit Chip Select signal, a clock signal, and an interrupt signal to WALLY. */ - - - - - - - module spi_apb import cvw::*; #(parameter cvw_t P) ( input logic PCLK, PRESETn, input logic PSEL, @@ -63,24 +56,23 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( //SPI registers - logic [11:0] SckDiv, HISckDiv; - logic [1:0] SckMode, HISckMode; - logic [1:0] ChipSelectID, HIChipSelectID; - logic [3:0] ChipSelectDef, HIChipSelectDef; - logic [1:0] ChipSelectMode, HIChipSelectMode; - logic [15:0] Delay0, Delay1, HIDelay0, HIDelay1; - logic [7:0] Format, HIFormat; + 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, HITransmitWatermark, HIReceiveWatermark; + logic [2:0] TransmitWatermark, ReceiveWatermark; logic [8:0] TransmitData; - logic [1:0] InterruptEnable, InterruptPending, HIInterruptEnable; + 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; @@ -151,12 +143,14 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( logic ReceiveShiftFullDelayPCLK; logic [2:0] LeftShiftAmount; logic [7:0] ASR; // AlignedReceiveShiftReg + logic DelayMode; - + + // apb assign Entry = {PADDR[7:2],2'b00}; // 32-bit word-aligned accesses assign Memwrite = PWRITE & PENABLE & PSEL; // only write in access phase - assign PREADY = 1'b1; // tie high if hardware interlock solution doesn't involve bus - //assign PREADY = TransmitInactive; // tie PREADY to transmission for hardware interlock + //assign PREADY = 1'b1; // tie high if hardware interlock solution doesn't involve bus + assign PREADY = TransmitInactive; // tie PREADY to transmission for hardware interlock @@ -189,17 +183,6 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( ReceiveWatermark <= #1 3'b0; InterruptEnable <= #1 2'b0; InterruptPending <= #1 2'b0; - HISckDiv <= #1 12'd3; - HISckMode <= #1 2'b0; - HIChipSelectID <= #1 2'b0; - HIChipSelectDef <= #1 4'b1111; - HIChipSelectMode <= #1 0; - HIDelay0 <= #1 {8'b1,8'b1}; - HIDelay1 <= #1 {8'b0,8'b1}; - HIFormat <= #1 {8'b10000000}; - HITransmitWatermark <= #1 3'b0; - HIReceiveWatermark <= #1 3'b0; - HIInterruptEnable <= #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 @@ -209,32 +192,19 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( /* verilator lint_off CASEINCOMPLETE */ if (Memwrite) case(Entry) //flop to sample inputs - 8'h00: HISckDiv <= Din[11:0]; - 8'h04: HISckMode <= Din[1:0]; - 8'h10: HIChipSelectID <= Din[1:0]; - 8'h14: HIChipSelectDef <= Din[3:0]; - 8'h18: HIChipSelectMode <= Din[1:0]; - 8'h28: HIDelay0 <= {Din[23:16], Din[7:0]}; - 8'h2C: HIDelay1 <= {Din[23:16], Din[7:0]}; - 8'h40: HIFormat <= {Din[19:16], Din[3:0]}; + 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: HITransmitWatermark <= Din[2:0]; - 8'h54: HIReceiveWatermark <= Din[2:0]; - 8'h70: HIInterruptEnable <= Din[1:0]; + 8'h50: TransmitWatermark <= Din[2:0]; + 8'h54: ReceiveWatermark <= Din[2:0]; + 8'h70: InterruptEnable <= Din[1:0]; endcase - if (TransmitInactive) begin - SckDiv <= HISckDiv; - SckMode <= HISckMode; - ChipSelectID <= HIChipSelectID; - ChipSelectDef <= HIChipSelectDef; - ChipSelectMode <= HIChipSelectMode; - Delay0 <= HIDelay0; - Delay1 <= HIDelay1; - Format <= HIFormat; - TransmitWatermark <= HITransmitWatermark; - ReceiveWatermark <= HIReceiveWatermark; - InterruptEnable <= HIInterruptEnable; - end /* verilator lint_off CASEINCOMPLETE */ //interrupt clearance InterruptPending[0] <= TransmitReadMark; @@ -260,10 +230,10 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( - - assign SCLKenable = (DivCounter >= {1'b0,SckDiv}); - assign SCLKenableEarly = ((DivCounter + 13'b1) >= {1'b0, SckDiv}); - // + // SPI enable generation, where SCLK = PCLK/(2*(SckDiv + 1)) + // generates a high signal at the rising and falling edge of SCLK by counting from 0 to SckDiv + assign SCLKenable = (DivCounter == {1'b0,SckDiv}); + assign SCLKenableEarly = ((DivCounter + 13'b1) == {1'b0, SckDiv}); always_ff @(posedge PCLK, negedge PRESETn) if (~PRESETn) DivCounter <= #1 0; else if (SCLKenable) DivCounter <= 0; @@ -274,10 +244,8 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( if (~PRESETn) SCLKenableDelay <= 0; else SCLKenableDelay <= SCLKenable; - - //SCK_CONTROL + //Boolean logic that tracks frame progression //multiplies frame count by 2 or 4 if in dual or quad mode - always_comb case(Format[1:0]) 2'b00: FrameCountShifted = FrameCount; @@ -287,7 +255,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( endcase //Calculates penultimate frame - //Frame compare doubles number of frames in dual or qyad mode to account for half-duplex communication + //Frame compare doubles number of frames in dual or quad mode to account for half-duplex communication //FrameCompareProtocol further adjusts comparison according to dual or quad mode always_comb @@ -316,7 +284,6 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( endcase - //Signals that track frame count comparisons assign FrameCompareBoolean = (FrameCountShifted < FrameCompareProtocol); assign ReceivePenultimateFrameCount = FrameCountShifted + ReceivePenultimateFrame; @@ -324,8 +291,6 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( // 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})); @@ -336,7 +301,6 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( assign FrameCompare = (Format[0] | Format[1]) ? ({Format[7:4], 1'b0}) : {1'b0,Format[7:4]}; // Transmit and Receive FIFOs - //calculate when tx/rx shift registers are full/empty TransmitShiftFSM TransmitShiftFSM_1 (PCLK, PRESETn, TransmitFIFOReadEmpty, ReceivePenultimateFrameBoolean, Active0, TransmitShiftEmpty); ReceiveShiftFSM ReceiveShiftFSM_1 (PCLK, PRESETn, SCLKenable, ReceivePenultimateFrameBoolean, SampleEdge, SckMode[0], ReceiveShiftFull); @@ -356,10 +320,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( else if (~ReceiveFIFOReadIncrement) ReceiveFIFOReadIncrement <= ((Entry == 8'h4C) & ~ReceiveFIFOReadEmpty & PSEL); else ReceiveFIFOReadIncrement <= 0; - - assign TransmitDataEndian = Format[2] ? {TransmitData[0], TransmitData[1], TransmitData[2], TransmitData[3], TransmitData[4], TransmitData[5], TransmitData[6], TransmitData[7]} : TransmitData[7:0]; - - TransmitSynchFIFO #(3,8) txFIFO(PCLK, SCLKenable, PRESETn, TransmitFIFOWriteIncrementDelay, TransmitFIFOReadIncrement, TransmitDataEndian, TransmitWriteWatermarkLevel, TransmitWatermark[2:0], TransmitFIFOReadData[7:0], TransmitFIFOWriteFull, TransmitFIFOReadEmpty, TransmitWriteMark, TransmitReadMark); + TransmitSynchFIFO #(3,8) txFIFO(PCLK, SCLKenable, PRESETn, TransmitFIFOWriteIncrementDelay, TransmitFIFOReadIncrement, TransmitData[7:0], TransmitWriteWatermarkLevel, TransmitWatermark[2:0], TransmitFIFOReadData[7:0], TransmitFIFOWriteFull, TransmitFIFOReadEmpty, TransmitWriteMark, TransmitReadMark); ReceiveSynchFIFO #(3,8) rxFIFO(PCLK, SCLKenable, PRESETn, ReceiveFIFOWriteIncrement, ReceiveFIFOReadIncrement, ReceiveShiftRegEndian, ReceiveWatermark[2:0], ReceiveReadWatermarkLevel, ReceiveData[7:0], ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty, RecieveWriteMark, RecieveReadMark); always_ff @(posedge PCLK, negedge PRESETn) @@ -377,7 +338,6 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( assign TransmitShiftRegLoad = ~TransmitShiftEmpty & ~Active | (((ChipSelectMode == 2'b10) & ~|(Delay1[15:8])) & ((ReceiveShiftFullDelay | ReceiveShiftFull) & ~SampleEdge & ~TransmitFIFOReadEmpty)); //Main FSM which controls SPI transmission - typedef enum logic [2:0] {CS_INACTIVE, DELAY_0, ACTIVE_0, ACTIVE_1, DELAY_1,INTER_CS, INTER_XFR} statetype; statetype state; @@ -443,10 +403,9 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( /* 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 DelayMode = SckMode[0] ? (state == DELAY_1) : (state == ACTIVE_1 & ReceiveShiftFull); + assign ChipSelectInternal = (state == CS_INACTIVE | state == INTER_CS | DelayMode & ~|(Delay0[15:8])) ? ChipSelectDef : ~ChipSelectDef; assign sck = (state == ACTIVE_0) ? ~SckMode[1] : SckMode[1]; - assign 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 SampleEdge = SckMode[0] ? (state == ACTIVE_1) : (state == ACTIVE_0); assign ZeroDelayHoldMode = ((ChipSelectMode == 2'b10) & (~|(Delay1[7:4]))); @@ -454,6 +413,8 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( assign Active0 = (state == ACTIVE_0); assign Inactive = (state == CS_INACTIVE); + // Ensures that when ChipSelectMode = hold, CS pin is deasserted only when a different value is written to csmode or csid or a write to csdeg changes the state + // of the selected pin always_ff @(posedge PCLK, negedge PRESETn) if (~PRESETn) HoldModeDeassert <= 0; else if (Inactive) HoldModeDeassert <= 0; @@ -463,7 +424,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( - + // Signal tracks which edge of sck to shift data always_comb case(SckMode[1:0]) 2'b00: sckPhaseSelect = ~sck & SCLKenable; @@ -473,12 +434,13 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( default: sckPhaseSelect = sck & SCLKenable; endcase - + //Transmit shift register + assign TransmitDataEndian = Format[2] ? {TransmitFIFOReadData[0], TransmitFIFOReadData[1], TransmitFIFOReadData[2], TransmitFIFOReadData[3], TransmitFIFOReadData[4], TransmitFIFOReadData[5], TransmitFIFOReadData[6], TransmitFIFOReadData[7]} : TransmitFIFOReadData[7:0]; always_ff @(posedge PCLK, negedge PRESETn) if(~PRESETn) begin TransmitShiftReg <= 8'b0; end - else if (TransmitShiftRegLoad) TransmitShiftReg <= TransmitFIFOReadData; + else if (TransmitShiftRegLoad) TransmitShiftReg <= TransmitDataEndian; else if (sckPhaseSelect) begin //if ((ChipSelectMode[1:0] == 2'b10) & ~|(Delay1[15:8]) & (~TransmitFIFOReadEmpty) & TransmitShiftEmpty) TransmitShiftReg <= TransmitFIFOReadData; if (Active) begin @@ -492,7 +454,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( end always_comb - //Transmit shift register + //Output pin control based on single, dual, or quad mode if (Active | Delay0Compare | ~TransmitShiftEmpty) begin case(Format[1:0]) 2'b00: SPIOut = {3'b0,TransmitShiftReg[7]}; @@ -503,6 +465,8 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( endcase end else SPIOut = 4'b0; + //If in loopback mode, receive shift register is connected directly to module's output pins. Else, connected to SPIIn + //There are no setup/hold time issues because transmit shift register and receive shift register always shift/sample on opposite edges assign shiftin = P.SPI_LOOPBACK_TEST ? SPIOut : SPIIn; // Receive shift register @@ -540,9 +504,8 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( endmodule - module TransmitSynchFIFO #(parameter M =3 , N= 8)( - input logic PCLK, ren, PRESETn, + input logic PCLK, sclken, PRESETn, input logic winc,rinc, input logic [N-1:0] wdata, input logic [M-1:0] wwatermarklevel, rwatermarklevel, @@ -562,41 +525,43 @@ module TransmitSynchFIFO #(parameter M =3 , N= 8)( always_ff @(posedge PCLK) if (winc & ~wfull) mem[waddr] <= wdata; + // read flops are only enabled on sclk edges b/c transmit fifo is read on sclk always_ff @(posedge PCLK, negedge PRESETn) - if (~PRESETn) rptr <= 0; - else if (ren) rptr <= rptrnext; - + if (~PRESETn) begin + rptr <= 0; + wptr <= 0; + wfull <= 1'b0; + rempty <= 1'b1; + end + else begin + wfull <= wfull_val; + wptr <= wptrnext; + if (sclken) begin + rptr <= rptrnext; + rempty <= rempty_val; + end + end assign raddr = rptr[M-1:0]; assign rptrnext = rptr + {3'b0, (rinc & ~rempty)}; - - always_ff @(posedge PCLK, negedge PRESETn) - if (~PRESETn) wptr <= 0; - else wptr <= wptrnext; + assign rempty_val = (wptr == rptrnext); + assign rwatermark = ((rptr[M-1:0] - wptr[M-1:0]) < rwatermarklevel); assign waddr = wptr[M-1:0]; assign wwatermark = ((wptr[M-1:0] - rptr[M-1:0]) > wwatermarklevel); assign wptrnext = wptr + {3'b0, (winc & ~wfull)}; - - assign rempty_val = (wptr == rptrnext); assign wfull_val = ({~wptrnext[M], wptrnext[M-1:0]} == rptr); - assign rwatermark = ((rptr[M-1:0] - wptr[M-1:0]) < rwatermarklevel); - always_ff @(posedge PCLK, negedge PRESETn) - if (~PRESETn) wfull <= 1'b0; - else wfull <= wfull_val; - always_ff @(posedge PCLK, negedge PRESETn) - if (~PRESETn) rempty <= 1'b1; - else if (ren) rempty <= rempty_val; + endmodule module ReceiveSynchFIFO #(parameter M =3 , N= 8)( - input logic PCLK, ren, PRESETn, + input logic PCLK, sclken, PRESETn, input logic winc,rinc, input logic [N-1:0] wdata, input logic [M-1:0] wwatermarklevel, rwatermarklevel, @@ -615,31 +580,34 @@ module ReceiveSynchFIFO #(parameter M =3 , N= 8)( assign rdata = mem[raddr]; always_ff @(posedge PCLK) if(winc & ~wfull & PCLK) mem[waddr] <= wdata; + + //write flops are enabled only on sclk edges b/c receive fifo is written then always_ff @(posedge PCLK, negedge PRESETn) - if (~PRESETn) rptr <= 0; - else rptr <= rptrnext; + if (~PRESETn) begin + rptr <= 0; + wptr <= 0; + wfull <= 0; + rempty <= 0; + end else begin + rptr <= rptrnext; + rempty <= rempty_val; + if (sclken) begin + wptr <= wptrnext; + wfull <= wfull_val; + end + end + assign rwatermark = ((rptr[M-1:0] - wptr[M-1:0]) < rwatermarklevel); assign raddr = rptr[M-1:0]; assign rptrnext = rptr + {3'b0, (rinc & ~rempty)}; assign rempty_val = (wptr == rptrnext); - always_ff @(posedge PCLK, negedge PRESETn) - if (~PRESETn) rempty <= 1'b1; - else rempty <= rempty_val; - - always_ff @(posedge PCLK, negedge PRESETn) - if (~PRESETn) wptr <= 0; - else if (ren) wptr <= wptrnext; - assign waddr = wptr[M-1:0]; assign wwatermark = ((wptr[M-1:0] - rptr[M-1:0]) > wwatermarklevel); assign wptrnext = wptr + {3'b0, (winc & ~wfull)}; - assign wfull_val = ({~wptrnext[M], wptrnext[M-1:0]} == rptr); - always_ff @(posedge PCLK, negedge PRESETn) - if (~PRESETn) wfull <= 1'b0; - else if (ren) wfull <= wfull_val; + endmodule diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S index c76843ef0..2ae66de05 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S @@ -306,12 +306,26 @@ test_cases: .8byte rx_data, 0x000000BC, read32_test .8byte rx_data, 0x000000AB, read32_test +# Test hold mode deassert conditions + +.8byte delay1, 0x00000001, write32_test # reset delay1 register +.8byte delay0, 0x00010001, write32_test # reset delay0 register +.8byte cs_mode, 0x00000002, write32_test # set cs_mode to hold +.8byte tx_data, 0x000000CE, write32_test # place data into tx_data +.8byte cs_id, 0x00000001, write32_test #change selected cs pin. should deassert cs[0] in hold mode +.8byte cs_def, 0x00001101, write32_test # change selected cs pins def value. should deassert cs[1] +.8byte cs_def, 0x00001111, write32_test # reset cs_def +.8byte cs_mode, 0x00000000, write32_test # change cs_mode to auto, should deassert cs[1], have now gone through all deassertion conditions +.8byte rx_data, 0x000000CE, read32_test # clear rx_fifo + +# Test transmit and receive fifo full edge cases + + # =========== Test frame format (fmt) register =========== # Test frame length of 4 -.8byte delay1, 0x00000001, write32_test # reset delay1 register -.8byte delay0, 0x00010001, write32_test # reset delay0 register + .8byte sck_mode, 0x00000000, write32_test #reset sckmode register .8byte cs_mode, 0x00000000, write32_test # set cs_mode to AUTO .8byte fmt, 0x00040000, write32_test # set frame length to 4 From e3d8162279a0cae37eaddd0683f267ac3cf95fb4 Mon Sep 17 00:00:00 2001 From: naichewa Date: Wed, 1 Nov 2023 10:14:15 -0700 Subject: [PATCH 08/12] harris code review 3 --- config/fpga/config.vh | 6 + src/uncore/spi_apb.sv | 476 ++++++--------------------------- src/uncore/uncore.sv | 6 +- src/wally/wallypipelinedsoc.sv | 8 +- testbench/testbench.sv | 3 +- testbench/wallywrapper.sv | 4 +- 6 files changed, 95 insertions(+), 408 deletions(-) diff --git a/config/fpga/config.vh b/config/fpga/config.vh index 9e2b4cbb9..d390453f4 100644 --- a/config/fpga/config.vh +++ b/config/fpga/config.vh @@ -135,10 +135,15 @@ localparam SDC_SUPPORTED = 1'b1; localparam logic [63:0] SDC_BASE = 64'h00013000; localparam logic [63:0] SDC_RANGE = 64'h0000007F; +localparam SPI_SUPPORTED = 1'b1; +localparam logic [63:0] SPI_BASE = 64'h10040000; +localparam logic [63:0] SPI_RANGE = 64'h00000FFF; + // Test modes // Tie GPIO outputs back to inputs localparam GPIO_LOOPBACK_TEST = 0; +localparam SPI_LOOPBACK_TEST = 0; // Hardware configuration localparam UART_PRESCALE = 32'd0; @@ -149,6 +154,7 @@ localparam PLIC_NUM_SRC = 32'd53; localparam PLIC_NUM_SRC_LT_32 = (PLIC_NUM_SRC < 32); localparam PLIC_GPIO_ID = 32'd3; localparam PLIC_UART_ID = 32'd10; +localparam PLIC_SPI_ID = 32'd6; localparam PLIC_SDC_ID = 32'd20; localparam BPRED_SUPPORTED = 1; diff --git a/src/uncore/spi_apb.sv b/src/uncore/spi_apb.sv index d86974500..a177e6502 100644 --- a/src/uncore/spi_apb.sv +++ b/src/uncore/spi_apb.sv @@ -27,9 +27,15 @@ // Current limitations: Flash read sequencer mode not implemented, dual and quad modes untestable with current test plan. // Hardware interlock change to busy signal +// Get rid of dual/ quad mode // write tests for fifo full and empty watermark edge cases -// HoldModeDeassert verilater lint, relook in general +// HoldModeDeassert make sure still works // Comment on FIFOs: watermark calculations +// Comment all interface and internal signals on the lines they are declared +// Get tabs correct so things line up +// Relook at frame compare/ Delay count logic w/o multibit +// look at ReadIncrement/WriteIncrement delay necessity +// test case for two's complement rollover on fifo watermark calculation + watermark calc redesign /* high level explanation of architecture SPI module is written to the specifications described in FU540-C000-v1.0. At the top level, it is consists of synchronous 8 byte transmit and recieve FIFOs connected to shift registers. The FIFOs are connected to WALLY by an apb bus control register interface, which includes various control registers for modifying the SPI transmission along with registers for writing @@ -38,20 +44,19 @@ along with a 4 bit Chip Select signal, a clock signal, and an interrupt signal t */ 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 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, + input logic PWRITE, + input logic PENABLE, + output logic PREADY, + output logic [P.XLEN-1:0] PRDATA, + output logic SPIOut, + input logic SPIIn, output logic [3:0] SPICS, output logic SPIIntr - ); //SPI registers @@ -62,7 +67,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( logic [3:0] ChipSelectDef; logic [1:0] ChipSelectMode; logic [15:0] Delay0, Delay1; - logic [7:0] Format; + logic [4:0] Format; logic [8:0] ReceiveData; logic [8:0] ReceiveDataPlaceholder; logic [2:0] TransmitWatermark, ReceiveWatermark; @@ -77,8 +82,9 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( //FIFO FSM signals logic TransmitWriteMark, TransmitReadMark, RecieveWriteMark, RecieveReadMark; logic TransmitFIFOWriteFull, TransmitFIFOReadEmpty; - logic TransmitFIFOWriteIncrement, TransmitFIFOReadIncrement; - logic ReceiveFIFOWriteIncrement, ReceiveFIFOReadIncrement; + logic TransmitFIFOReadIncrement; + logic TransmitFIFOWriteIncrement; + logic ReceiveFIFOReadIncrement; logic ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty; logic [7:0] TransmitFIFOReadData, ReceiveFIFOWriteData; @@ -89,7 +95,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( //transmission signals logic sck; - logic [12:0] DivCounter; + logic [11:0] DivCounter; logic SCLKenable; logic [8:0] Delay0Count; logic [8:0] Delay1Count; @@ -104,7 +110,6 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( logic [4:0] FrameCompare; logic FrameCompareBoolean; - logic [4:0] FrameCountShifted; logic [4:0] ReceivePenultimateFrame; logic [4:0] ReceivePenultimateFrameCount; logic ReceivePenultimateFrameBoolean; @@ -135,38 +140,31 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( logic ReceiveShiftFullDelay; logic SCLKenableDelay; - logic [3:0] shiftin; + logic shiftin; logic [7:0] ReceiveShiftRegInvert; logic ZeroDelayHoldMode; logic TransmitInactive; logic SCLKenableEarly; logic ReceiveShiftFullDelayPCLK; - logic [2:0] LeftShiftAmount; + logic [3:0] LeftShiftAmount; logic [7:0] ASR; // AlignedReceiveShiftReg logic DelayMode; + logic [3:0] PWChipSelect; - - // apb + // APB access assign Entry = {PADDR[7:2],2'b00}; // 32-bit word-aligned accesses assign Memwrite = PWRITE & PENABLE & PSEL; // only write in access phase - //assign PREADY = 1'b1; // tie high if hardware interlock solution doesn't involve bus - assign PREADY = TransmitInactive; // tie PREADY to transmission for hardware interlock - - - + assign PREADY = 1'b1; // tie high if hardware interlock solution doesn't involve bus + //assign PREADY = TransmitInactive; // tie PREADY to transmission for hardware interlock // account for subword read/write circuitry - // -- Note 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 + // -- Note SPI registers are 32 bits no matter what; access them with LW SW. + + assign Din = PWDATA[31:0]; + if (P.XLEN == 64) assign PRDATA = {Dout, Dout}; + else assign PRDATA = Dout; - // register access + // register access *** clean this up always_ff@(posedge PCLK, negedge PRESETn) if (~PRESETn) begin SckDiv <= #1 12'd3; @@ -176,9 +174,8 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( ChipSelectMode <= #1 0; Delay0 <= #1 {8'b1,8'b1}; Delay1 <= #1 {8'b0,8'b1}; - Format <= #1 {8'b10000000}; + Format <= #1 {5'b10000}; TransmitData <= #1 9'b0; - //ReceiveData <= #1 9'b100000000; TransmitWatermark <= #1 3'b0; ReceiveWatermark <= #1 3'b0; InterruptEnable <= #1 2'b0; @@ -187,8 +184,6 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( //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 @@ -199,7 +194,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( 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'h40: Format <= {Din[19:16], Din[2]}; 8'h48: if (~TransmitFIFOWriteFull) TransmitData[7:0] <= Din[7:0]; 8'h50: TransmitWatermark <= Din[2:0]; 8'h54: ReceiveWatermark <= Din[2:0]; @@ -217,7 +212,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( 8'h18: Dout <= #1 {30'b0, ChipSelectMode}; 8'h28: Dout <= {8'b0, Delay0[15:8], 8'b0, Delay0[7:0]}; 8'h2C: Dout <= {8'b0, Delay1[15:8], 8'b0, Delay1[7:0]}; - 8'h40: Dout <= {12'b0, Format[7:4], 12'b0, Format[3:0]}; + 8'h40: Dout <= {12'b0, Format[4:1], 13'b0, Format[0], 2'b0}; 8'h48: Dout <= #1 {23'b0, TransmitFIFOWriteFull, 8'b0}; 8'h4C: Dout <= #1 {23'b0, ReceiveFIFOReadEmpty, ReceiveData[7:0]}; 8'h50: Dout <= #1 {29'b0, TransmitWatermark}; @@ -227,67 +222,21 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( default: Dout <= #1 32'b0; endcase end - - - + // SPI enable generation, where SCLK = PCLK/(2*(SckDiv + 1)) // generates a high signal at the rising and falling edge of SCLK by counting from 0 to SckDiv - assign SCLKenable = (DivCounter == {1'b0,SckDiv}); - assign SCLKenableEarly = ((DivCounter + 13'b1) == {1'b0, SckDiv}); + assign SCLKenable = (DivCounter == SckDiv); + assign SCLKenableEarly = ((DivCounter + 12'b1) == SckDiv); always_ff @(posedge PCLK, negedge PRESETn) if (~PRESETn) DivCounter <= #1 0; else if (SCLKenable) DivCounter <= 0; - else DivCounter <= DivCounter + 13'b1; - - - always_ff @(posedge PCLK, negedge PRESETn) - if (~PRESETn) SCLKenableDelay <= 0; - else SCLKenableDelay <= SCLKenable; + else DivCounter <= DivCounter + 12'b1; //Boolean logic that tracks frame progression - //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 quad 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 - - - assign FrameCompareBoolean = (FrameCountShifted < FrameCompareProtocol); - assign ReceivePenultimateFrameCount = FrameCountShifted + ReceivePenultimateFrame; - assign ReceivePenultimateFrameBoolean = (ReceivePenultimateFrameCount >= FrameCompareProtocol); + assign FrameCompare = {1'b0,Format[4:1]}; + assign FrameCompareBoolean = (FrameCount < FrameCompare); + assign ReceivePenultimateFrameCount = FrameCount + 5'b00001; + assign ReceivePenultimateFrameBoolean = (ReceivePenultimateFrameCount >= FrameCompare); // Computing delays // When sckmode.pha = 0, an extra half-period delay is implicit in the cs-sck delay, and vice-versa for sck-cs @@ -296,11 +245,6 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( 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]}; - - // Transmit and Receive FIFOs //calculate when tx/rx shift registers are full/empty TransmitShiftFSM TransmitShiftFSM_1 (PCLK, PRESETn, TransmitFIFOReadEmpty, ReceivePenultimateFrameBoolean, Active0, TransmitShiftEmpty); ReceiveShiftFSM ReceiveShiftFSM_1 (PCLK, PRESETn, SCLKenable, ReceivePenultimateFrameBoolean, SampleEdge, SckMode[0], ReceiveShiftFull); @@ -312,16 +256,13 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( 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; - - TransmitSynchFIFO #(3,8) txFIFO(PCLK, SCLKenable, PRESETn, TransmitFIFOWriteIncrementDelay, TransmitFIFOReadIncrement, TransmitData[7:0], TransmitWriteWatermarkLevel, TransmitWatermark[2:0], TransmitFIFOReadData[7:0], TransmitFIFOWriteFull, TransmitFIFOReadEmpty, TransmitWriteMark, TransmitReadMark); - ReceiveSynchFIFO #(3,8) rxFIFO(PCLK, SCLKenable, PRESETn, ReceiveFIFOWriteIncrement, ReceiveFIFOReadIncrement, ReceiveShiftRegEndian, ReceiveWatermark[2:0], ReceiveReadWatermarkLevel, ReceiveData[7:0], ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty, RecieveWriteMark, RecieveReadMark); + else ReceiveFIFOReadIncrement <= ((Entry == 8'h4C) & ~ReceiveFIFOReadEmpty & PSEL & ~ReceiveFIFOReadIncrement); + + //tx/rx FIFOs + SynchFIFO #(3,8) txFIFO(PCLK, 1'b1, SCLKenable, PRESETn, TransmitFIFOWriteIncrementDelay, TransmitShiftEmpty, TransmitData[7:0], TransmitWriteWatermarkLevel, TransmitWatermark[2:0], TransmitFIFOReadData[7:0], TransmitFIFOWriteFull, TransmitFIFOReadEmpty, TransmitWriteMark, TransmitReadMark); + SynchFIFO #(3,8) rxFIFO(PCLK, SCLKenable, 1'b1, PRESETn, ReceiveShiftFullDelay, ReceiveFIFOReadIncrement, ReceiveShiftRegEndian, ReceiveWatermark[2:0], ReceiveReadWatermarkLevel, ReceiveData[7:0], ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty, RecieveWriteMark, RecieveReadMark); always_ff @(posedge PCLK, negedge PRESETn) if (~PRESETn) TransmitFIFOReadEmptyDelay <= 1; @@ -415,16 +356,12 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( // Ensures that when ChipSelectMode = hold, CS pin is deasserted only when a different value is written to csmode or csid or a write to csdeg changes the state // of the selected pin + assign PWChipSelect = PWDATA[3:0]; always_ff @(posedge PCLK, negedge PRESETn) if (~PRESETn) HoldModeDeassert <= 0; - else if (Inactive) 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 */ + else if (~Inactive & ((ChipSelectMode[1:0] == 2'b10) & (Entry == (8'h18 | 8'h10) | ((Entry == 8'h14) & (PWChipSelect[ChipSelectID] != ChipSelectDef[ChipSelectID])))) & Memwrite) HoldModeDeassert <= 1; - - - // Signal tracks which edge of sck to shift data + // Signal tracks which edge of sck to shift data always_comb case(SckMode[1:0]) 2'b00: sckPhaseSelect = ~sck & SCLKenable; @@ -435,36 +372,14 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( endcase //Transmit shift register - assign TransmitDataEndian = Format[2] ? {TransmitFIFOReadData[0], TransmitFIFOReadData[1], TransmitFIFOReadData[2], TransmitFIFOReadData[3], TransmitFIFOReadData[4], TransmitFIFOReadData[5], TransmitFIFOReadData[6], TransmitFIFOReadData[7]} : TransmitFIFOReadData[7:0]; + assign TransmitDataEndian = Format[0] ? {TransmitFIFOReadData[0], TransmitFIFOReadData[1], TransmitFIFOReadData[2], TransmitFIFOReadData[3], TransmitFIFOReadData[4], TransmitFIFOReadData[5], TransmitFIFOReadData[6], TransmitFIFOReadData[7]} : TransmitFIFOReadData[7:0]; always_ff @(posedge PCLK, negedge PRESETn) - if(~PRESETn) begin - TransmitShiftReg <= 8'b0; - end - else if (TransmitShiftRegLoad) TransmitShiftReg <= TransmitDataEndian; - 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 - - //Output pin control based on single, dual, or quad mode - 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; + if(~PRESETn) TransmitShiftReg <= 8'b0; + else if (TransmitShiftRegLoad) TransmitShiftReg <= TransmitDataEndian; + else if (sckPhaseSelect & Active) TransmitShiftReg <= {TransmitShiftReg[6:0], 1'b0}; + assign SPIOut = TransmitShiftReg[7]; + //If in loopback mode, receive shift register is connected directly to module's output pins. Else, connected to SPIIn //There are no setup/hold time issues because transmit shift register and receive shift register always shift/sample on opposite edges assign shiftin = P.SPI_LOOPBACK_TEST ? SPIOut : SPIIn; @@ -474,25 +389,19 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( if(~PRESETn) ReceiveShiftReg <= 8'b0; else if (SampleEdge & SCLKenable) 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 + else ReceiveShiftReg <= {ReceiveShiftReg[6:0], shiftin}; end // Aligns received data and reverses if little-endian - assign LeftShiftAmount = 8 - Format[7:4]; - assign ASR = ReceiveShiftReg << LeftShiftAmount; - assign ReceiveShiftRegEndian = Format[2] ? {ASR[0], ASR[1], ASR[2], ASR[3], ASR[4], ASR[5], ASR[6], ASR[7]} : ASR[7:0]; + assign LeftShiftAmount = 4'h8 - Format[4:1]; + assign ASR = ReceiveShiftReg << LeftShiftAmount[2:0]; + assign ReceiveShiftRegEndian = Format[0] ? {ASR[0], ASR[1], ASR[2], ASR[3], ASR[4], ASR[5], ASR[6], ASR[7]} : ASR[7:0]; // Interrupt logic: raise interrupt if any enabled interrupts are pending assign SPIIntr = |(InterruptPending & InterruptEnable); // Chip select logic + always_comb case(ChipSelectID[1:0]) 2'b00: ChipSelectAuto = {ChipSelectDef[3], ChipSelectDef[2], ChipSelectDef[1], ChipSelectInternal[0]}; @@ -500,12 +409,12 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( 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 TransmitSynchFIFO #(parameter M =3 , N= 8)( - input logic PCLK, sclken, PRESETn, + +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, @@ -514,7 +423,7 @@ module TransmitSynchFIFO #(parameter M =3 , N= 8)( output logic wwatermark, rwatermark); logic [N-1:0] mem[2**M]; - logic [M:0] rptr, wptr; + logic [M:0] rwpr, wptr; logic [M:0] rptrnext, wptrnext; logic rempty_val; logic wfull_val; @@ -525,7 +434,7 @@ module TransmitSynchFIFO #(parameter M =3 , N= 8)( always_ff @(posedge PCLK) if (winc & ~wfull) mem[waddr] <= wdata; - // read flops are only enabled on sclk edges b/c transmit fifo is read on sclk + // write and read are enabled always_ff @(posedge PCLK, negedge PRESETn) if (~PRESETn) begin rptr <= 0; @@ -534,9 +443,11 @@ module TransmitSynchFIFO #(parameter M =3 , N= 8)( rempty <= 1'b1; end else begin - wfull <= wfull_val; - wptr <= wptrnext; - if (sclken) begin + if (wen) begin + wfull <= wfull_val; + wptr <= wptrnext; + end + if (ren) begin rptr <= rptrnext; rempty <= rempty_val; end @@ -545,245 +456,12 @@ module TransmitSynchFIFO #(parameter M =3 , N= 8)( assign raddr = rptr[M-1:0]; assign rptrnext = rptr + {3'b0, (rinc & ~rempty)}; assign rempty_val = (wptr == rptrnext); - assign rwatermark = ((rptr[M-1:0] - wptr[M-1:0]) < rwatermarklevel); + assign rwatermark = ((raddr - waddr) < rwatermarklevel); assign waddr = wptr[M-1:0]; - assign wwatermark = ((wptr[M-1:0] - rptr[M-1:0]) > wwatermarklevel); + assign wwatermark = ((waddr - raddr) > wwatermarklevel); assign wptrnext = wptr + {3'b0, (winc & ~wfull)}; assign wfull_val = ({~wptrnext[M], wptrnext[M-1:0]} == rptr); - - - - - - -endmodule - - -module ReceiveSynchFIFO #(parameter M =3 , N= 8)( - input logic PCLK, sclken, PRESETn, - input logic winc,rinc, - input logic [N-1:0] wdata, - input logic [M-1:0] wwatermarklevel, rwatermarklevel, - output logic [N-1:0] rdata, - output logic wfull, rempty, - output logic wwatermark, rwatermark); - - logic [N-1:0] mem[2**M]; - logic [M:0] rptr, wptr; - logic [M:0] rptrnext, wptrnext; - logic rempty_val; - logic wfull_val; - logic [M-1:0] raddr; - logic [M-1:0] waddr; - - assign rdata = mem[raddr]; - always_ff @(posedge PCLK) - if(winc & ~wfull & PCLK) mem[waddr] <= wdata; - - //write flops are enabled only on sclk edges b/c receive fifo is written then - always_ff @(posedge PCLK, negedge PRESETn) - if (~PRESETn) begin - rptr <= 0; - wptr <= 0; - wfull <= 0; - rempty <= 0; - end else begin - rptr <= rptrnext; - rempty <= rempty_val; - if (sclken) begin - wptr <= wptrnext; - wfull <= wfull_val; - end - end - - assign rwatermark = ((rptr[M-1:0] - wptr[M-1:0]) < rwatermarklevel); - assign raddr = rptr[M-1:0]; - assign rptrnext = rptr + {3'b0, (rinc & ~rempty)}; - assign rempty_val = (wptr == rptrnext); - - assign waddr = wptr[M-1:0]; - assign wwatermark = ((wptr[M-1:0] - rptr[M-1:0]) > wwatermarklevel); - assign wptrnext = wptr + {3'b0, (winc & ~wfull)}; - assign wfull_val = ({~wptrnext[M], wptrnext[M-1:0]} == rptr); - - - -endmodule - -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( diff --git a/src/uncore/uncore.sv b/src/uncore/uncore.sv index 3f9aae238..916dc53ef 100644 --- a/src/uncore/uncore.sv +++ b/src/uncore/uncore.sv @@ -55,9 +55,9 @@ module uncore import cvw::*; #(parameter cvw_t P)( input logic UARTSin, // UART serial input output logic UARTSout, // UART serial output input logic SDCIntr, - input logic [3:0] SPIIn, - output logic [3:0] SPIOut, - output logic [3:0] SPICS + input logic SPIIn, + output logic SPIOut, + output logic [3:0] SPICS ); logic [P.XLEN-1:0] HREADRam, HREADSDC; diff --git a/src/wally/wallypipelinedsoc.sv b/src/wally/wallypipelinedsoc.sv index 336bb7a6a..ab0071fff 100644 --- a/src/wally/wallypipelinedsoc.sv +++ b/src/wally/wallypipelinedsoc.sv @@ -54,14 +54,14 @@ module wallypipelinedsoc import cvw::*; #(parameter cvw_t P) ( output logic [31:0] GPIOEN, // output enables for GPIO input logic UARTSin, // UART serial data input output logic UARTSout, // UART serial data output - input logic SDCIntr, - input logic [3:0] SPIIn, // SPI pins in - output logic [3:0] SPIOut, // SPI pins out + input logic SDCIntr, + input logic SPIIn, // SPI pins in + output logic SPIOut, // SPI pins out output logic [3:0] SPICS // SPI chip select pins ); // Uncore signals - logic [P.AHBW-1:0] HRDATA; // from AHB mux in uncore + logic [P.AHBW-1:0] HRDATA; // from AHB mux in uncore logic HRESP; // response from AHB logic MTimerInt, MSwInt;// timer and software interrupts from CLINT logic [63:0] MTIME_CLINT; // from CLINT to CSRs diff --git a/testbench/testbench.sv b/testbench/testbench.sv index a417e4075..56a8db268 100644 --- a/testbench/testbench.sv +++ b/testbench/testbench.sv @@ -64,7 +64,8 @@ module testbench; logic [31:0] GPIOIN, GPIOOUT, GPIOEN; logic UARTSin, UARTSout; - logic [3:0] SPIIn, SPIOut, SPICS; + logic SPIIn, SPIOut; + logic [3:0] SPICS; logic SDCIntr; logic HREADY; diff --git a/testbench/wallywrapper.sv b/testbench/wallywrapper.sv index 465aaec90..64b63c54a 100644 --- a/testbench/wallywrapper.sv +++ b/testbench/wallywrapper.sv @@ -51,6 +51,8 @@ module wallywrapper; logic [31:0] GPIOIN, GPIOOUT, GPIOEN; logic UARTSin, UARTSout; + logic SPIIn, SPIOut; + logic [3:0] SPICS; logic SDCIntr; logic HREADY; @@ -70,6 +72,6 @@ module wallywrapper; wallypipelinedsoc #(P) dut(.clk, .reset_ext, .reset, .HRDATAEXT,.HREADYEXT, .HRESPEXT,.HSELEXT, .HSELEXTSDC, .HCLK, .HRESETn, .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HSIZE, .HBURST, .HPROT, .HTRANS, .HMASTLOCK, .HREADY, .TIMECLK(1'b0), .GPIOIN, .GPIOOUT, .GPIOEN, - .UARTSin, .UARTSout, .SDCIntr); + .UARTSin, .UARTSout, .SPIIn, .SPIOut, .SPICS, .SDCIntr); endmodule From a08356fdaac20da025af701e4c6b4ee89138b79d Mon Sep 17 00:00:00 2001 From: naichewa Date: Wed, 1 Nov 2023 10:34:39 -0700 Subject: [PATCH 09/12] correct exclusion tags and reset testbench --- src/mmu/pmachecker.sv | 8 ++++---- testbench/testbench.sv | 4 ++-- testbench/tests.vh | 12 ++++++------ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/mmu/pmachecker.sv b/src/mmu/pmachecker.sv index cd47eadfe..7aa20fc2f 100644 --- a/src/mmu/pmachecker.sv +++ b/src/mmu/pmachecker.sv @@ -62,13 +62,13 @@ module pmachecker import cvw::*; #(parameter cvw_t P) ( // 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[11] | SelRegions[10] | SelRegions[9] | SelRegions[8] | SelRegions[7]; - assign Idempotent = (PBMemoryType == 2'b00) ? IdempotentRegion : (PBMemoryType == 2'b01); // exclusion-tag: unused-idempotent + assign IdempotentRegion = SelRegions[11] | SelRegions[10] | SelRegions[9] | SelRegions[8] | SelRegions[7]; // exclusion-tag: unused-idempotent + assign Idempotent = (PBMemoryType == 2'b00) ? IdempotentRegion : (PBMemoryType == 2'b01); // Atomic operations are only allowed on RAM - assign AtomicAllowed = SelRegions[11] | SelRegions[9] | SelRegions[7]; + assign AtomicAllowed = SelRegions[11] | SelRegions[9] | SelRegions[7]; // exclusion-tag: unused-idempotent // Check if tightly integrated memories are selected - assign SelTIM = SelRegions[11] | SelRegions[10]; + assign SelTIM = SelRegions[11] | SelRegions[10]; // exclusion-tag: unused-idempotent // Detect access faults assign PMAAccessFault = (SelRegions[0]) & AccessRWX | AtomicAccessM & ~AtomicAllowed; diff --git a/testbench/testbench.sv b/testbench/testbench.sv index 56a8db268..42014cbdb 100644 --- a/testbench/testbench.sv +++ b/testbench/testbench.sv @@ -159,7 +159,7 @@ module testbench; end if (tests.size() == 0) begin $display("TEST %s not supported in this configuration", TEST); - //$stop; + $stop; end end // initial begin @@ -511,7 +511,7 @@ module testbench; errors = errors+1; $display(" Error on test %s result %d: adr = %h sim (D$) %h sim (DTIM_SUPPORTED) = %h, signature = %h", TestName, i, (testadr+i)*(P.XLEN/8), testbench.DCacheFlushFSM.ShadowRAM[testadr+i], sig, signature[i]); - //$stop; //***debug + $stop; //***debug end i = i + 1; end diff --git a/testbench/tests.vh b/testbench/tests.vh index f1cc6db39..0a1607a16 100644 --- a/testbench/tests.vh +++ b/testbench/tests.vh @@ -2004,12 +2004,12 @@ string arch64zbs[] = '{ string wally64periph[] = '{ `WALLYTEST, - //"rv64i_m/privilege/src/WALLY-periph-01.S", - //"rv64i_m/privilege/src/WALLY-clint-01.S", - //"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-periph-01.S", + "rv64i_m/privilege/src/WALLY-clint-01.S", + "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-spi-01.S" }; From 29e42b21df4be8f1d0f907974f219a8b5c6d6b39 Mon Sep 17 00:00:00 2001 From: naichewa Date: Thu, 2 Nov 2023 15:42:28 -0700 Subject: [PATCH 10/12] added test cases --- src/uncore/spi_apb.sv | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/uncore/spi_apb.sv b/src/uncore/spi_apb.sv index a177e6502..a707534cc 100644 --- a/src/uncore/spi_apb.sv +++ b/src/uncore/spi_apb.sv @@ -27,7 +27,6 @@ // Current limitations: Flash read sequencer mode not implemented, dual and quad modes untestable with current test plan. // Hardware interlock change to busy signal -// Get rid of dual/ quad mode // write tests for fifo full and empty watermark edge cases // HoldModeDeassert make sure still works // Comment on FIFOs: watermark calculations @@ -423,7 +422,7 @@ module SynchFIFO #(parameter M =3 , N= 8)( output logic wwatermark, rwatermark); logic [N-1:0] mem[2**M]; - logic [M:0] rwpr, wptr; + logic [M:0] rptr, wptr; logic [M:0] rptrnext, wptrnext; logic rempty_val; logic wfull_val; From 4651b807ed598c4875b225a89c16943dbd7aabf9 Mon Sep 17 00:00:00 2001 From: naichewa Date: Thu, 2 Nov 2023 15:43:08 -0700 Subject: [PATCH 11/12] added test cases --- .../references/WALLY-spi-01.reference_output | 19 ++++++++++ .../rv64i_m/privilege/src/WALLY-spi-01.S | 35 +++++++++++++------ 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-spi-01.reference_output b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-spi-01.reference_output index 520908265..3e947f38d 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-spi-01.reference_output +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-spi-01.reference_output @@ -116,6 +116,25 @@ 00000000 000000AB 00000000 +#000000CE hold mode deassert +#00000000 +#00000002 #fifo edge case +#00000000 +#000000D1 +#00000000 +#000000C1 +#00000000 +#000000B1 +#00000000 +#000000A1 +#0000001B +#00000000 +#0000001A +#00000000 +#000000F1 +#00000000 +#000000E1 +#00000000 000000F0 #fmt register 00000000 00000000 diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S index 2ae66de05..4960e85dc 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-spi-01.S @@ -308,24 +308,39 @@ test_cases: # Test hold mode deassert conditions -.8byte delay1, 0x00000001, write32_test # reset delay1 register -.8byte delay0, 0x00010001, write32_test # reset delay0 register -.8byte cs_mode, 0x00000002, write32_test # set cs_mode to hold -.8byte tx_data, 0x000000CE, write32_test # place data into tx_data -.8byte cs_id, 0x00000001, write32_test #change selected cs pin. should deassert cs[0] in hold mode -.8byte cs_def, 0x00001101, write32_test # change selected cs pins def value. should deassert cs[1] -.8byte cs_def, 0x00001111, write32_test # reset cs_def -.8byte cs_mode, 0x00000000, write32_test # change cs_mode to auto, should deassert cs[1], have now gone through all deassertion conditions -.8byte rx_data, 0x000000CE, read32_test # clear rx_fifo +#.8byte delay1, 0x00000001, write32_test # reset delay1 register +#.8byte delay0, 0x00010001, write32_test # reset delay0 register +#.8byte cs_mode, 0x00000002, write32_test # set cs_mode to hold +#.8byte tx_data, 0x000000CE, write32_test # place data into tx_data +#.8byte cs_id, 0x00000001, write32_test #change selected cs pin. should deassert cs[0] in hold mode +#.8byte cs_def, 0x00001101, write32_test # change selected cs pins def value. should deassert cs[1] +#.8byte cs_def, 0x00001111, write32_test # reset cs_def +#.8byte cs_mode, 0x00000000, write32_test # change cs_mode to auto, should deassert cs[1], have now gone through all deassertion conditions +#.8byte rx_data, 0x000000CE, read32_test # clear rx_fifo # Test transmit and receive fifo full edge cases +#.8byte rx_mark, 0x00000007, write32_test #set rx watermark to 7 (only high when full) +#.8byte tx_data, 0xA1B1C1D1, spi_burst_send #fill rx fifo +#.8byte tx_data, 0xE1F11A1B, spi_burst_send +#.8byte 0x0, 0x00000007, spi_data_wait #wait for rx fifo to fill +#.8byte ip, 0x00000002, read32_test #rxmark ip should be high +#.8byte rx_data, 0x000000D1, read32_test #clear rx fifo +#.8byte rx_data, 0x000000C1, read32_test +#.8byte rx_data, 0x000000B1, read32_test +#.8byte rx_data, 0x000000A1, read32_test +#.8byte rx_data, 0x0000001B, read32_test +#.8byte rx_data, 0x0000001A, read32_test +#.8byte rx_data, 0x000000F1, read32_test +#.8byte rx_data, 0x000000E1, read32_test +#test fifo watermark edge cases (wrap arounds, 2s complement) # =========== Test frame format (fmt) register =========== # Test frame length of 4 - +.8byte delay1, 0x00000001, write32_test # reset delay1 register +.8byte delay0, 0x00010001, write32_test # reset delay0 register .8byte sck_mode, 0x00000000, write32_test #reset sckmode register .8byte cs_mode, 0x00000000, write32_test # set cs_mode to AUTO .8byte fmt, 0x00040000, write32_test # set frame length to 4 From 75f1c070221082984e2f890b3bceee0bdfa5f48c Mon Sep 17 00:00:00 2001 From: naichewa Date: Fri, 3 Nov 2023 13:16:19 -0700 Subject: [PATCH 12/12] merge main, pull /A/ tests --- addins/riscv-arch-test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addins/riscv-arch-test b/addins/riscv-arch-test index 873d16e74..197179fdc 160000 --- a/addins/riscv-arch-test +++ b/addins/riscv-arch-test @@ -1 +1 @@ -Subproject commit 873d16e748ad60023dcdda3926144957c096e31d +Subproject commit 197179fdc9dfeeca821e848f373c897a3fdae86c