From d5d4f9d044e4402a90fd81ca76dbf5a702c01e56 Mon Sep 17 00:00:00 2001 From: naichewa Date: Thu, 12 Oct 2023 13:36:57 -0700 Subject: [PATCH 01/36] 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/36] 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/36] 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/36] 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/36] 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/36] 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/36] 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/36] 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/36] 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/36] 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/36] 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 09aebbf25286dca9795a01c59e171690dca6b6b4 Mon Sep 17 00:00:00 2001 From: David Harris Date: Fri, 3 Nov 2023 04:38:27 -0700 Subject: [PATCH 12/36] Fixed regression error of watchdog timeout when PCM is optimized out of the IFU --- src/ifu/ifu.sv | 26 ++++++++++++++++---------- testbench/common/watchdog.sv | 8 +++++--- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/ifu/ifu.sv b/src/ifu/ifu.sv index 325153ac5..fc3107030 100644 --- a/src/ifu/ifu.sv +++ b/src/ifu/ifu.sv @@ -114,10 +114,7 @@ module ifu import cvw::*; #(parameter cvw_t P) ( logic [31:0] IROMInstrF; // Instruction from the IROM logic [31:0] ICacheInstrF; // Instruction from the I$ logic [31:0] InstrRawF; // Instruction from the IROM, I$, or bus - logic CompressedF; // The fetched instruction is compressed - logic CompressedD; // The decoded instruction is compressed - logic CompressedE; // The execution instruction is compressed - logic CompressedM; // The execution instruction is compressed + logic CompressedF, CompressedE; // The fetched instruction is compressed logic [31:0] PostSpillInstrRawF; // Fetch instruction after merge two halves of spill logic [31:0] InstrRawD; // Non-decompressed instruction in the Decode stage logic IllegalIEUInstrD; // IEU Instruction (regular or compressed) is not good @@ -403,17 +400,26 @@ module ifu import cvw::*; #(parameter cvw_t P) ( // PCM is only needed with CSRs or branch prediction if (P.ZICSR_SUPPORTED | P.BPRED_SUPPORTED) flopenr #(P.XLEN) PCMReg(clk, reset, ~StallM, PCE, PCM); - else assign PCM = 0; + else assign PCM = 0; - flopenrc #(1) CompressedDReg(clk, reset, FlushD, ~StallD, CompressedF, CompressedD); - flopenrc #(1) CompressedEReg(clk, reset, FlushE, ~StallE, CompressedD, CompressedE); - assign PCLinkE = PCE + (CompressedE ? 'd2 : 'd4); // 'd4 means 4 but stops Design Compiler complaining about signed to unsigned conversion + if (P.COMPRESSED_SUPPORTED) begin + logic CompressedD; // instruction is compressed + flopenrc #(1) CompressedDReg(clk, reset, FlushD, ~StallD, CompressedF, CompressedD); + flopenrc #(1) CompressedEReg(clk, reset, FlushE, ~StallE, CompressedD, CompressedE); + assign PCLinkE = PCE + (CompressedE ? 'd2 : 'd4); // 'd4 means 4 but stops Design Compiler complaining about signed to unsigned conversion + end else begin + assign CompressedE = 0; + assign PCLinkE = PCE + 'd4; + end // pipeline original compressed instruction in case it is needed for MTVAL on an illegal instruction exception - if (P.ZICSR_SUPPORTED) begin + if (P.ZICSR_SUPPORTED & P.COMPRESSED_SUPPORTED) begin + logic CompressedM; // instruction is compressed flopenrc #(16) InstrRawEReg(clk, reset, FlushE, ~StallE, InstrRawD[15:0], InstrRawE); flopenrc #(16) InstrRawMReg(clk, reset, FlushM, ~StallM, InstrRawE, InstrRawM); flopenrc #(1) CompressedMReg(clk, reset, FlushM, ~StallM, CompressedE, CompressedM); mux2 #(32) InstrOrigMux(InstrM, {16'b0, InstrRawM}, CompressedM, InstrOrigM); - end else assign InstrOrigM = 0; + end else + assign InstrOrigM = InstrM; + endmodule diff --git a/testbench/common/watchdog.sv b/testbench/common/watchdog.sv index 51ed8c30f..1e2b760ca 100644 --- a/testbench/common/watchdog.sv +++ b/testbench/common/watchdog.sv @@ -30,11 +30,13 @@ module watchdog #(parameter XLEN, WatchDogTimerThreshold) ); // check for hang up. - logic [XLEN-1:0] PCW; - flopenr #(XLEN) PCWReg(clk, reset, ~dut.core.ieu.dp.StallW, dut.core.ifu.PCM, PCW); - logic [XLEN-1:0] OldPCW; + logic [XLEN-1:0] PCM, PCW, OldPCW; integer WatchDogTimerCount; logic WatchDogTimeOut; + + flopenr #(XLEN) PCMReg(clk, reset, ~dut.core.ifu.StallM, dut.core.ifu.PCE, PCM); // duplicate PCM register because it is not in ifu for all configurations + flopenr #(XLEN) PCWReg(clk, reset, ~dut.core.ieu.dp.StallW, PCM, PCW); + always_ff @(posedge clk) begin OldPCW <= PCW; if(OldPCW == PCW) WatchDogTimerCount = WatchDogTimerCount + 1'b1; From 402538e13c282b225594d4477e43c023c9b27d07 Mon Sep 17 00:00:00 2001 From: David Harris Date: Fri, 3 Nov 2023 04:59:44 -0700 Subject: [PATCH 13/36] Temporary fix of InstrM to prevent testbench hanging --- src/ifu/ifu.sv | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ifu/ifu.sv b/src/ifu/ifu.sv index fc3107030..4e51fed71 100644 --- a/src/ifu/ifu.sv +++ b/src/ifu/ifu.sv @@ -386,22 +386,22 @@ module ifu import cvw::*; #(parameter cvw_t P) ( assign BranchMisalignedFaultE = (IEUAdrE[1] & ~P.COMPRESSED_SUPPORTED) & PCSrcE; flopenr #(1) InstrMisalignedReg(clk, reset, ~StallM, BranchMisalignedFaultE, InstrMisalignedFaultM); - // Instruction and PC pipeline registers - // Cannot use flopenrc for Instr(E/M) as it resets to NOP not 0. + // Instruction and PC pipeline registers flush to NOP, not zero mux2 #(32) FlushInstrEMux(InstrD, nop, FlushE, NextInstrD); mux2 #(32) FlushInstrMMux(InstrE, nop, FlushM, NextInstrE); flopenr #(32) InstrEReg(clk, reset, ~StallE, NextInstrD, InstrE); flopenr #(P.XLEN) PCEReg(clk, reset, ~StallE, PCD, PCE); // InstrM is only needed with CSRs or atomic operations - if (P.ZICSR_SUPPORTED | P.A_SUPPORTED) + if (P.ZICSR_SUPPORTED | P.A_SUPPORTED | 1) flopenr #(32) InstrMReg(clk, reset, ~StallM, NextInstrE, InstrM); else assign InstrM = 0; // PCM is only needed with CSRs or branch prediction if (P.ZICSR_SUPPORTED | P.BPRED_SUPPORTED) flopenr #(P.XLEN) PCMReg(clk, reset, ~StallM, PCE, PCM); else assign PCM = 0; - + + // If compressed instructions are supported, increment PCLink by 2 or 4 for a jal. Otherwise, just by 4 if (P.COMPRESSED_SUPPORTED) begin logic CompressedD; // instruction is compressed flopenrc #(1) CompressedDReg(clk, reset, FlushD, ~StallD, CompressedF, CompressedD); @@ -411,9 +411,9 @@ module ifu import cvw::*; #(parameter cvw_t P) ( assign CompressedE = 0; assign PCLinkE = PCE + 'd4; end - + // pipeline original compressed instruction in case it is needed for MTVAL on an illegal instruction exception - if (P.ZICSR_SUPPORTED & P.COMPRESSED_SUPPORTED) begin + if (P.ZICSR_SUPPORTED & P.COMPRESSED_SUPPORTED | 1) begin logic CompressedM; // instruction is compressed flopenrc #(16) InstrRawEReg(clk, reset, FlushE, ~StallE, InstrRawD[15:0], InstrRawE); flopenrc #(16) InstrRawMReg(clk, reset, FlushM, ~StallM, InstrRawE, InstrRawM); From dd072c80f2d05bcc92d1e43d2ce2f06e30c38df9 Mon Sep 17 00:00:00 2001 From: David Harris Date: Fri, 3 Nov 2023 05:24:15 -0700 Subject: [PATCH 14/36] Updated testbenches to capture InstrM because it may be optimized out of IFU --- src/ifu/ifu.sv | 6 +++--- testbench/testbench-imperas.sv | 11 ++++++++--- testbench/testbench-linux-imperas.sv | 12 +++++++++--- testbench/testbench-linux.sv | 12 +++++++++--- testbench/testbench-xcelium.sv | 13 +++++++++---- testbench/testbench.sv | 13 +++++++++---- 6 files changed, 47 insertions(+), 20 deletions(-) diff --git a/src/ifu/ifu.sv b/src/ifu/ifu.sv index 4e51fed71..4fdef8c6a 100644 --- a/src/ifu/ifu.sv +++ b/src/ifu/ifu.sv @@ -388,14 +388,14 @@ module ifu import cvw::*; #(parameter cvw_t P) ( // Instruction and PC pipeline registers flush to NOP, not zero mux2 #(32) FlushInstrEMux(InstrD, nop, FlushE, NextInstrD); - mux2 #(32) FlushInstrMMux(InstrE, nop, FlushM, NextInstrE); flopenr #(32) InstrEReg(clk, reset, ~StallE, NextInstrD, InstrE); flopenr #(P.XLEN) PCEReg(clk, reset, ~StallE, PCD, PCE); // InstrM is only needed with CSRs or atomic operations - if (P.ZICSR_SUPPORTED | P.A_SUPPORTED | 1) + if (P.ZICSR_SUPPORTED | P.A_SUPPORTED) begin + mux2 #(32) FlushInstrMMux(InstrE, nop, FlushM, NextInstrE); flopenr #(32) InstrMReg(clk, reset, ~StallM, NextInstrE, InstrM); - else assign InstrM = 0; + end else assign InstrM = 0; // PCM is only needed with CSRs or branch prediction if (P.ZICSR_SUPPORTED | P.BPRED_SUPPORTED) flopenr #(P.XLEN) PCMReg(clk, reset, ~StallM, PCE, PCM); diff --git a/testbench/testbench-imperas.sv b/testbench/testbench-imperas.sv index ac7e49a48..4360d4422 100644 --- a/testbench/testbench-imperas.sv +++ b/testbench/testbench-imperas.sv @@ -214,7 +214,7 @@ module testbench; `endif flopenr #(P.XLEN) PCWReg(clk, reset, ~dut.core.ieu.dp.StallW, dut.core.ifu.PCM, PCW); - flopenr #(32) InstrWReg(clk, reset, ~dut.core.ieu.dp.StallW, dut.core.ifu.InstrM, InstrW); + flopenr #(32) InstrWReg(clk, reset, ~dut.core.ieu.dp.StallW, InstrM, InstrW); // check assertions for a legal configuration riscvassertions #(P) riscvassertions(); @@ -261,7 +261,7 @@ module testbench; instrTrackerTB it(clk, reset, dut.core.ieu.dp.FlushE, dut.core.ifu.InstrRawF[31:0], dut.core.ifu.InstrD, dut.core.ifu.InstrE, - dut.core.ifu.InstrM, InstrW, + InstrM, InstrW, InstrFName, InstrDName, InstrEName, InstrMName, InstrWName); // initialize tests @@ -298,6 +298,11 @@ module testbench; .ProgramLabelMapFile(ProgramLabelMapFile)); end + // Duplicate copy of pipeline registers that are optimized out of some configurations + logic [31:0] NextInstrE, InstrM; + mux2 #(32) FlushInstrMMux(dut.core.ifu.InstrE, dut.core.ifu.nop, dut.core.ifu.FlushM, NextInstrE); + flopenr #(32) InstrMReg(clk, reset, ~dut.core.ifu.StallM, NextInstrE, InstrM); + // Termination condition // terminate on a specific ECALL after li x3,1 for old Imperas tests, *** remove this when old imperas tests are removed // or sw gp,-56(t0) for new Imperas tests @@ -311,7 +316,7 @@ module testbench; (dut.core.ieu.dp.regf.we3 & dut.core.ieu.dp.regf.a3 == 3 & dut.core.ieu.dp.regf.wd3 == 1)) | - ((dut.core.ifu.InstrM == 32'h6f | dut.core.ifu.InstrM == 32'hfc32a423 | dut.core.ifu.InstrM == 32'hfc32a823) & dut.core.ieu.c.InstrValidM ) | + ((InstrM == 32'h6f | InstrM == 32'hfc32a423 | InstrM == 32'hfc32a823) & dut.core.ieu.c.InstrValidM ) | ((dut.core.lsu.IEUAdrM == ProgramAddrLabelArray["tohost"]) & InstrMName == "SW" ); DCacheFlushFSM #(P) DCacheFlushFSM(.clk(clk), diff --git a/testbench/testbench-linux-imperas.sv b/testbench/testbench-linux-imperas.sv index 52a351d2e..c5443af42 100644 --- a/testbench/testbench-linux-imperas.sv +++ b/testbench/testbench-linux-imperas.sv @@ -229,10 +229,16 @@ module testbench; /////////////////////////////////////////////////////////////////////////////// /////////////////////////////// Cache Issue /////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// + + // Duplicate copy of pipeline registers that are optimized out of some configurations + logic [31:0] NextInstrE, InstrM; + mux2 #(32) FlushInstrMMux(dut.core.ifu.InstrE, dut.core.ifu.nop, dut.core.ifu.FlushM, NextInstrE); + flopenr #(32) InstrMReg(clk, reset, ~dut.core.ifu.StallM, NextInstrE, InstrM); + logic probe; if (NO_SPOOFING) assign probe = testbench.dut.core.PCM == 64'hffffffff80200c8c - & testbench.dut.core.InstrM != 32'h14021273 + & InstrM != 32'h14021273 & testbench.dut.core.InstrValidM; @@ -452,7 +458,7 @@ module testbench; `define FLUSHW dut.core.FlushW `define STALLW dut.core.StallW flopenrc #(P.XLEN) PCWReg(clk, reset, `FLUSHW, ~`STALLW, `PCM, PCW); - flopenr #(32) InstrWReg(clk, reset, ~`STALLW, `FLUSHW ? nop : dut.core.ifu.InstrM, InstrW); + flopenr #(32) InstrWReg(clk, reset, ~`STALLW, `FLUSHW ? nop : InstrM, InstrW); flopenrc #(1) controlregW(clk, reset, `FLUSHW, ~`STALLW, dut.core.ieu.c.InstrValidM, InstrValidW); flopenrc #(P.XLEN) IEUAdrWReg(clk, reset, `FLUSHW, ~`STALLW, dut.core.IEUAdrM, IEUAdrW); flopenrc #(P.XLEN) WriteDataWReg(clk, reset, `FLUSHW, ~`STALLW, dut.core.lsu.WriteDataM, WriteDataW); @@ -969,7 +975,7 @@ module testbench; instrTrackerTB it(clk, reset, dut.core.ieu.dp.FlushE, dut.core.ifu.InstrRawF[31:0], dut.core.ifu.InstrD, dut.core.ifu.InstrE, - dut.core.ifu.InstrM, InstrW, + InstrM, InstrW, InstrFName, InstrDName, InstrEName, InstrMName, InstrWName); // ------------------ diff --git a/testbench/testbench-linux.sv b/testbench/testbench-linux.sv index 683f55952..ef165865f 100644 --- a/testbench/testbench-linux.sv +++ b/testbench/testbench-linux.sv @@ -212,10 +212,16 @@ module testbench; /////////////////////////////////////////////////////////////////////////////// /////////////////////////////// Cache Issue /////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// + + // Duplicate copy of pipeline registers that are optimized out of some configurations + logic [31:0] NextInstrE, InstrM; + mux2 #(32) FlushInstrMMux(dut.core.ifu.InstrE, dut.core.ifu.nop, dut.core.ifu.FlushM, NextInstrE); + flopenr #(32) InstrMReg(dut.core.clk, dut.core.reset, ~dut.core.ifu.StallM, NextInstrE, InstrM); + logic probe; if (NO_SPOOFING) assign probe = testbench.dut.core.PCM == 64'hffffffff80200c8c - & testbench.dut.core.InstrM != 32'h14021273 + & InstrM != 32'h14021273 & testbench.dut.core.InstrValidM; @@ -280,7 +286,7 @@ module testbench; `define FLUSHW dut.core.FlushW `define STALLW dut.core.StallW flopenrc #(P.XLEN) PCWReg(clk, reset, `FLUSHW, ~`STALLW, `PCM, PCW); - flopenr #(32) InstrWReg(clk, reset, ~`STALLW, `FLUSHW ? nop : dut.core.ifu.InstrM, InstrW); + flopenr #(32) InstrWReg(clk, reset, ~`STALLW, `FLUSHW ? nop : InstrM, InstrW); flopenrc #(1) controlregW(clk, reset, `FLUSHW, ~`STALLW, dut.core.ieu.c.InstrValidM, InstrValidW); flopenrc #(P.XLEN) IEUAdrWReg(clk, reset, `FLUSHW, ~`STALLW, dut.core.IEUAdrM, IEUAdrW); flopenrc #(P.XLEN) WriteDataWReg(clk, reset, `FLUSHW, ~`STALLW, dut.core.lsu.WriteDataM, WriteDataW); @@ -794,7 +800,7 @@ module testbench; instrTrackerTB it(clk, reset, dut.core.ieu.dp.FlushE, dut.core.ifu.InstrRawF[31:0], dut.core.ifu.InstrD, dut.core.ifu.InstrE, - dut.core.ifu.InstrM, InstrW, + InstrM, InstrW, InstrFName, InstrDName, InstrEName, InstrMName, InstrWName); // ------------------ diff --git a/testbench/testbench-xcelium.sv b/testbench/testbench-xcelium.sv index 89a7cc995..f5dd89290 100644 --- a/testbench/testbench-xcelium.sv +++ b/testbench/testbench-xcelium.sv @@ -440,20 +440,25 @@ module testbench; // Support logic //////////////////////////////////////////////////////////////////////////////// + // Duplicate copy of pipeline registers that are optimized out of some configurations + logic [31:0] NextInstrE, InstrM; + mux2 #(32) FlushInstrMMux(dut.core.ifu.InstrE, dut.core.ifu.nop, dut.core.ifu.FlushM, NextInstrE); + flopenr #(32) InstrMReg(clk, reset, ~dut.core.ifu.StallM, NextInstrE, InstrM); + // Track names of instructions string InstrFName, InstrDName, InstrEName, InstrMName, InstrWName; logic [31:0] InstrW; - flopenr #(32) InstrWReg(clk, reset, ~dut.core.ieu.dp.StallW, dut.core.ifu.InstrM, InstrW); + flopenr #(32) InstrWReg(clk, reset, ~dut.core.ieu.dp.StallW, InstrM, InstrW); instrTrackerTB it(clk, reset, dut.core.ieu.dp.FlushE, dut.core.ifu.InstrRawF[31:0], dut.core.ifu.InstrD, dut.core.ifu.InstrE, - dut.core.ifu.InstrM, InstrW, + InstrM, InstrW, InstrFName, InstrDName, InstrEName, InstrMName, InstrWName); // watch for problems such as lockup, reading unitialized memory, bad configs watchdog #(P.XLEN, 1000000) watchdog(.clk, .reset); // check if PCW is stuck ramxdetector #(P.XLEN, P.LLEN) ramxdetector(clk, dut.core.lsu.MemRWM[1], dut.core.lsu.LSULoadAccessFaultM, dut.core.lsu.ReadDataM, - dut.core.ifu.PCM, dut.core.ifu.InstrM, dut.core.lsu.IEUAdrM, InstrMName); + dut.core.ifu.PCM, InstrM, dut.core.lsu.IEUAdrM, InstrMName); riscvassertions #(P) riscvassertions(); // check assertions for a legal configuration loggers #(P, TEST, PrintHPMCounters, I_CACHE_ADDR_LOGGER, D_CACHE_ADDR_LOGGER, BPRED_LOGGER) loggers (clk, reset, DCacheFlushStart, DCacheFlushDone, memfilename); @@ -478,7 +483,7 @@ module testbench; (dut.core.ieu.dp.regf.we3 & dut.core.ieu.dp.regf.a3 == 3 & dut.core.ieu.dp.regf.wd3 == 1)) | - ((dut.core.ifu.InstrM == 32'h6f | dut.core.ifu.InstrM == 32'hfc32a423 | dut.core.ifu.InstrM == 32'hfc32a823) & dut.core.ieu.c.InstrValidM ) | + ((InstrM == 32'h6f | InstrM == 32'hfc32a423 | InstrM == 32'hfc32a823) & dut.core.ieu.c.InstrValidM ) | ((dut.core.lsu.IEUAdrM == ProgramAddrLabelArray["tohost"]) & InstrMName == "SW" ); DCacheFlushFSM #(P) DCacheFlushFSM(.clk(clk), .reset(reset), .start(DCacheFlushStart), .done(DCacheFlushDone)); diff --git a/testbench/testbench.sv b/testbench/testbench.sv index 97d91b0ab..063ff5448 100644 --- a/testbench/testbench.sv +++ b/testbench/testbench.sv @@ -408,20 +408,25 @@ module testbench; // Support logic //////////////////////////////////////////////////////////////////////////////// + // Duplicate copy of pipeline registers that are optimized out of some configurations + logic [31:0] NextInstrE, InstrM; + mux2 #(32) FlushInstrMMux(dut.core.ifu.InstrE, dut.core.ifu.nop, dut.core.ifu.FlushM, NextInstrE); + flopenr #(32) InstrMReg(clk, reset, ~dut.core.ifu.StallM, NextInstrE, InstrM); + // Track names of instructions string InstrFName, InstrDName, InstrEName, InstrMName, InstrWName; logic [31:0] InstrW; - flopenr #(32) InstrWReg(clk, reset, ~dut.core.ieu.dp.StallW, dut.core.ifu.InstrM, InstrW); + flopenr #(32) InstrWReg(clk, reset, ~dut.core.ieu.dp.StallW, InstrM, InstrW); instrTrackerTB it(clk, reset, dut.core.ieu.dp.FlushE, dut.core.ifu.InstrRawF[31:0], dut.core.ifu.InstrD, dut.core.ifu.InstrE, - dut.core.ifu.InstrM, InstrW, + InstrM, InstrW, InstrFName, InstrDName, InstrEName, InstrMName, InstrWName); // watch for problems such as lockup, reading unitialized memory, bad configs watchdog #(P.XLEN, 1000000) watchdog(.clk, .reset); // check if PCW is stuck ramxdetector #(P.XLEN, P.LLEN) ramxdetector(clk, dut.core.lsu.MemRWM[1], dut.core.lsu.LSULoadAccessFaultM, dut.core.lsu.ReadDataM, - dut.core.ifu.PCM, dut.core.ifu.InstrM, dut.core.lsu.IEUAdrM, InstrMName); + dut.core.ifu.PCM, InstrM, dut.core.lsu.IEUAdrM, InstrMName); riscvassertions #(P) riscvassertions(); // check assertions for a legal configuration loggers #(P, TEST, PrintHPMCounters, I_CACHE_ADDR_LOGGER, D_CACHE_ADDR_LOGGER, BPRED_LOGGER) loggers (clk, reset, DCacheFlushStart, DCacheFlushDone, memfilename); @@ -446,7 +451,7 @@ module testbench; (dut.core.ieu.dp.regf.we3 & dut.core.ieu.dp.regf.a3 == 3 & dut.core.ieu.dp.regf.wd3 == 1)) | - ((dut.core.ifu.InstrM == 32'h6f | dut.core.ifu.InstrM == 32'hfc32a423 | dut.core.ifu.InstrM == 32'hfc32a823) & dut.core.ieu.c.InstrValidM ) | + ((InstrM == 32'h6f | InstrM == 32'hfc32a423 | InstrM == 32'hfc32a823) & dut.core.ieu.c.InstrValidM ) | ((dut.core.lsu.IEUAdrM == ProgramAddrLabelArray["tohost"]) & InstrMName == "SW" ); DCacheFlushFSM #(P) DCacheFlushFSM(.clk(clk), .reset(reset), .start(DCacheFlushStart), .done(DCacheFlushDone)); From 1f2899de14a54225ffa860000f2da73b4f38a842 Mon Sep 17 00:00:00 2001 From: David Harris Date: Fri, 3 Nov 2023 05:44:13 -0700 Subject: [PATCH 15/36] Modified rams to take USE_SRAM rather than P to facilitate synthesis --- src/cache/cacheway.sv | 6 +++--- src/fpu/fdivsqrt/fdivsqrtcycles.sv | 3 ++- src/generic/mem/ram1p1rwbe.sv | 9 ++++----- src/generic/mem/ram1p1rwe.sv | 9 ++++----- src/generic/mem/ram2p1r1wbe.sv | 9 ++++----- src/ifu/bpred/btb.sv | 2 +- src/ifu/bpred/gshare.sv | 2 +- src/ifu/bpred/gsharebasic.sv | 2 +- src/ifu/bpred/localaheadbp.sv | 4 ++-- src/ifu/bpred/localbpbasic.sv | 2 +- src/ifu/bpred/localrepairbp.sv | 6 +++--- src/ifu/bpred/twoBitPredictor.sv | 2 +- src/lsu/dtim.sv | 2 +- src/uncore/ram_ahb.sv | 2 +- 14 files changed, 29 insertions(+), 31 deletions(-) diff --git a/src/cache/cacheway.sv b/src/cache/cacheway.sv index 216cd82d2..f64397070 100644 --- a/src/cache/cacheway.sv +++ b/src/cache/cacheway.sv @@ -126,7 +126,7 @@ module cacheway import cvw::*; #(parameter cvw_t P, // Tag Array ///////////////////////////////////////////////////////////////////////////////////////////// - ram1p1rwe #(.P(P), .DEPTH(NUMLINES), .WIDTH(TAGLEN)) CacheTagMem(.clk, .ce(CacheEn), + ram1p1rwe #(.USE_SRAM(P.USE_SRAM), .DEPTH(NUMLINES), .WIDTH(TAGLEN)) CacheTagMem(.clk, .ce(CacheEn), .addr(CacheSet), .dout(ReadTag), .din(PAdr[PA_BITS-1:OFFSETLEN+INDEXLEN]), .we(SetValidEN)); @@ -148,12 +148,12 @@ module cacheway import cvw::*; #(parameter cvw_t P, for(words = 0; words < NUMSRAM; words++) begin: word if (!READ_ONLY_CACHE) begin:wordram - ram1p1rwbe #(.P(P), .DEPTH(NUMLINES), .WIDTH(SRAMLEN)) CacheDataMem(.clk, .ce(CacheEn), .addr(CacheSet), + ram1p1rwbe #(.USE_SRAM(P.USE_SRAM), .DEPTH(NUMLINES), .WIDTH(SRAMLEN)) CacheDataMem(.clk, .ce(CacheEn), .addr(CacheSet), .dout(ReadDataLine[SRAMLEN*(words+1)-1:SRAMLEN*words]), .din(LineWriteData[SRAMLEN*(words+1)-1:SRAMLEN*words]), .we(SelectedWriteWordEn), .bwe(FinalByteMask[SRAMLENINBYTES*(words+1)-1:SRAMLENINBYTES*words])); end else begin:wordram // no byte-enable needed for i$. - ram1p1rwe #(.P(P), .DEPTH(NUMLINES), .WIDTH(SRAMLEN)) CacheDataMem(.clk, .ce(CacheEn), .addr(CacheSet), + ram1p1rwe #(.USE_SRAM(P.USE_SRAM), .DEPTH(NUMLINES), .WIDTH(SRAMLEN)) CacheDataMem(.clk, .ce(CacheEn), .addr(CacheSet), .dout(ReadDataLine[SRAMLEN*(words+1)-1:SRAMLEN*words]), .din(LineWriteData[SRAMLEN*(words+1)-1:SRAMLEN*words]), .we(SelectedWriteWordEn)); diff --git a/src/fpu/fdivsqrt/fdivsqrtcycles.sv b/src/fpu/fdivsqrt/fdivsqrtcycles.sv index 09b17871a..ed28c9355 100644 --- a/src/fpu/fdivsqrt/fdivsqrtcycles.sv +++ b/src/fpu/fdivsqrt/fdivsqrtcycles.sv @@ -65,7 +65,8 @@ module fdivsqrtcycles import cvw::*; #(parameter cvw_t P) ( endcase always_comb begin - if (SqrtE) fbits = Nf + 2 + 2; // Nf + two fractional bits for round/guard + 2 for right shift by up to 2 + if (SqrtE) fbits = Nf + 2 + 1; // Nf + two fractional bits for round/guard + 2 for right shift by up to 2 *** unclear why it works with just +1; is it related to DIVCOPIES logic below? + // if (SqrtE) fbits = Nf + 2 + 2; // Nf + two fractional bits for round/guard + 2 for right shift by up to 2 else fbits = Nf + 2 + P.LOGR; // Nf + two fractional bits for round/guard + integer bits - try this when placing results in msbs if (P.IDIV_ON_FPU) CyclesE = IntDivE ? ((nE + 1)/P.DIVCOPIES) : (fbits + (P.LOGR*P.DIVCOPIES)-1)/(P.LOGR*P.DIVCOPIES); else CyclesE = (fbits + (P.LOGR*P.DIVCOPIES)-1)/(P.LOGR*P.DIVCOPIES); diff --git a/src/generic/mem/ram1p1rwbe.sv b/src/generic/mem/ram1p1rwbe.sv index 46716aa75..bf246bfe6 100644 --- a/src/generic/mem/ram1p1rwbe.sv +++ b/src/generic/mem/ram1p1rwbe.sv @@ -32,8 +32,7 @@ // WIDTH is number of bits in one "word" of the memory, DEPTH is number of such words -module ram1p1rwbe import cvw::*; #(parameter cvw_t P, parameter DEPTH=64, WIDTH=44, - parameter PRELOAD_ENABLED=0) ( +module ram1p1rwbe import cvw::*; #(parameter USE_SRAM, DEPTH=64, WIDTH=44, PRELOAD_ENABLED=0) ( input logic clk, input logic ce, input logic [$clog2(DEPTH)-1:0] addr, @@ -48,7 +47,7 @@ module ram1p1rwbe import cvw::*; #(parameter cvw_t P, parameter DEPTH=64, WIDTH= // *************************************************************************** // TRUE SRAM macro // *************************************************************************** - if ((P.USE_SRAM == 1) & (WIDTH == 128) & (DEPTH == 64)) begin // Cache data subarray + if ((USE_SRAM == 1) & (WIDTH == 128) & (DEPTH == 64)) begin // Cache data subarray genvar index; // 64 x 128-bit SRAM logic [WIDTH-1:0] BitWriteMask; @@ -58,7 +57,7 @@ module ram1p1rwbe import cvw::*; #(parameter cvw_t P, parameter DEPTH=64, WIDTH= .A(addr), .D(din), .BWEB(~BitWriteMask), .Q(dout)); - end else if ((P.USE_SRAM == 1) & (WIDTH == 44) & (DEPTH == 64)) begin // RV64 cache tag + end else if ((USE_SRAM == 1) & (WIDTH == 44) & (DEPTH == 64)) begin // RV64 cache tag genvar index; // 64 x 44-bit SRAM logic [WIDTH-1:0] BitWriteMask; @@ -68,7 +67,7 @@ module ram1p1rwbe import cvw::*; #(parameter cvw_t P, parameter DEPTH=64, WIDTH= .A(addr), .D(din), .BWEB(~BitWriteMask), .Q(dout)); - end else if ((P.USE_SRAM == 1) & (WIDTH == 22) & (DEPTH == 64)) begin // RV32 cache tag + end else if ((USE_SRAM == 1) & (WIDTH == 22) & (DEPTH == 64)) begin // RV32 cache tag genvar index; // 64 x 22-bit SRAM logic [WIDTH-1:0] BitWriteMask; diff --git a/src/generic/mem/ram1p1rwe.sv b/src/generic/mem/ram1p1rwe.sv index 40929544a..645141b01 100644 --- a/src/generic/mem/ram1p1rwe.sv +++ b/src/generic/mem/ram1p1rwe.sv @@ -30,8 +30,7 @@ // WIDTH is number of bits in one "word" of the memory, DEPTH is number of such words -module ram1p1rwe import cvw::* ; #(parameter cvw_t P, - parameter DEPTH=64, WIDTH=44) ( +module ram1p1rwe import cvw::* ; #(parameter USE_SRAM, DEPTH=64, WIDTH=44) ( input logic clk, input logic ce, input logic [$clog2(DEPTH)-1:0] addr, @@ -45,19 +44,19 @@ module ram1p1rwe import cvw::* ; #(parameter cvw_t P, // *************************************************************************** // TRUE SRAM macro // *************************************************************************** - if ((P.USE_SRAM == 1) & (WIDTH == 128) & (DEPTH == 64)) begin // Cache data subarray + if ((USE_SRAM == 1) & (WIDTH == 128) & (DEPTH == 64)) begin // Cache data subarray // 64 x 128-bit SRAM ram1p1rwbe_64x128 sram1A (.CLK(clk), .CEB(~ce), .WEB(~we), .A(addr), .D(din), .BWEB('0), .Q(dout)); - end else if ((P.USE_SRAM == 1) & (WIDTH == 44) & (DEPTH == 64)) begin // RV64 cache tag + end else if ((USE_SRAM == 1) & (WIDTH == 44) & (DEPTH == 64)) begin // RV64 cache tag // 64 x 44-bit SRAM ram1p1rwbe_64x44 sram1B (.CLK(clk), .CEB(~ce), .WEB(~we), .A(addr), .D(din), .BWEB('0), .Q(dout)); - end else if ((P.USE_SRAM == 1) & (WIDTH == 22) & (DEPTH == 64)) begin // RV32 cache tag + end else if ((USE_SRAM == 1) & (WIDTH == 22) & (DEPTH == 64)) begin // RV32 cache tag // 64 x 22-bit SRAM ram1p1rwbe_64x22 sram1 (.CLK(clk), .CEB(~ce), .WEB(~we), .A(addr), .D(din), diff --git a/src/generic/mem/ram2p1r1wbe.sv b/src/generic/mem/ram2p1r1wbe.sv index 202d0432b..15155fd0f 100644 --- a/src/generic/mem/ram2p1r1wbe.sv +++ b/src/generic/mem/ram2p1r1wbe.sv @@ -31,8 +31,7 @@ // WIDTH is number of bits in one "word" of the memory, DEPTH is number of such words -module ram2p1r1wbe import cvw::*; #(parameter cvw_t P, - parameter DEPTH=1024, WIDTH=68) ( +module ram2p1r1wbe import cvw::*; #(parameter USE_SRAM, DEPTH=1024, WIDTH=68) ( input logic clk, input logic ce1, ce2, input logic [$clog2(DEPTH)-1:0] ra1, @@ -51,7 +50,7 @@ module ram2p1r1wbe import cvw::*; #(parameter cvw_t P, // TRUE Smem macro // *************************************************************************** - if ((P.USE_SRAM == 1) & (WIDTH == 68) & (DEPTH == 1024)) begin + if ((USE_SRAM == 1) & (WIDTH == 68) & (DEPTH == 1024)) begin ram2p1r1wbe_1024x68 memory1(.CLKA(clk), .CLKB(clk), .CEBA(~ce1), .CEBB(~ce2), @@ -63,7 +62,7 @@ module ram2p1r1wbe import cvw::*; #(parameter cvw_t P, .QA(rd1), .QB()); - end else if ((P.USE_SRAM == 1) & (WIDTH == 36) & (DEPTH == 1024)) begin + end else if ((USE_SRAM == 1) & (WIDTH == 36) & (DEPTH == 1024)) begin ram2p1r1wbe_1024x36 memory1(.CLKA(clk), .CLKB(clk), .CEBA(~ce1), .CEBB(~ce2), @@ -75,7 +74,7 @@ module ram2p1r1wbe import cvw::*; #(parameter cvw_t P, .QA(rd1), .QB()); - end else if ((P.USE_SRAM == 1) & (WIDTH == 2) & (DEPTH == 1024)) begin + end else if ((USE_SRAM == 1) & (WIDTH == 2) & (DEPTH == 1024)) begin logic [SRAMWIDTH-1:0] SRAMReadData; logic [SRAMWIDTH-1:0] SRAMWriteData; diff --git a/src/ifu/bpred/btb.sv b/src/ifu/bpred/btb.sv index e93c1decb..066176daa 100644 --- a/src/ifu/bpred/btb.sv +++ b/src/ifu/bpred/btb.sv @@ -92,7 +92,7 @@ module btb import cvw::*; #(parameter cvw_t P, // An optimization may be using a PC relative address. - ram2p1r1wbe #(P, 2**Depth, P.XLEN+4) memory( + ram2p1r1wbe #(.USE_SRAM(P.USE_SRAM), .DEPTH(2**Depth), .WIDTH(P.XLEN+4)) memory( .clk, .ce1(~StallF | reset), .ra1(PCNextFIndex), .rd1(TableBTBPredF), .ce2(~StallW & ~FlushW), .wa2(PCMIndex), .wd2({InstrClassM, IEUAdrM}), .we2(BTBWrongM), .bwe2('1)); diff --git a/src/ifu/bpred/gshare.sv b/src/ifu/bpred/gshare.sv index 460acbcbf..fcdf46655 100644 --- a/src/ifu/bpred/gshare.sv +++ b/src/ifu/bpred/gshare.sv @@ -84,7 +84,7 @@ module gshare import cvw::*; #(parameter cvw_t P, assign BPDirPredF = MatchX ? FwdNewDirPredF : TableBPDirPredF; - ram2p1r1wbe #(P, 2**k, 2) PHT(.clk(clk), + ram2p1r1wbe #(.USE_SRAM(P.USE_SRAM), .DEPTH(2**k), .WIDTH(2)) PHT(.clk(clk), .ce1(~StallF), .ce2(~StallW & ~FlushW), .ra1(IndexNextF), .rd1(TableBPDirPredF), diff --git a/src/ifu/bpred/gsharebasic.sv b/src/ifu/bpred/gsharebasic.sv index 2914c3e3f..7ae9f0282 100644 --- a/src/ifu/bpred/gsharebasic.sv +++ b/src/ifu/bpred/gsharebasic.sv @@ -58,7 +58,7 @@ module gsharebasic import cvw::*; #(parameter cvw_t P, assign IndexM = GHRM; end - ram2p1r1wbe #(P, 2**k, 2) PHT(.clk(clk), + ram2p1r1wbe #(.USE_SRAM(P.USE_SRAM), .DEPTH(2**k), .WIDTH(2)) PHT(.clk(clk), .ce1(~StallF), .ce2(~StallW & ~FlushW), .ra1(IndexNextF), .rd1(BPDirPredF), diff --git a/src/ifu/bpred/localaheadbp.sv b/src/ifu/bpred/localaheadbp.sv index 266219416..4d6d536a7 100644 --- a/src/ifu/bpred/localaheadbp.sv +++ b/src/ifu/bpred/localaheadbp.sv @@ -59,7 +59,7 @@ module localaheadbp import cvw::*; #(parameter cvw_t P, //assign IndexNextF = LHR; assign IndexM = LHRW; - ram2p1r1wbe #(P, 2**k, 2) PHT(.clk(clk), + ram2p1r1wbe #(.USE_SRAM(P.USE_SRAM), .DEPTH(2**k), .WIDTH(2)) PHT(.clk(clk), .ce1(~StallD), .ce2(~StallW & ~FlushW), .ra1(LHRF), .rd1(BPDirPredD), @@ -92,7 +92,7 @@ module localaheadbp import cvw::*; #(parameter cvw_t P, assign IndexLHRM = {PCW[m+1] ^ PCW[1], PCW[m:2]}; assign IndexLHRNextF = {PCNextF[m+1] ^ PCNextF[1], PCNextF[m:2]}; - ram2p1r1wbe #(P, 2**m, k) BHT(.clk(clk), + ram2p1r1wbe #(.USE_SRAM(P.USE_SRAM), .DEPTH(2**m), .WIDTH(k)) BHT(.clk(clk), .ce1(~StallF), .ce2(~StallW & ~FlushW), .ra1(IndexLHRNextF), .rd1(LHRF), diff --git a/src/ifu/bpred/localbpbasic.sv b/src/ifu/bpred/localbpbasic.sv index 8037b743d..d3a694c33 100644 --- a/src/ifu/bpred/localbpbasic.sv +++ b/src/ifu/bpred/localbpbasic.sv @@ -56,7 +56,7 @@ module localbpbasic import cvw::*; #(parameter cvw_t P, assign IndexNextF = LHR; assign IndexM = LHRM; - ram2p1r1wbe #(P, 2**k, 2) PHT(.clk(clk), + ram2p1r1wbe #(.USE_SRAM(P.USE_SRAM), .DEPTH(2**k), .WIDTH(2)) PHT(.clk(clk), .ce1(~StallF), .ce2(~StallW & ~FlushW), .ra1(IndexNextF), .rd1(BPDirPredF), diff --git a/src/ifu/bpred/localrepairbp.sv b/src/ifu/bpred/localrepairbp.sv index 3af6d7b9f..95399e65a 100644 --- a/src/ifu/bpred/localrepairbp.sv +++ b/src/ifu/bpred/localrepairbp.sv @@ -58,7 +58,7 @@ module localrepairbp import cvw::*; #(parameter cvw_t P, logic SpeculativeFlushedF; - ram2p1r1wbe #(P, 2**k, 2) PHT(.clk(clk), + ram2p1r1wbe #(.USE_SRAM(P.USE_SRAM), .DEPTH(2**k), .WIDTH(2)) PHT(.clk(clk), .ce1(~StallD), .ce2(~StallW & ~FlushW), .ra1(LHRF), .rd1(BPDirPredD), @@ -89,7 +89,7 @@ module localrepairbp import cvw::*; #(parameter cvw_t P, assign IndexLHRM = {PCW[m+1] ^ PCW[1], PCW[m:2]}; assign IndexLHRNextF = {PCNextF[m+1] ^ PCNextF[1], PCNextF[m:2]}; - ram2p1r1wbe #(P, 2**m, k) BHT(.clk(clk), + ram2p1r1wbe #(.USE_SRAM(P.USE_SRAM), .DEPTH(2**m), .WIDTH(k)) BHT(.clk(clk), .ce1(~StallF), .ce2(~StallW & ~FlushW), .ra1(IndexLHRNextF), .rd1(LHRCommittedF), @@ -101,7 +101,7 @@ module localrepairbp import cvw::*; #(parameter cvw_t P, assign IndexLHRD = {PCE[m+1] ^ PCE[1], PCE[m:2]}; assign LHRNextE = BranchD ? {BPDirPredD[1], LHRE[k-1:1]} : LHRE; // *** replace with a small CAM - ram2p1r1wbe #(P, 2**m, k) SHB(.clk(clk), + ram2p1r1wbe #(.USE_SRAM(P.USE_SRAM), .DEPTH(2**m), .WIDTH(k)) SHB(.clk(clk), .ce1(~StallF), .ce2(~StallE & ~FlushE), .ra1(IndexLHRNextF), .rd1(LHRSpeculativeF), diff --git a/src/ifu/bpred/twoBitPredictor.sv b/src/ifu/bpred/twoBitPredictor.sv index 52e24d901..5b2fcb9b8 100644 --- a/src/ifu/bpred/twoBitPredictor.sv +++ b/src/ifu/bpred/twoBitPredictor.sv @@ -53,7 +53,7 @@ module twoBitPredictor import cvw::*; #(parameter cvw_t P, parameter XLEN, assign IndexM = {PCM[k+1] ^ PCM[1], PCM[k:2]}; - ram2p1r1wbe #(P, 2**k, 2) PHT(.clk(clk), + ram2p1r1wbe #(.USE_SRAM(P.USE_SRAM), .DEPTH(2**k), .WIDTH(2)) PHT(.clk(clk), .ce1(~StallF), .ce2(~StallW & ~FlushW), .ra1(IndexNextF), .rd1(BPDirPredF), diff --git a/src/lsu/dtim.sv b/src/lsu/dtim.sv index c8668e767..fb3d25adc 100644 --- a/src/lsu/dtim.sv +++ b/src/lsu/dtim.sv @@ -49,6 +49,6 @@ module dtim import cvw::*; #(parameter cvw_t P) ( assign we = MemRWM[0] & ~FlushW; // have to ignore write if Trap. - ram1p1rwbe #(.P(P), .DEPTH(DEPTH), .WIDTH(P.LLEN)) + ram1p1rwbe #(.USE_SRAM(P.USE_SRAM), .DEPTH(DEPTH), .WIDTH(P.LLEN)) ram(.clk, .ce, .we, .bwe(ByteMaskM), .addr(DTIMAdr[ADDR_WDITH+OFFSET-1:OFFSET]), .dout(ReadDataWordM), .din(WriteDataM)); endmodule diff --git a/src/uncore/ram_ahb.sv b/src/uncore/ram_ahb.sv index 17b6c8ed8..7b6c504bd 100644 --- a/src/uncore/ram_ahb.sv +++ b/src/uncore/ram_ahb.sv @@ -71,7 +71,7 @@ module ram_ahb import cvw::*; #(parameter cvw_t P, mux2 #(P.PA_BITS) adrmux(HADDR, HADDRD, memwriteD | ~HREADY, RamAddr); // single-ported RAM - ram1p1rwbe #(.P(P), .DEPTH(RANGE/8), .WIDTH(P.XLEN), .PRELOAD_ENABLED(P.FPGA)) memory(.clk(HCLK), .ce(1'b1), + ram1p1rwbe #(.USE_SRAM(P.USE_SRAM), .DEPTH(RANGE/8), .WIDTH(P.XLEN), .PRELOAD_ENABLED(P.FPGA)) memory(.clk(HCLK), .ce(1'b1), .addr(RamAddr[ADDR_WIDTH+OFFSET-1:OFFSET]), .we(memwriteD), .din(HWDATA), .bwe(HWSTRB), .dout(HREADRam)); // use this to add arbitrary latency to ram. Helps test AHB controller correctness From 7a56a66927339c960225858e2541d5bc99ae625e Mon Sep 17 00:00:00 2001 From: David Harris Date: Fri, 3 Nov 2023 06:37:05 -0700 Subject: [PATCH 16/36] set default USE_SRAM=0 in memories; cleaned up synthesis script grep for cvw_t --- src/generic/mem/ram1p1rwbe.sv | 2 +- src/generic/mem/ram1p1rwe.sv | 2 +- src/generic/mem/ram2p1r1wbe.sv | 2 +- src/generic/mem/rom1p1r.sv | 4 +--- synthDC/scripts/synth.tcl | 8 +++----- 5 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/generic/mem/ram1p1rwbe.sv b/src/generic/mem/ram1p1rwbe.sv index bf246bfe6..4af3c255c 100644 --- a/src/generic/mem/ram1p1rwbe.sv +++ b/src/generic/mem/ram1p1rwbe.sv @@ -32,7 +32,7 @@ // WIDTH is number of bits in one "word" of the memory, DEPTH is number of such words -module ram1p1rwbe import cvw::*; #(parameter USE_SRAM, DEPTH=64, WIDTH=44, PRELOAD_ENABLED=0) ( +module ram1p1rwbe import cvw::*; #(parameter USE_SRAM=0, DEPTH=64, WIDTH=44, PRELOAD_ENABLED=0) ( input logic clk, input logic ce, input logic [$clog2(DEPTH)-1:0] addr, diff --git a/src/generic/mem/ram1p1rwe.sv b/src/generic/mem/ram1p1rwe.sv index 645141b01..e3746c181 100644 --- a/src/generic/mem/ram1p1rwe.sv +++ b/src/generic/mem/ram1p1rwe.sv @@ -30,7 +30,7 @@ // WIDTH is number of bits in one "word" of the memory, DEPTH is number of such words -module ram1p1rwe import cvw::* ; #(parameter USE_SRAM, DEPTH=64, WIDTH=44) ( +module ram1p1rwe import cvw::* ; #(parameter USE_SRAM=0, DEPTH=64, WIDTH=44) ( input logic clk, input logic ce, input logic [$clog2(DEPTH)-1:0] addr, diff --git a/src/generic/mem/ram2p1r1wbe.sv b/src/generic/mem/ram2p1r1wbe.sv index 15155fd0f..1ac11a633 100644 --- a/src/generic/mem/ram2p1r1wbe.sv +++ b/src/generic/mem/ram2p1r1wbe.sv @@ -31,7 +31,7 @@ // WIDTH is number of bits in one "word" of the memory, DEPTH is number of such words -module ram2p1r1wbe import cvw::*; #(parameter USE_SRAM, DEPTH=1024, WIDTH=68) ( +module ram2p1r1wbe import cvw::*; #(parameter USE_SRAM=0, DEPTH=1024, WIDTH=68) ( input logic clk, input logic ce1, ce2, input logic [$clog2(DEPTH)-1:0] ra1, diff --git a/src/generic/mem/rom1p1r.sv b/src/generic/mem/rom1p1r.sv index 60d041423..93f8c82df 100644 --- a/src/generic/mem/rom1p1r.sv +++ b/src/generic/mem/rom1p1r.sv @@ -25,9 +25,7 @@ // This model actually works correctly with vivado. -module rom1p1r #(parameter ADDR_WIDTH = 8, - parameter DATA_WIDTH = 32, - parameter PRELOAD_ENABLED = 0) +module rom1p1r #(parameter ADDR_WIDTH = 8, DATA_WIDTH = 32, PRELOAD_ENABLED = 0) (input logic clk, input logic ce, input logic [ADDR_WIDTH-1:0] addr, diff --git a/synthDC/scripts/synth.tcl b/synthDC/scripts/synth.tcl index 91ec44e2a..9be076edf 100755 --- a/synthDC/scripts/synth.tcl +++ b/synthDC/scripts/synth.tcl @@ -32,17 +32,15 @@ eval file copy -force [glob ${hdl_src}/cvw.sv] {$outputDir/hdl/} eval file copy -force [glob ${hdl_src}/*/*.sv] {$outputDir/hdl/} eval file copy -force [glob ${hdl_src}/*/*/*.sv] {$outputDir/hdl/} -# Check if a wrapper is needed (when cvw_t parameters are used) +# Check if a wrapper is needed and create it (to pass parameters when cvw_t parameters are used) set wrapper 0 -if {[eval exec grep "cvw_t" {$outputDir/hdl/$::env(DESIGN).sv}] ne ""} { +if {[catch {eval exec grep "cvw_t" $outputDir/hdl/$::env(DESIGN).sv}] == 0} { + echo "Creating wrapper" set wrapper 1 # make the wrapper exec python3 $::env(WALLY)/synthDC/scripts/wrapperGen.py $::env(DESIGN) $outputDir/hdl } -# Only for FMA class project; comment out when done -# eval file copy -force [glob ${hdl_src}/fma/fma16.v] {hdl/} - # Enables name mapping if { $saifpower == 1 } { saif_map -start From 75f1c070221082984e2f890b3bceee0bdfa5f48c Mon Sep 17 00:00:00 2001 From: naichewa Date: Fri, 3 Nov 2023 13:16:19 -0700 Subject: [PATCH 17/36] 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 From 568aa3c4a6260c1002fb2de0fc8b158ecf67162e Mon Sep 17 00:00:00 2001 From: David Harris Date: Sat, 4 Nov 2023 03:21:07 -0700 Subject: [PATCH 18/36] Verilator improvements --- sim/verilate | 10 ++-------- testbench/common/{shadowmem.sv => DCaacheFlushFSM.sv} | 2 +- testbench/wallywrapper.sv | 5 ++--- 3 files changed, 5 insertions(+), 12 deletions(-) rename testbench/common/{shadowmem.sv => DCaacheFlushFSM.sv} (99%) diff --git a/sim/verilate b/sim/verilate index 7aab1ba63..c59494c1d 100755 --- a/sim/verilate +++ b/sim/verilate @@ -8,15 +8,9 @@ basepath=$(dirname $0)/.. #for config in rv32e rv64gc rv32gc rv32imc rv32i rv64i rv64fpquad; do for config in rv64gc; do echo "$config simulating..." - if !($verilator --timescale "1ns/1ns" --timing --cc "$@" --top-module testbench "-I$basepath/config/shared" "-I$basepath/config/$config" $basepath/src/wally/cvw.sv $basepath/testbench/common/*.sv $basepath/testbench/testbench.sv $basepath/src/*/*.sv $basepath/src/*/*/*.sv --relative-includes ); then + if !($verilator --timescale "1ns/1ns" --timing --exe --cc "$@" --top-module testbench "-I$basepath/config/shared" "-I$basepath/config/$config" $basepath/src/cvw.sv $basepath/testbench/testbench.sv $basepath/testbench/common/*.sv $basepath/src/*/*.sv $basepath/src/*/*/*.sv --relative-includes ); then echo "Exiting after $config lint due to errors or warnings" exit 1 fi done -echo "All lints run with no errors or warnings" - -# --lint-only just runs lint rather than trying to compile and simulate -# -I points to the include directory where files such as `include config.vh are found - -# For more exhaustive (and sometimes spurious) warnings, add --Wall to the Verilator command -# Unfortunately, this produces a bunch of UNUSED and UNDRIVEN signal warnings in blocks that are configured to not exist. +echo "Verilation complete" diff --git a/testbench/common/shadowmem.sv b/testbench/common/DCaacheFlushFSM.sv similarity index 99% rename from testbench/common/shadowmem.sv rename to testbench/common/DCaacheFlushFSM.sv index 19884390d..1696a661c 100644 --- a/testbench/common/shadowmem.sv +++ b/testbench/common/DCaacheFlushFSM.sv @@ -1,5 +1,5 @@ /////////////////////////////////////////// -// shadowmem.sv +// DCacheFlushFSM.sv // // Written: David Harris David_Harris@hmc.edu and Ross Thompson ross1728@gmail.com // Modified: 14 June 2023 diff --git a/testbench/wallywrapper.sv b/testbench/wallywrapper.sv index 64b63c54a..990ebfe74 100644 --- a/testbench/wallywrapper.sv +++ b/testbench/wallywrapper.sv @@ -1,11 +1,10 @@ /////////////////////////////////////////// -// testbench.sv +// wallywrapper.sv // // Written: David_Harris@hmc.edu 9 January 2021 // Modified: // -// Purpose: Wally Testbench and helper modules -// Applies test programs from the riscv-arch-test and Imperas suites +// Purpose: Wrapper module to define parameters for Wally Verilator linting // // A component of the Wally configurable RISC-V project. // From b0dbf3a98475768a1865580102d48a52f6d38b2a Mon Sep 17 00:00:00 2001 From: David Harris Date: Sat, 4 Nov 2023 20:36:05 -0700 Subject: [PATCH 19/36] Testbench fixes to add SPI and make string pp static in testbench.fp to solve compiler issue --- testbench/testbench-fp.sv | 4 ++-- testbench/testbench-imperas.sv | 7 ++++--- testbench/testbench-linux-imperas.sv | 15 +++++++-------- testbench/testbench-linux.sv | 13 ++++++------- testbench/testbench-xcelium.sv | 10 ++++++---- 5 files changed, 25 insertions(+), 24 deletions(-) diff --git a/testbench/testbench-fp.sv b/testbench/testbench-fp.sv index 2ddd13072..e5f215e07 100644 --- a/testbench/testbench-fp.sv +++ b/testbench/testbench-fp.sv @@ -644,11 +644,11 @@ module testbenchfp; // Read the first test initial begin //string testname = {`PATH, Tests[TestNum]}; - string p = `PATH; + static string pp = `PATH; string testname; string tt0; tt0 = $psprintf("%s", Tests[TestNum]); - testname = {p, tt0}; + testname = {pp, tt0}; $display("Here you are %s", testname); $display("\n\nRunning %s vectors ", Tests[TestNum]); $readmemh(testname, TestVectors); diff --git a/testbench/testbench-imperas.sv b/testbench/testbench-imperas.sv index 4360d4422..b503372d4 100644 --- a/testbench/testbench-imperas.sv +++ b/testbench/testbench-imperas.sv @@ -72,6 +72,7 @@ module testbench; logic HMASTLOCK; logic HCLK, HRESETn; logic [P.XLEN-1:0] PCW; + logic [31:0] NextInstrE, InstrM; string ProgramAddrMapFile, ProgramLabelMapFile; integer ProgramAddrLabelArray [string] = '{ "begin_signature" : 0, "tohost" : 0 }; @@ -81,7 +82,8 @@ module testbench; logic [31:0] GPIOIN, GPIOOUT, GPIOEN; logic UARTSin, UARTSout; - + logic SPIIn, SPIOut; + logic [3:0] SPICS; logic SDCIntr; logic HREADY; @@ -255,7 +257,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, .SPICS, .SPIOut, .SPIIn); // Track names of instructions instrTrackerTB it(clk, reset, dut.core.ieu.dp.FlushE, @@ -299,7 +301,6 @@ module testbench; end // Duplicate copy of pipeline registers that are optimized out of some configurations - logic [31:0] NextInstrE, InstrM; mux2 #(32) FlushInstrMMux(dut.core.ifu.InstrE, dut.core.ifu.nop, dut.core.ifu.FlushM, NextInstrE); flopenr #(32) InstrMReg(clk, reset, ~dut.core.ifu.StallM, NextInstrE, InstrM); diff --git a/testbench/testbench-linux-imperas.sv b/testbench/testbench-linux-imperas.sv index c5443af42..d38535003 100644 --- a/testbench/testbench-linux-imperas.sv +++ b/testbench/testbench-linux-imperas.sv @@ -282,7 +282,9 @@ module testbench; logic SDCCmdOE; logic [3:0] SDCDatIn; logic SDCIntr; - + logic SPIIn, SPIOut; + logic [3:0] SPICS; + // Hardwire UART, GPIO pins assign GPIOIN = 0; @@ -440,13 +442,10 @@ module testbench; // Wally - wallypipelinedsoc #(P) dut(.clk, .reset, .reset_ext, - .HRDATAEXT, .HREADYEXT, .HREADY, .HSELEXT, .HRESPEXT, .HCLK, - .HRESETn, .HADDR, .HWDATA, .HWRITE, .HWSTRB, .HSIZE, .HBURST, .HPROT, - .HTRANS, .HMASTLOCK, - .TIMECLK('0), .GPIOIN, .GPIOOUT, .GPIOEN, - .UARTSin, .UARTSout, - .SDCIntr); + 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, .SPICS, .SPIOut, .SPIIn); // W-stage hardware not needed by Wally itself parameter nop = 'h13; diff --git a/testbench/testbench-linux.sv b/testbench/testbench-linux.sv index ef165865f..011c4d148 100644 --- a/testbench/testbench-linux.sv +++ b/testbench/testbench-linux.sv @@ -258,6 +258,8 @@ module testbench; logic [31:0] GPIOIN; logic [31:0] GPIOOUT, GPIOEN; logic UARTSin, UARTSout; + logic SPIIn, SPIOut; + logic [3:0] SPICS; // FPGA-specific Stuff logic SDCIntr; @@ -268,13 +270,10 @@ module testbench; assign SDCIntr = 0; // Wally - wallypipelinedsoc #(P) dut(.clk, .reset, .reset_ext, - .HRDATAEXT, .HREADYEXT, .HREADY, .HSELEXT, .HSELEXTSDC, .HRESPEXT, .HCLK, - .HRESETn, .HADDR, .HWDATA, .HWRITE, .HWSTRB, .HSIZE, .HBURST, .HPROT, - .HTRANS, .HMASTLOCK, - .TIMECLK('0), .GPIOIN, .GPIOOUT, .GPIOEN, - .UARTSin, .UARTSout, - .SDCIntr); + 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, .SPICS, .SPIOut, .SPIIn); // W-stage hardware not needed by Wally itself parameter nop = 'h13; diff --git a/testbench/testbench-xcelium.sv b/testbench/testbench-xcelium.sv index f5dd89290..44afbcd3b 100644 --- a/testbench/testbench-xcelium.sv +++ b/testbench/testbench-xcelium.sv @@ -70,6 +70,8 @@ module testbench; logic [3:0] SDCDatIn; tri1 [3:0] SDCDat; tri1 SDCCmd; + logic SPIIn, SPIOut; + logic [3:0] SPICS; logic HREADY; logic HSELEXT; @@ -426,10 +428,10 @@ module testbench; assign SDCDat = '0; end - wallypipelinedsoc #(P) dut(.clk, .reset_ext, .reset, .HRDATAEXT,.HREADYEXT, .HRESPEXT,.HSELEXT, - .HCLK, .HRESETn, .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HSIZE, .HBURST, .HPROT, - .HTRANS, .HMASTLOCK, .HREADY, .TIMECLK(1'b0), .GPIOIN, .GPIOOUT, .GPIOEN, - .UARTSin, .UARTSout, .SDCCmdIn, .SDCCmdOut, .SDCCmdOE, .SDCDatIn, .SDCCLK); + 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, .SPICS, .SPIOut, .SPIIn); // generate clock to sequence tests always begin From 9c4a7866b898f0f0b967f6fa81149143eab7e446 Mon Sep 17 00:00:00 2001 From: David Harris Date: Sun, 5 Nov 2023 06:51:01 -0800 Subject: [PATCH 20/36] Fixed Svnapot_page_mask for imperas.ic --- sim/imperas.ic | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sim/imperas.ic b/sim/imperas.ic index 0afb81c10..528b3a935 100644 --- a/sim/imperas.ic +++ b/sim/imperas.ic @@ -20,7 +20,7 @@ --override cpu/Zicboz=T --override cpu/Svpbmt=T # 64 KiB continuous huge pages supported ---override cpu/Svnapot_page_mask=1<<16 +--override cpu/Svnapot_page_mask=65536 # clarify From bddd2d573e8e78087ba4ae85ff1fff821babf553 Mon Sep 17 00:00:00 2001 From: David Harris Date: Sun, 5 Nov 2023 07:06:53 -0800 Subject: [PATCH 21/36] Shortened path to PCSrcE in logger to avoid problematic hierarchical reference --- testbench/common/loggers.sv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testbench/common/loggers.sv b/testbench/common/loggers.sv index 9dd2a7950..db259da7a 100644 --- a/testbench/common/loggers.sv +++ b/testbench/common/loggers.sv @@ -217,7 +217,7 @@ module loggers import cvw::*; #(parameter cvw_t P, logic PCSrcM; string LogFile; logic resetD, resetEdge; - flopenrc #(1) PCSrcMReg(clk, reset, dut.core.FlushM, ~dut.core.StallM, dut.core.ifu.bpred.bpred.Predictor.DirPredictor.PCSrcE, PCSrcM); + flopenrc #(1) PCSrcMReg(clk, reset, dut.core.FlushM, ~dut.core.StallM, dut.core.ifu.PCSrcE, PCSrcM); flop #(1) ResetDReg(clk, reset, resetD); assign resetEdge = ~reset & resetD; initial begin From 2b183020d586aef31f32713e8639d48a2f3ecb5a Mon Sep 17 00:00:00 2001 From: David Harris Date: Mon, 6 Nov 2023 14:11:01 -0800 Subject: [PATCH 22/36] Fixed bit manpulation on imperas config --- sim/imperas.ic | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sim/imperas.ic b/sim/imperas.ic index 528b3a935..9a9a0fc8f 100644 --- a/sim/imperas.ic +++ b/sim/imperas.ic @@ -11,7 +11,8 @@ --override refRoot/cpu/tvec_align=64 # bit manipulation ---override cpu/add_implicit_Extensions=B +--override cpu/add_Extensions=B +#--override cpu/add_implicit_Extensions=B --override cpu/bitmanip_version=1.0.0 # More extensions From 637cc3b78a6c004a08356c08fc9b4dc6aa3d8fbd Mon Sep 17 00:00:00 2001 From: David Harris Date: Mon, 6 Nov 2023 14:11:42 -0800 Subject: [PATCH 23/36] Reparitioned sign logic in fdivsqrt to match paper --- src/fpu/fdivsqrt/fdivsqrt.sv | 6 +++--- src/fpu/fdivsqrt/fdivsqrtpostproc.sv | 6 ++++-- src/fpu/fdivsqrt/fdivsqrtpreproc.sv | 8 +++----- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/fpu/fdivsqrt/fdivsqrt.sv b/src/fpu/fdivsqrt/fdivsqrt.sv index 9112da9d1..5c5fa0f57 100644 --- a/src/fpu/fdivsqrt/fdivsqrt.sv +++ b/src/fpu/fdivsqrt/fdivsqrt.sv @@ -68,7 +68,7 @@ module fdivsqrt import cvw::*; #(parameter cvw_t P) ( logic BZeroM; // Denominator is zero logic IntDivM; // Integer operation logic [P.DIVBLEN:0] nM, mM; // Shift amounts - logic NegQuotM, ALTBM, AsM, W64M; // Special handling for postprocessor + logic ALTBM, AsM, BsM, W64M; // Special handling for postprocessor logic [P.XLEN-1:0] AM; // Original Numerator for postprocessor logic ISpecialCaseE; // Integer div/remainder special cases @@ -78,7 +78,7 @@ module fdivsqrt import cvw::*; #(parameter cvw_t P) ( // Int-specific .ForwardedSrcAE, .ForwardedSrcBE, .IntDivE, .W64E, .ISpecialCaseE, .BZeroM, .nM, .mM, .AM, - .IntDivM, .W64M, .NegQuotM, .ALTBM, .AsM); + .IntDivM, .W64M, .ALTBM, .AsM, .BsM); fdivsqrtfsm #(P) fdivsqrtfsm( // FSM .clk, .reset, .XInfE, .YInfE, .XZeroE, .YZeroE, .XNaNE, .YNaNE, @@ -96,6 +96,6 @@ module fdivsqrt import cvw::*; #(parameter cvw_t P) ( .SqrtE, .Firstun, .SqrtM, .SpecialCaseM, .QmM, .WZeroE, .DivStickyM, // Int-specific - .nM, .mM, .ALTBM, .AsM, .BZeroM, .NegQuotM, .W64M, .RemOpM(Funct3M[1]), .AM, + .nM, .mM, .ALTBM, .AsM, .BsM, .BZeroM, .W64M, .RemOpM(Funct3M[1]), .AM, .FIntDivResultM); endmodule diff --git a/src/fpu/fdivsqrt/fdivsqrtpostproc.sv b/src/fpu/fdivsqrt/fdivsqrtpostproc.sv index 19856e932..c3c558902 100644 --- a/src/fpu/fdivsqrt/fdivsqrtpostproc.sv +++ b/src/fpu/fdivsqrt/fdivsqrtpostproc.sv @@ -34,9 +34,9 @@ module fdivsqrtpostproc import cvw::*; #(parameter cvw_t P) ( input logic [P.DIVb:0] FirstU, FirstUM, input logic [P.DIVb+1:0] FirstC, input logic SqrtE, - input logic Firstun, SqrtM, SpecialCaseM, NegQuotM, + input logic Firstun, SqrtM, SpecialCaseM, input logic [P.XLEN-1:0] AM, - input logic RemOpM, ALTBM, BZeroM, AsM, W64M, + input logic RemOpM, ALTBM, BZeroM, AsM, BsM, W64M, input logic [P.DIVBLEN:0] nM, mM, output logic [P.DIVb:0] QmM, output logic WZeroE, @@ -49,6 +49,7 @@ module fdivsqrtpostproc import cvw::*; #(parameter cvw_t P) ( logic NegStickyM; logic weq0E, WZeroM; logic [P.XLEN-1:0] IntDivResultM; + logic NegQuotM; // Integer quotient is negative ////////////////////////// // Execute Stage: Detect early termination for an exact result @@ -103,6 +104,7 @@ module fdivsqrtpostproc import cvw::*; #(parameter cvw_t P) ( assign UnsignedQuotM = {3'b000, PreQmM}; // Integer remainder: sticky and sign correction muxes + assign NegQuotM = AsM ^ BsM; // Integer Quotient is negative mux2 #(P.DIVb+4) normremdmux(W, W+D, NegStickyM, NormRemDM); mux2 #(P.DIVb+4) normremsmux(NormRemDM, -NormRemDM, AsM, NormRemM); mux2 #(P.DIVb+4) quotresmux(UnsignedQuotM, -UnsignedQuotM, NegQuotM, NormQuotM); diff --git a/src/fpu/fdivsqrt/fdivsqrtpreproc.sv b/src/fpu/fdivsqrt/fdivsqrtpreproc.sv index 5e14d3122..6c397576a 100644 --- a/src/fpu/fdivsqrt/fdivsqrtpreproc.sv +++ b/src/fpu/fdivsqrt/fdivsqrtpreproc.sv @@ -43,8 +43,8 @@ module fdivsqrtpreproc import cvw::*; #(parameter cvw_t P) ( output logic ISpecialCaseE, output logic [P.DURLEN-1:0] CyclesE, output logic [P.DIVBLEN:0] nM, mM, - output logic NegQuotM, ALTBM, IntDivM, W64M, - output logic AsM, BZeroM, + output logic ALTBM, IntDivM, W64M, + output logic AsM, BsM, BZeroM, output logic [P.XLEN-1:0] AM ); @@ -57,7 +57,6 @@ module fdivsqrtpreproc import cvw::*; #(parameter cvw_t P) ( logic NumerZeroE; // Numerator is zero (X or A) logic AZeroE, BZeroE; // A or B is Zero for integer division logic SignedDivE; // signed division - logic NegQuotE; // Integer quotient is negative logic AsE, BsE; // Signs of integer inputs logic [P.XLEN-1:0] AE; // input A after W64 adjustment logic ALTBE; @@ -84,7 +83,6 @@ module fdivsqrtpreproc import cvw::*; #(parameter cvw_t P) ( assign BZeroE = ~(|BE); assign AsE = AE[P.XLEN-1] & SignedDivE; assign BsE = BE[P.XLEN-1] & SignedDivE; - assign NegQuotE = AsE ^ BsE; // Integer Quotient is negative // Force integer inputs to be postiive mux2 #(P.XLEN) posamux(AE, -AE, AsE, PosA); @@ -192,9 +190,9 @@ module fdivsqrtpreproc import cvw::*; #(parameter cvw_t P) ( // pipeline registers flopen #(1) mdureg(clk, IFDivStartE, IntDivE, IntDivM); flopen #(1) altbreg(clk, IFDivStartE, ALTBE, ALTBM); - flopen #(1) negquotreg(clk, IFDivStartE, NegQuotE, NegQuotM); flopen #(1) bzeroreg(clk, IFDivStartE, BZeroE, BZeroM); flopen #(1) asignreg(clk, IFDivStartE, AsE, AsM); + flopen #(1) bsignreg(clk, IFDivStartE, BsE, BsM); flopen #(P.DIVBLEN+1) nreg(clk, IFDivStartE, nE, nM); flopen #(P.DIVBLEN+1) mreg(clk, IFDivStartE, mE, mM); flopen #(P.XLEN) srcareg(clk, IFDivStartE, AE, AM); From a5837eb62c764460bb58dca3171e713e4bf8d277 Mon Sep 17 00:00:00 2001 From: naichewa Date: Tue, 7 Nov 2023 17:59:46 -0800 Subject: [PATCH 24/36] fifo fixes and edge case testing --- src/uncore/spi_apb.sv | 17 +- .../references/WALLY-spi-01.reference_output | 123 +++++++++-- .../rv32i_m/privilege/src/WALLY-spi-01.S | 206 ++++++++++++++++-- .../references/WALLY-spi-01.reference_output | 81 +++++-- .../rv64i_m/privilege/src/WALLY-spi-01.S | 111 +++++++--- 5 files changed, 444 insertions(+), 94 deletions(-) diff --git a/src/uncore/spi_apb.sv b/src/uncore/spi_apb.sv index a707534cc..126eff6bb 100644 --- a/src/uncore/spi_apb.sv +++ b/src/uncore/spi_apb.sv @@ -26,15 +26,16 @@ //////////////////////////////////////////////////////////////////////////////////////////////// // Current limitations: Flash read sequencer mode not implemented, dual and quad modes untestable with current test plan. -// Hardware interlock change to busy signal + // write tests for fifo full and empty watermark edge cases +// test case for two's complement rollover on fifo watermark calculation + watermark calc redesign +// rempty triggers when fifo full, txmark = 7 doesnt work // 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 @@ -153,8 +154,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( // 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 = TransmitInactive; // tie PREADY to transmission for hardware interlock // account for subword read/write circuitry // -- Note SPI registers are 32 bits no matter what; access them with LW SW. @@ -249,7 +249,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( ReceiveShiftFSM ReceiveShiftFSM_1 (PCLK, PRESETn, SCLKenable, ReceivePenultimateFrameBoolean, SampleEdge, SckMode[0], ReceiveShiftFull); //calculate tx/rx fifo write and recieve increment signals - assign TransmitFIFOWriteIncrement = (Memwrite & (Entry == 8'h48) & ~TransmitFIFOWriteFull); + assign TransmitFIFOWriteIncrement = (Memwrite & (Entry == 8'h48) & ~TransmitFIFOWriteFull & TransmitInactive); always_ff @(posedge PCLK, negedge PRESETn) if (~PRESETn) TransmitFIFOWriteIncrementDelay <= 0; @@ -358,7 +358,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( assign PWChipSelect = PWDATA[3:0]; always_ff @(posedge PCLK, negedge PRESETn) if (~PRESETn) HoldModeDeassert <= 0; - else if (~Inactive & ((ChipSelectMode[1:0] == 2'b10) & (Entry == (8'h18 | 8'h10) | ((Entry == 8'h14) & (PWChipSelect[ChipSelectID] != ChipSelectDef[ChipSelectID])))) & Memwrite) HoldModeDeassert <= 1; + else if (~Inactive & Memwrite & ((ChipSelectMode[1:0] == 2'b10) & (Entry == (8'h18 | 8'h10) | ((Entry == 8'h14) & (PWChipSelect[ChipSelectID] != ChipSelectDef[ChipSelectID]))))) HoldModeDeassert <= 1; // Signal tracks which edge of sck to shift data always_comb @@ -455,10 +455,9 @@ module SynchFIFO #(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 = ((raddr - waddr) < rwatermarklevel); - + assign rwatermark = ((waddr - raddr) < rwatermarklevel) & ~wfull; assign waddr = wptr[M-1:0]; - assign wwatermark = ((waddr - raddr) > wwatermarklevel); + assign wwatermark = ((waddr - raddr) > wwatermarklevel) | wfull; assign wptrnext = wptr + {3'b0, (winc & ~wfull)}; assign wfull_val = ({~wptrnext[M], wptrnext[M-1:0]} == rptr); endmodule 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 246e5d46a..b1b76274e 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 @@ -13,7 +13,7 @@ 00000001 # delay 1 00080000 # fmt - + 00000000 # tx_data 00000000 # tx_mark @@ -23,6 +23,62 @@ 00000000 # ie reset 00000000 # ip reset + +00000000 # fifo watermark and edge case tests + +00000001 + +00000003 + +00000003 + +00000074 + +00000063 + +00000052 + +00000041 + +000000A1 + +00000003 + +000000B2 + +00000001 + +000000C3 + +000000D4 + +00000003 + +000000A4 + +00000001 + +000000B4 + +000000A5 + +000000B5 + +000000C5 + +000000D5 + +000000A7 + +000000B7 + +000000C7 + +00000002 + +000000D7 + +00000000 00000011 #basic read write @@ -116,6 +172,8 @@ 000000AB +000000CE hold mode deassert + 000000F0 #fmt register 00000000 @@ -146,12 +204,52 @@ 0000001F +00000062 # hardware interlock + +00000026 + +000000D2 + +0000002D + +00000048 + +00000037 + +00000026 + +00000015 + +00000084 + +00000073 + +00000062 + +00000051 + +00000046 + +00000035 + +00000024 + +00000013 + +00000064 + +00000053 + +00000042 + +00000031 + 00000001 #watermark interrupts 00000000 #read mip 00000000 #read tx ip - + 00000022 #clear 1 frame from rx fifo 00000000 # read recieve ip @@ -170,24 +268,21 @@ 00000001 #read tx ip -00000800 #read mip 11 +00000800 #read mip -00000000 #read tx wm 10 +00000022 #clear frame -00000000 #read mip 91 9 +00000000 #read rx ip -00000022 #clear frame 8 +00000000 #read mip 94 -00000000 #read rx ip 7 +00000002 #read rx ip -00000000 #read mip 94 6 +00000800 #read mip -00000002 #read rx ip 5 +00000033 #clear frame -00000800 #read mip 4 +00000000 #read rx wm -00000033 #clear frame 3 +00000000 #read mip 99 -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-spi-01.S b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-spi-01.S index ad2501909..75643063d 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 @@ -115,6 +115,68 @@ test_cases: .4byte ie, 0x00000000, read32_test # ie reset to 0x0 .4byte ip, 0x00000000, read32_test # ip reset to 0x0 +#test watermark interrupts at beginning where fifo read/write pointers are known b/c reset +# txwmp raised when # of entries in txfifo < txmark, rxwm raised when # of entries in rxfifo > rxmark + +.4byte ip, 0x00000000, read32_test # txfifo entries not < 0, rxfifo entries not > 0; +.4byte tx_mark, 0x00000004, write32_test # set tx_mark to 4 +.4byte rx_mark, 0x00000003, write32_test # set rx_mark to 3 +.4byte ip, 0x00000001, read32_test # tx entries < 4, rx entries ! > 3 +.4byte tx_data, 0x41526374, spi_burst_send +.4byte 0x0, 0x00000003, spi_data_wait +.4byte ip, 0x00000003, read32_test # tx entries < 4, rx entries > 3, visual inspection should see tx TransmitFIFOReadIncrement + +# txfifo wptr now at 0011, rxfifo wptr at 0000 + +.4byte rx_mark, 0x00000007, write32_test # set rx_mark to 7 +.4byte tx_data, 0xD4C3B2A1, spi_burst_send +.4byte 0x0, 0x00000007, spi_data_wait # rxfifo full, txfifo wptr at 1000, rxfifo wptr at 0000 +.4byte ip, 0x00000003, read32_test +.4byte rx_data, 0x00000074, read32_test +.4byte rx_data, 0x00000063, read32_test # clear 2 entries, txfifo wptr at 1000, rxfifo wptr at 0010 + + +.4byte tx_data, 0x000000A4, write32_test +.4byte tx_data, 0x000000B4, write32_test # tx 1010, rx 0010 +.4byte 0x0, 0x00000007, spi_data_wait # 8 tx 1010, rx 0010 +.4byte rx_mark, 0x00000004, write32_test +.4byte rx_data, 0x00000052, read32_test # 7 rx 0011 +.4byte rx_data, 0x00000041, read32_test # 6 rx 0100 +.4byte rx_data, 0x000000A1, read32_test # 5 rx 0101 +.4byte ip, 0x00000003, read32_test # 5 things in rx fifo +.4byte rx_data, 0x000000B2, read32_test # 4 tx 1010, rx 0110 +.4byte ip, 0x00000001, read32_test # 4 entries in rxfifo, not strictly greater than 4 + +.4byte rx_mark, 0x00000007, write32_test +.4byte tx_data, 0xD5C5B5A5, spi_burst_send # 8 tx1110, rx 0110 +.4byte 0x0, 0x00000007, spi_data_wait + +.4byte rx_mark, 0x00000005, write32_test +.4byte rx_data, 0x000000C3, read32_test # tx 1110, rx 0111 +.4byte rx_data, 0x000000D4, read32_test # tx 1110, rx 1000 +.4byte ip, 0x00000003, read32_test # 6 entries +.4byte rx_data, 0x000000A4, read32_test # tx 1110, rx 1001 +.4byte ip, 0x00000001, read32_test # 5 entries +.4byte rx_data, 0x000000B4, read32_test # tx 1110, rx 1010 +.4byte rx_data, 0x000000A5, read32_test # tx 1110, rx 1011 + +.4byte rx_mark, 0x00000006, write32_test +.4byte tx_data, 0xD7C7B7A7, spi_burst_send +.4byte 0x0, 0x00000006, spi_data_wait # tx 0010, rx 1011 +.4byte tx_mark, 0x00000000, write32_test +.4byte rx_mark, 0x00000000, write32_test +.4byte rx_data, 0x000000B5, read32_test # tx 0010, rx 1100 +.4byte rx_data, 0x000000C5, read32_test # tx 0010, rx 1101 +.4byte rx_data, 0x000000D5, read32_test # tx 0010, rx 1110 +.4byte rx_data, 0x000000A7, read32_test # tx 0010, rx 1111 +.4byte rx_data, 0x000000B7, read32_test # tx 0010, rx 0000 +.4byte rx_data, 0x000000C7, read32_test # tx 0010, rx 0001 +.4byte ip, 0x00000002, read32_test +.4byte rx_data, 0x000000D7, read32_test # tx 0010, rx 1010 +.4byte ip, 0x00000000, read32_test +.4byte tx_mark, 0x00000000, write32_test +.4byte rx_mark, 0x00000000, write32_test # reset watermark registers + # =========== Basic read-write =========== .4byte tx_data, 0x000000011, write32_test # place 8'h11 into tx_data @@ -226,7 +288,7 @@ test_cases: # Test arbitrary sck-cs delay (sck phase 1) -.4byte delay0, 0x00000501, write32_test # set cs-sck delay to A5 cycles +.4byte delay0, 0x00050001, 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 @@ -246,6 +308,7 @@ test_cases: .4byte delay0, 0x00010001, write32_test # reset delay0 register .4byte delay1, 0x00000005, write32_test # set inter_cs delay to 5 +.4byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock .4byte tx_data, 0x44332211, spi_burst_send .4byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end .4byte rx_data, 0x00000011, read32_test @@ -256,6 +319,7 @@ test_cases: #test long inter_cs delay .4byte delay1, 0x000000A5, write32_test +.4byte rx_mark, 0x0000000, write32_test # preset rx watermark b/c of hardware interlock .4byte tx_data, 0x0000007B, write32_test .4byte 0x0, 0x00000000, spi_data_wait .4byte rx_data, 0x0000007B, read32_test @@ -264,6 +328,7 @@ test_cases: # Test inter_cs delay set to 0 .4byte delay1, 0x00000000, write32_test # set inter_cs delay to 5 +.4byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock .4byte tx_data, 0x54433221, spi_burst_send .4byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end .4byte rx_data, 0x00000021, read32_test @@ -306,6 +371,7 @@ test_cases: # test long inter_xfr delay .4byte delay1, 0x00A50001, write32_test +.4byte rx_mark, 0x0000000, write32_test # preset rx watermark b/c of hardware interlock .4byte tx_data, 0x00000048, write32_test .4byte 0x0, 0x00000000, spi_data_wait .4byte rx_data, 0x00000048, read32_test @@ -314,6 +380,7 @@ test_cases: .4byte delay1, 0x00000001, write32_test # set inter_xfr delay to 0 .4byte delay0, 0x00010005, write32_test # set cs-sck delay to 5 (should have no effect because cs is never inactive) +.4byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock .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 +390,7 @@ test_cases: # Test sck-cs delay cs_mode = HOLD -.4byte delay0, 0x00050001, write32_test # set sck-cs delay to 5 (should have no effect because cs is never inactive) +.4byte 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 @@ -331,6 +398,18 @@ test_cases: .4byte rx_data, 0x000000BC, read32_test .4byte rx_data, 0x000000AB, read32_test +# Test hold mode deassert conditions + +.4byte delay1, 0x00000001, write32_test # reset delay1 register +.4byte delay0, 0x00010001, write32_test # reset delay0 register +.4byte cs_mode, 0x00000002, write32_test # set cs_mode to hold +.4byte tx_data, 0x000000CE, write32_test # place data into tx_data +.4byte cs_id, 0x00000001, write32_test #change selected cs pin. should deassert cs[0] in hold mode +.4byte cs_def, 0x00001101, write32_test # change selected cs pins def value. should deassert cs[1] +.4byte cs_def, 0x00001111, write32_test # reset cs_def +.4byte cs_mode, 0x00000000, write32_test # change cs_mode to auto, should deassert cs[1], have now gone through all deassertion conditions +.4byte rx_data, 0x000000CE, read32_test # clear rx_fifo + # =========== Test frame format (fmt) register =========== # Test frame length of 4 @@ -340,6 +419,7 @@ test_cases: .4byte sck_mode, 0x00000000, write32_test #reset sckmode register .4byte cs_mode, 0x00000000, write32_test # set cs_mode to AUTO .4byte fmt, 0x00040000, write32_test # set frame length to 4 +.4byte rx_mark, 0x0000000, write32_test # preset rx watermark b/c of hardware interlock .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 @@ -353,6 +433,7 @@ test_cases: # test frame length 1 burst .4byte fmt, 0x00010000, write32_test +.4byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock .4byte tx_data, 0x80008000, spi_burst_send .4byte 0x0, 0x00000003, spi_data_wait .4byte rx_data, 0x00000000, read32_test @@ -364,12 +445,14 @@ test_cases: # Test big endian with frame length = 5 .4byte fmt, 0x00050000, write32_test # set frame length to 5, big endian +.4byte rx_mark, 0x0000000, write32_test # preset rx watermark b/c of hardware interlock .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 rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock .4byte tx_data, 0x03774FFF, spi_burst_send .4byte 0x0, 0x00000003, spi_data_wait .4byte rx_data, 0x000000F8, read32_test @@ -383,12 +466,14 @@ test_cases: # Test little endian with frame length = 5 .4byte fmt, 0x00050004, write32_test # set frame length to 5, little-endian +.4byte rx_mark, 0x0000000, write32_test # preset rx watermark b/c of hardware interlock .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 rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock .4byte tx_data, 0xFF4F7703, spi_burst_send .4byte 0x0, 0x00000003, spi_data_wait .4byte rx_data, 0x00000003, read32_test #03 @@ -446,20 +531,116 @@ test_cases: #.4byte 0x0, 0x00000000, spi_data_wait # wait for transmission to end #.4byte rx_data, 0x000000F0, read32_test # read rx_data +#=========== Test Hardware Interlock ================ + +# interlock in base case + +.4byte fmt, 0x00080000, write32_test # reset fmt register +.4byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock +.4byte tx_data, 0x00000062, write32_test # initiate transmission +.4byte sck_mode, 0x00000002, write32_test # flip polarity during transmission +.4byte tx_data, 0x00000026, write32_test # transmit second frame w/ control register updated +.4byte 0x0, 0x00000001, spi_data_wait +.4byte rx_data, 0x00000062, read32_test +.4byte rx_data, 0x00000026, read32_test # clear rx fifo +.4byte sck_mode, 0x00000000, write32_test # reset polarity + +# interlock in case where cs_mode is auto, but there is minimal intercs delay + +.4byte delay0, 0x00000001, write32_test # set sck-cs delay to 0, with sck.pha 0 there is 0 delay +.4byte tx_data, 0x000000D2, write32_test # initiate transmission +.4byte sck_mode, 0x00000002, write32_test # flip sck polarity +.4byte tx_data, 0x0000002D, write32_test # transmit second frame +.4byte 0x0, 0x00000001, spi_data_wait +.4byte rx_data, 0x000000D2, read32_test +.4byte rx_data, 0x0000002D, read32_test # clear rx fifo +.4byte sck_mode, 0x00000000, write32_test # reset polarity + +# interlock in case where cs_mode = hold, 0 intercs delay +.4byte delay0, 0x00010001, write32_test # reset delay0 +.4byte sck_mode, 0x00000000, write32_test # reset polarity +.4byte cs_mode, 0x00000002, write32_test # set cs_mode to hold +.4byte tx_data, 0x15263748, spi_burst_send # place 4 frames into tx fifo +.4byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame) +.4byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end +.4byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock +.4byte sck_mode, 0x00000000, write32_test # flip polarity again +.4byte 0x0, 0x00000003, spi_data_wait # wait for final frame +.4byte rx_data, 0x00000048, read32_test +.4byte rx_data, 0x00000037, read32_test +.4byte rx_data, 0x00000026, read32_test +.4byte rx_data, 0x00000015, read32_test #clear rx fifo + +# interlock in case where cs_mode = hold, intercs delay + +.4byte sck_mode, 0x00000000, write32_test # reset polarity +.4byte delay1, 0x00010001, write32_test # set intercs delay to 1 +.4byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock +.4byte tx_data, 0x51627384, spi_burst_send # place 4 frames into tx fifo +.4byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame) +.4byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end +.4byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock +.4byte sck_mode, 0x00000000, write32_test # flip polarity again +.4byte 0x0, 0x00000003, spi_data_wait # wait for final frame +.4byte rx_data, 0x00000084, read32_test +.4byte rx_data, 0x00000073, read32_test +.4byte rx_data, 0x00000062, read32_test +.4byte rx_data, 0x00000051, read32_test #clear rx fifo + +# repeat previous set of tests with cs_mode = off + +.4byte cs_mode, 0x00000003, write32_test # set cs_mode to hold +.4byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock +.4byte tx_data, 0x13243546, spi_burst_send # place 4 frames into tx fifo +.4byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame) +.4byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end +.4byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock +.4byte sck_mode, 0x00000000, write32_test # flip polarity again +.4byte 0x0, 0x00000003, spi_data_wait # wait for final frame +.4byte rx_data, 0x00000046, read32_test +.4byte rx_data, 0x00000035, read32_test +.4byte rx_data, 0x00000024, read32_test +.4byte rx_data, 0x00000013, read32_test #clear rx fifo + +# interlock in case where cs_mode = hold, intercs delay + +.4byte sck_mode, 0x00000000, write32_test # reset polarity +.4byte delay1, 0x00000000, write32_test # set intercs delay to 0 +.4byte rx_mark, 0x0000001, write32_test # preset rx watermark b/c of hardware interlock +.4byte tx_data, 0x31425364, spi_burst_send # place 4 frames into tx fifo +.4byte sck_mode, 0x00000002, write32_test # flip polarity (should change 2 second frame) +.4byte 0x0, 0x00000001, spi_data_wait # wait for second transmission to end +.4byte rx_mark, 0x0000003, write32_test # preset rx watermark b/c of hardware interlock +.4byte sck_mode, 0x00000000, write32_test # flip polarity again +.4byte 0x0, 0x00000003, spi_data_wait # wait for final frame +.4byte rx_data, 0x00000064, read32_test +.4byte rx_data, 0x00000053, read32_test +.4byte rx_data, 0x00000042, read32_test +.4byte rx_data, 0x00000031, read32_test #clear rx fifo + + + + + + + + + + # =========== Test watermark interrupts =========== # Test transmit watermark interrupt (triggers when entries in tx FIFO < tx watermark) without external enables -# rx fifo > rx mark SETUP_PLIC -.4byte fmt, 0x00080000, write32_test # reset fmt register -.4byte tx_mark, 0x00000004, write32_test # set transmit watermark to 4 +.4byte delay1, 0x0000001, write32_test # reset delay1 register +.4byte cs_mode, 0x00000000, write32_test # reset cs_mode +.4byte tx_mark, 0x00000001, write32_test # set transmit watermark to 1 (any entry turns mark off) #.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 ip, 0x00000000, read32_test # tx watermark interupt should be off 125 .4byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end # test recieve watermark interrupt (triggers when entries in rx FIFO > rx watermark) @@ -478,23 +659,18 @@ SETUP_PLIC .4byte rx_data, 0x00000055, read32_test # clear rx fifo -.4byte tx_mark, 0x00000004, write32_test # set transmit watermark to 4 +.4byte tx_mark, 0x00000001, write32_test # set transmit watermark to 0 .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 tx_data, 0x55443322, spi_burst_send # place 4 entries in transmit fifo .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 0x0, 0x00000000, claim_m_plic_interrupts .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 @@ -508,4 +684,6 @@ SETUP_PLIC .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/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 3e947f38d..83376aab1 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 @@ -24,6 +24,62 @@ 00000000 00000000 # ip reset 00000000 +00000000 # fifo watermark and edge case tests +00000000 +00000001 +00000000 +00000003 +00000000 +00000003 +00000000 +00000074 +00000000 +00000063 +00000000 +00000052 +00000000 +00000041 +00000000 +000000A1 +00000000 +00000003 +00000000 +000000B2 +00000000 +00000001 +00000000 +000000C3 +00000000 +000000D4 +00000000 +00000003 +00000000 +000000A4 +00000000 +00000001 +00000000 +000000B4 +00000000 +000000A5 +00000000 +000000B5 +00000000 +000000C5 +00000000 +000000D5 +00000000 +000000A7 +00000000 +000000B7 +00000000 +000000C7 +00000000 +00000002 +00000000 +000000D7 +00000000 +00000000 +00000000 00000011 #basic read write 00000000 000000FF @@ -116,25 +172,8 @@ 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 +000000CE hold mode deassert +00000000 000000F0 #fmt register 00000000 00000000 @@ -231,10 +270,6 @@ 00000000 00000800 #read mip 00000000 -00000000 #read tx wm -00000000 -00000000 #read mip 91 -00000000 00000022 #clear frame 00000000 00000000 #read rx ip 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 4960e85dc..3f2690162 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 @@ -85,6 +85,70 @@ test_cases: .8byte ie, 0x00000000, read32_test # ie reset to 0x0 .8byte ip, 0x00000000, read32_test # ip reset to 0x0 +# =========== watermark interrupts =============== + +#test watermark interrupts at beginning where fifo read/write pointers are known b/c reset +# txwmp raised when # of entries in txfifo < txmark, rxwm raised when # of entries in rxfifo > rxmark + +.8byte ip, 0x00000000, read32_test # txfifo entries not < 0, rxfifo entries not > 0; +.8byte tx_mark, 0x00000004, write32_test # set tx_mark to 4 +.8byte rx_mark, 0x00000003, write32_test # set rx_mark to 3 +.8byte ip, 0x00000001, read32_test # tx entries < 4, rx entries ! > 3 +.8byte tx_data, 0x41526374, spi_burst_send +.8byte 0x0, 0x00000003, spi_data_wait +.8byte ip, 0x00000003, read32_test # tx entries < 4, rx entries > 3, visual inspection should see tx TransmitFIFOReadIncrement + +# txfifo wptr now at 0011, rxfifo wptr at 0000 + +.8byte rx_mark, 0x00000007, write32_test # set rx_mark to 7 +.8byte tx_data, 0xD4C3B2A1, spi_burst_send +.8byte 0x0, 0x00000007, spi_data_wait # rxfifo full, txfifo wptr at 1000, rxfifo wptr at 0000 +.8byte ip, 0x00000003, read32_test +.8byte rx_data, 0x00000074, read32_test +.8byte rx_data, 0x00000063, read32_test # clear 2 entries, txfifo wptr at 1000, rxfifo wptr at 0010 + + +.8byte tx_data, 0x000000A4, write32_test +.8byte tx_data, 0x000000B4, write32_test # tx 1010, rx 0010 +.8byte 0x0, 0x00000007, spi_data_wait # 8 tx 1010, rx 0010 +.8byte rx_mark, 0x00000004, write32_test +.8byte rx_data, 0x00000052, read32_test # 7 rx 0011 +.8byte rx_data, 0x00000041, read32_test # 6 rx 0100 +.8byte rx_data, 0x000000A1, read32_test # 5 rx 0101 +.8byte ip, 0x00000003, read32_test # 5 things in rx fifo +.8byte rx_data, 0x000000B2, read32_test # 4 tx 1010, rx 0110 +.8byte ip, 0x00000001, read32_test # 4 entries in rxfifo, not strictly greater than 4 + +.8byte rx_mark, 0x00000007, write32_test +.8byte tx_data, 0xD5C5B5A5, spi_burst_send # 8 tx1110, rx 0110 +.8byte 0x0, 0x00000007, spi_data_wait + +.8byte rx_mark, 0x00000005, write32_test +.8byte rx_data, 0x000000C3, read32_test # tx 1110, rx 0111 +.8byte rx_data, 0x000000D4, read32_test # tx 1110, rx 1000 +.8byte ip, 0x00000003, read32_test # 6 entries +.8byte rx_data, 0x000000A4, read32_test # tx 1110, rx 1001 +.8byte ip, 0x00000001, read32_test # 5 entries +.8byte rx_data, 0x000000B4, read32_test # tx 1110, rx 1010 +.8byte rx_data, 0x000000A5, read32_test # tx 1110, rx 1011 + +.8byte rx_mark, 0x00000006, write32_test +.8byte tx_data, 0xD7C7B7A7, spi_burst_send +.8byte 0x0, 0x00000006, spi_data_wait # tx 0010, rx 1011 +.8byte tx_mark, 0x00000000, write32_test +.8byte rx_mark, 0x00000000, write32_test +.8byte rx_data, 0x000000B5, read32_test # tx 0010, rx 1100 +.8byte rx_data, 0x000000C5, read32_test # tx 0010, rx 1101 +.8byte rx_data, 0x000000D5, read32_test # tx 0010, rx 1110 +.8byte rx_data, 0x000000A7, read32_test # tx 0010, rx 1111 +.8byte rx_data, 0x000000B7, read32_test # tx 0010, rx 0000 +.8byte rx_data, 0x000000C7, read32_test # tx 0010, rx 0001 +.8byte ip, 0x00000002, read32_test +.8byte rx_data, 0x000000D7, read32_test # tx 0010, rx 1010 +.8byte ip, 0x00000000, read32_test +.8byte tx_mark, 0x00000000, write32_test +.8byte rx_mark, 0x00000000, write32_test # reset watermark registers + # =========== Basic read-write =========== .8byte tx_data, 0x000000011, write32_test # place 8'h11 into tx_data @@ -308,32 +372,15 @@ 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 - -# 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) +.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 frame format (fmt) register =========== @@ -560,12 +607,12 @@ SETUP_PLIC .8byte delay1, 0x0000001, write32_test # reset delay1 register .8byte cs_mode, 0x00000000, write32_test # reset cs_mode -.8byte tx_mark, 0x00000004, write32_test # set transmit watermark to 4 +.8byte tx_mark, 0x00000001, write32_test # set transmit watermark to 1 (any entry turns mark off) #.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 ip, 0x00000000, read32_test # tx watermark interupt should be off 125 .8byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end # test recieve watermark interrupt (triggers when entries in rx FIFO > rx watermark) @@ -584,16 +631,12 @@ SETUP_PLIC .8byte rx_data, 0x00000055, read32_test # clear rx fifo -.8byte tx_mark, 0x00000004, write32_test # set transmit watermark to 4 +.8byte tx_mark, 0x00000001, write32_test # set transmit watermark to 0 .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 tx_data, 0x55443322, spi_burst_send # place 4 entries in transmit fifo .8byte 0x0, 0x00000003, spi_data_wait # wait for transmission to end # test recieve watermark interrupt (triggers when entries in rx FIFO > rx watermark) From f83188a4a4d88547373a60e7d13385e72644c0f8 Mon Sep 17 00:00:00 2001 From: "James E. Stine" Date: Wed, 8 Nov 2023 13:59:04 -0600 Subject: [PATCH 25/36] add typo on setting WALLY for C-shell that caused some incompatability issues --- setup.csh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.csh b/setup.csh index 58b0918dd..0508c36d0 100755 --- a/setup.csh +++ b/setup.csh @@ -6,7 +6,7 @@ echo "Executing Wally setup.csh" # Path to Wally repository -set WALLY = $PWD +setenv WALLY $PWD echo '$WALLY set to ' ${WALLY} # Extend alias which makes extending PATH much easier. From 41f4c634b0b1601c0485c9eb5e28b9250c60cb3e Mon Sep 17 00:00:00 2001 From: "James E. Stine" Date: Wed, 8 Nov 2023 14:00:36 -0600 Subject: [PATCH 26/36] Update to ppaSynth and ppaAnalyze - still have to push in mod for ppaAnalyze to plot more refined plots as well as some other plots - I have a fix working - just need to push in which will do later today --- synthDC/ppa/ppaAnalyze.py | 25 +++++++++++++++---------- synthDC/ppa/ppaSynth.py | 11 +++++++---- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/synthDC/ppa/ppaAnalyze.py b/synthDC/ppa/ppaAnalyze.py index 03758cdf6..459a8520d 100755 --- a/synthDC/ppa/ppaAnalyze.py +++ b/synthDC/ppa/ppaAnalyze.py @@ -1,5 +1,9 @@ #!/usr/bin/python3 +# +# Python regression test for DC # Madeleine Masser-Frye mmasserfrye@hmc.edu 5/22 +# James Stine james.stine@okstate.edu 15 October 2023 +# import scipy.optimize as opt import subprocess @@ -565,6 +569,7 @@ def makeLineLegend(): fullLeg += [lines.Line2D([0], [0], color='black', label='smallest', linestyle='--')] fullLeg += [lines.Line2D([0], [0], color='blue', label='tsmc28', marker='^')] fullLeg += [lines.Line2D([0], [0], color='green', label='sky90', marker='o')] + fullLeg += [lines.Line2D([0], [0], color='green', label='sky130', marker='+')] fullLeg += [lines.Line2D([0], [0], color='red', label='combined', marker='_')] fig.legend(handles=fullLeg, ncol=5, handlelength=1.4, loc='center') saveStr = './plots/legend.png' @@ -689,7 +694,7 @@ def makePlotDirectory(): os.makedirs(new_directory) os.chdir(new_directory) if 'freq' in folder: - for tech in ['sky90', 'tsmc28']: + for tech in ['sky90', 'sky130', 'tsmc28']: for mod in modules: tech_directory = os.path.join(new_directory, tech) mod_directory = os.path.join(tech_directory, mod) @@ -702,15 +707,14 @@ def makePlotDirectory(): if __name__ == '__main__': ############################## # set up stuff, global variables - widths = [8, 16, 32, 64, 128] - modules = ['priorityencoder', 'add', 'csa', 'shiftleft', 'comparator', 'flop', 'mux2', 'mux4', 'mux8', 'mult'] #, 'mux2d', 'mux4d', 'mux8d'] + widths = [8, 16, 32, 64, 128] + modules = ['priorityencoder', 'add', 'csa', 'shiftleft', 'comparator', 'flop', 'mux2', 'mux4', 'mux8', 'mult'] normAddWidth = 32 # divisor to use with N since normalizing to add_32 - fitDict = {'add': ['cg', 'l', 'l'], 'mult': ['cg', 's', 's'], 'comparator': ['cg', 'l', 'l'], 'csa': ['c', 'l', 'l'], 'shiftleft': ['cg', 'l', 'ln'], 'flop': ['c', 'l', 'l'], 'priorityencoder': ['cg', 'l', 'l']} - fitDict.update(dict.fromkeys(['mux2', 'mux4', 'mux8'], ['cg', 'l', 'l'])) + fitDict = {'add': ['cg', 'l', 'l'], 'mult': ['cg', 's', 's'], 'comparator': ['cg', 'l', 'l'], 'csa': ['c', 'l', 'l'], 'shiftleft': ['cg', 'l', 'ln'], 'flop': ['c', 'l', 'l'], 'priorityencoder': ['cg', 'l', 'l']} fitDict.update(dict.fromkeys(['mux2', 'mux4', 'mux8'], ['cg', 'l', 'l'])) TechSpec = namedtuple("TechSpec", "tech color shape delay area lpower denergy") - techSpecs = [['sky90', 'green', 'o', 43.2e-3, 1440.600027, 714.057, 0.658022690438], ['tsmc28', 'blue', '^', 12.2e-3, 209.286002, 1060.0, .08153281695882594]] + techSpecs = [['sky90', 'green', 'o', 43.2e-3, 1440.600027, 714.057, 0.658022690438], ['sky130', 'red', 'o', 43.2e-3, 1440.600027, 714.057, 0.658022690438], ['tsmc28', 'blue', '^', 12.2e-3, 209.286002, 1060.0, .08153281695882594]] techSpecs = [TechSpec(*t) for t in techSpecs] combined = TechSpec('combined fit', 'red', '_', 0, 0, 0, 0) ############################## @@ -731,7 +735,8 @@ if __name__ == '__main__': for mod in modules: for w in widths: freqPlot('sky90', mod, w) - freqPlot('tsmc28', mod, w) - plotPPA(mod, norm=False) - plotPPA(mod, aleOpt=True) - plt.close('all') \ No newline at end of file + #freqPlot('sky130', mod, w) + #freqPlot('tsmc28', mod, w) + #plotPPA(mod, norm=False) + #plotPPA(mod, aleOpt=True) + plt.close('all') diff --git a/synthDC/ppa/ppaSynth.py b/synthDC/ppa/ppaSynth.py index cbfd52538..6b45e2c4c 100755 --- a/synthDC/ppa/ppaSynth.py +++ b/synthDC/ppa/ppaSynth.py @@ -1,6 +1,9 @@ #!/usr/bin/python3 -# Madeleine Masser-Frye mmasserfrye@hmc.edu 6/22 - +# +# Python analysis for regression test run by ppaSynth.py +# Madeleine Masser-Frye mmasserfrye@hmc.edu 5/22 +# James Stine james.stine@okstate.edu 15 October 2023 +# import subprocess import re from multiprocessing import Pool @@ -56,7 +59,7 @@ if __name__ == '__main__': ##### Run specific syntheses widths = [8, 16, 32, 64, 128] modules = ['mult', 'add', 'shiftleft', 'flop', 'comparator', 'priorityencoder', 'add', 'csa', 'mux2', 'mux4', 'mux8'] - techs = ['sky90', 'tsmc28'] + techs = ['sky90', 'sky130', 'tsmc28', 'tsmc28psyn'] freqs = [5000] synthsToRun = allCombos(widths, modules, techs, freqs) @@ -70,4 +73,4 @@ if __name__ == '__main__': synthsToRun = filterRedundant(synthsToRun) pool = Pool(processes=25) - pool.starmap(print, synthsToRun) \ No newline at end of file + pool.starmap(print, synthsToRun) From d67badfc60d84d8e7caa6850ce243b7e1445d992 Mon Sep 17 00:00:00 2001 From: naichewa Date: Wed, 8 Nov 2023 15:20:51 -0800 Subject: [PATCH 27/36] fix hardware interlock, hold mode deassert --- src/uncore/spi_apb.sv | 19 +++------- .../rv32i_m/privilege/src/WALLY-spi-01.S | 35 ++----------------- .../rv64i_m/privilege/src/WALLY-spi-01.S | 5 +-- 3 files changed, 10 insertions(+), 49 deletions(-) diff --git a/src/uncore/spi_apb.sv b/src/uncore/spi_apb.sv index 126eff6bb..b51516368 100644 --- a/src/uncore/spi_apb.sv +++ b/src/uncore/spi_apb.sv @@ -27,16 +27,14 @@ // Current limitations: Flash read sequencer mode not implemented, dual and quad modes untestable with current test plan. -// write tests for fifo full and empty watermark edge cases -// test case for two's complement rollover on fifo watermark calculation + watermark calc redesign -// rempty triggers when fifo full, txmark = 7 doesnt work // 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 -/* 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, @@ -184,7 +182,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( //of entries in tx/rx fifo is strictly more/less than tx/rxmark /* verilator lint_off CASEINCOMPLETE */ - if (Memwrite) + if (Memwrite & TransmitInactive) case(Entry) //flop to sample inputs 8'h00: SckDiv <= Din[11:0]; 8'h04: SckMode <= Din[1:0]; @@ -308,7 +306,6 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( 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; @@ -334,8 +331,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( FrameCount <= 5'b0; InterCSCount <= 9'b10; InterXFRCount <= InterXFRCount + 9'b1; - if (HoldModeDeassert) state <= CS_INACTIVE; - else if (InterXFRCompare & ~TransmitFIFOReadEmptyDelay) state <= ACTIVE_0; + if (InterXFRCompare & ~TransmitFIFOReadEmptyDelay) state <= ACTIVE_0; else if (~|ChipSelectMode[1:0]) state <= CS_INACTIVE; end endcase @@ -353,13 +349,6 @@ 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 - assign PWChipSelect = PWDATA[3:0]; - always_ff @(posedge PCLK, negedge PRESETn) - if (~PRESETn) HoldModeDeassert <= 0; - else if (~Inactive & Memwrite & ((ChipSelectMode[1:0] == 2'b10) & (Entry == (8'h18 | 8'h10) | ((Entry == 8'h14) & (PWChipSelect[ChipSelectID] != ChipSelectDef[ChipSelectID]))))) HoldModeDeassert <= 1; - // Signal tracks which edge of sck to shift data always_comb case(SckMode[1:0]) 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 75643063d..b9c82c92d 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 @@ -69,36 +69,6 @@ test_cases: .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 @@ -405,9 +375,10 @@ test_cases: .4byte cs_mode, 0x00000002, write32_test # set cs_mode to hold .4byte tx_data, 0x000000CE, write32_test # place data into tx_data .4byte cs_id, 0x00000001, write32_test #change selected cs pin. should deassert cs[0] in hold mode -.4byte cs_def, 0x00001101, write32_test # change selected cs pins def value. should deassert cs[1] -.4byte cs_def, 0x00001111, write32_test # reset cs_def +.4byte cs_def, 0x0000000D, write32_test # change selected cs pins def value. should deassert cs[1] .4byte cs_mode, 0x00000000, write32_test # change cs_mode to auto, should deassert cs[1], have now gone through all deassertion conditions +.4byte cs_def, 0x0000000F, write32_test # reset cs_def +.4byte cs_id, 0x00000000, write32_test # reset cs_id .4byte rx_data, 0x000000CE, read32_test # clear rx_fifo # =========== Test frame format (fmt) register =========== 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 3f2690162..266b0e74f 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 @@ -377,9 +377,10 @@ test_cases: .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_def, 0x0000000D, write32_test # change selected cs pins def value. should deassert cs[1] .8byte cs_mode, 0x00000000, write32_test # change cs_mode to auto, should deassert cs[1], have now gone through all deassertion conditions +.8byte cs_def, 0x0000000F, write32_test # reset cs_def +.8byte cs_id, 0x00000000, write32_test # reset cs_id .8byte rx_data, 0x000000CE, read32_test # clear rx_fifo # =========== Test frame format (fmt) register =========== From b13b8feee413e3adc4d2953ed80599858879811b Mon Sep 17 00:00:00 2001 From: naichewa Date: Wed, 8 Nov 2023 15:28:51 -0800 Subject: [PATCH 28/36] updated to-do comments --- 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 b51516368..3d2e0a340 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. -// 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 @@ -36,7 +35,7 @@ /* 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 +The FIFOs are connected to WALLY by an apb 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. */ From a6bc69d73fa37c6f506aa890e3814cfb251051c1 Mon Sep 17 00:00:00 2001 From: "James E. Stine" Date: Wed, 8 Nov 2023 23:57:59 -0600 Subject: [PATCH 29/36] Add encoding for utf-8 on wrapperGen.py to avoid issue with incorrect encoding on RHEL C-shell --- synthDC/scripts/wrapperGen.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/synthDC/scripts/wrapperGen.py b/synthDC/scripts/wrapperGen.py index 3a0984bc3..b570ad0c0 100755 --- a/synthDC/scripts/wrapperGen.py +++ b/synthDC/scripts/wrapperGen.py @@ -21,7 +21,7 @@ args=parser.parse_args() fin_path = glob.glob(f"{os.getenv('WALLY')}/src/**/{args.DESIGN}.sv",recursive=True)[0] -fin = open(fin_path, "r") +fin = open(fin_path, "r", encoding='utf-8') lines = fin.readlines() @@ -70,4 +70,4 @@ fout.write(buf) fin.close() fout.close() -#print(buf) \ No newline at end of file +#print(buf) From 5a115bc6f2201ff1b752782410efcffa50c734e0 Mon Sep 17 00:00:00 2001 From: "James E. Stine" Date: Thu, 9 Nov 2023 00:52:40 -0600 Subject: [PATCH 30/36] update ppaSynth.py with runCommand --- synthDC/ppa/ppaSynth.py | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/synthDC/ppa/ppaSynth.py b/synthDC/ppa/ppaSynth.py index 6b45e2c4c..d9d07c10d 100755 --- a/synthDC/ppa/ppaSynth.py +++ b/synthDC/ppa/ppaSynth.py @@ -1,16 +1,19 @@ #!/usr/bin/python3 # -# Python analysis for regression test run by ppaSynth.py +# Python regression test for DC # Madeleine Masser-Frye mmasserfrye@hmc.edu 5/22 # James Stine james.stine@okstate.edu 15 October 2023 # + import subprocess import re from multiprocessing import Pool from ppaAnalyze import synthsfromcsv def runCommand(module, width, tech, freq): - command = "make synth DESIGN=ppa_{}_{} TECH={} DRIVE=INV FREQ={} MAXOPT=1 MAXCORES=1".format(module, width, tech, freq) + command = "make synth DESIGN={} WIDTH={} TECH={} DRIVE=INV FREQ={} MAXOPT=1 MAXCORES=1".format(module, width, tech, freq) + print('here we go') + subprocess.Popen(command, shell=True) def deleteRedundant(synthsToRun): @@ -23,7 +26,7 @@ def deleteRedundant(synthsToRun): def freqSweep(module, width, tech): synthsToRun = [] arr = [-8, -6, -4, -2, 0, 2, 4, 6, 8] - allSynths = synthsfromcsv('bestSynths.csv') + allSynths = synthsfromcsv('ppa/bestSynths.csv') for synth in allSynths: if (synth.module == module) & (synth.tech == tech) & (synth.width == width): f = 1000/synth.delay @@ -57,20 +60,20 @@ def allCombos(widths, modules, techs, freqs): if __name__ == '__main__': ##### Run specific syntheses - widths = [8, 16, 32, 64, 128] - modules = ['mult', 'add', 'shiftleft', 'flop', 'comparator', 'priorityencoder', 'add', 'csa', 'mux2', 'mux4', 'mux8'] - techs = ['sky90', 'sky130', 'tsmc28', 'tsmc28psyn'] - freqs = [5000] - synthsToRun = allCombos(widths, modules, techs, freqs) + widths = [8, 16, 32, 64, 128] + modules = ['mult', 'add', 'shiftleft', 'flop', 'comparator', 'priorityencoder', 'add', 'csa', 'mux2', 'mux4', 'mux8'] + techs = ['sky90', 'tsmc28'] + freqs = [5000] + synthsToRun = allCombos(widths, modules, techs, freqs) ##### Run a sweep based on best delay found in existing syntheses - module = 'add' - width = 32 - tech = 'sky90' - synthsToRun = freqSweep(module, width, tech) + module = 'add' + width = 32 + tech = 'sky90' + synthsToRun = freqSweep(module, width, tech) ##### Only do syntheses for which a run doesn't already exist - synthsToRun = filterRedundant(synthsToRun) - - pool = Pool(processes=25) - pool.starmap(print, synthsToRun) + synthsToRun = filterRedundant(synthsToRun) + + pool = Pool(processes=25) + pool.starmap(runCommand, synthsToRun) From 9a47667fd7bacce43b0d06cd1db4152e791e53a9 Mon Sep 17 00:00:00 2001 From: "James E. Stine" Date: Thu, 9 Nov 2023 01:00:33 -0600 Subject: [PATCH 31/36] update README on ppa --- synthDC/README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/synthDC/README.md b/synthDC/README.md index 91804b29b..edbd57340 100644 --- a/synthDC/README.md +++ b/synthDC/README.md @@ -31,3 +31,12 @@ SAIFPOWER 0: switching factor power analysis 1: RTL simulation driven power analysis. +----- +Extra Tool (PPA) + +To run ppa analysis that hones into target frequency, you can type: +python3 ppa/ppaSynth.py from the synthDC directory. This runs a sweep +across all modules listed at the bottom of the ppaSynth.py file. + + + From 625652b9ca4d4833fe009c7cd342e7faa1f1275d Mon Sep 17 00:00:00 2001 From: David Harris Date: Thu, 9 Nov 2023 06:59:29 -0800 Subject: [PATCH 32/36] Reporting stall path in synthesis script, support Zcb in Imperas --- sim/imperas.ic | 2 ++ synthDC/scripts/synth.tcl | 2 ++ 2 files changed, 4 insertions(+) diff --git a/sim/imperas.ic b/sim/imperas.ic index 9a9a0fc8f..33f2cc62a 100644 --- a/sim/imperas.ic +++ b/sim/imperas.ic @@ -16,10 +16,12 @@ --override cpu/bitmanip_version=1.0.0 # More extensions +--override cpu/Zcb=T --override cpu/Zicbom=T --override cpu/Zicbop=T --override cpu/Zicboz=T --override cpu/Svpbmt=T +#--override cpu/Svadu=T # 64 KiB continuous huge pages supported --override cpu/Svnapot_page_mask=65536 diff --git a/synthDC/scripts/synth.tcl b/synthDC/scripts/synth.tcl index 9be076edf..ba548869f 100755 --- a/synthDC/scripts/synth.tcl +++ b/synthDC/scripts/synth.tcl @@ -308,6 +308,8 @@ set filename [format "%s%s" $outputDir "/reports/mindelay.rep"] redirect $filename { report_timing -capacitance -transition_time -nets -delay_type min -nworst 1 } set filename [format "%s%s" $outputDir "/reports/per_module_timing.rep"] +redirect -append $filename { echo "\n\n\n//// Critical paths through Stall ////\n\n\n" } +redirect -append $filename { report_timing -capacitance -transition_time -nets -through {Stall*} -nworst 1 } redirect -append $filename { echo "\n\n\n//// Critical paths through ifu ////\n\n\n" } redirect -append $filename { report_timing -capacitance -transition_time -nets -through {ifu/*} -nworst 1 } redirect -append $filename { echo "\n\n\n//// Critical paths through ieu ////\n\n\n" } From 3052a68d84d5063a4283f6351e93a0e400cedff6 Mon Sep 17 00:00:00 2001 From: naichewa Date: Thu, 9 Nov 2023 16:48:11 -0800 Subject: [PATCH 33/36] Remove old 2/4 bit logic, add comments, clean up unused signals --- src/uncore/spi_apb.sv | 218 +++++++++++++++++++++--------------------- 1 file changed, 108 insertions(+), 110 deletions(-) diff --git a/src/uncore/spi_apb.sv b/src/uncore/spi_apb.sv index 3d2e0a340..9840e4bd0 100644 --- a/src/uncore/spi_apb.sv +++ b/src/uncore/spi_apb.sv @@ -27,10 +27,8 @@ // Current limitations: Flash read sequencer mode not implemented, dual and quad modes untestable with current test plan. -// 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 +// Attempt to move from >= comparisons by initializing in FSM differently +// Parameterize SynchFIFO // look at ReadIncrement/WriteIncrement delay necessity /* @@ -56,8 +54,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( output logic SPIIntr ); - //SPI registers - + //SPI control registers. Refer to SiFive FU540-C000 manual logic [11:0] SckDiv; logic [1:0] SckMode; logic [1:0] ChipSelectID; @@ -65,102 +62,96 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( logic [1:0] ChipSelectMode; logic [15:0] Delay0, Delay1; logic [4:0] Format; - logic [8:0] ReceiveData; - logic [8:0] ReceiveDataPlaceholder; + logic [7:0] ReceiveData; logic [2:0] TransmitWatermark, ReceiveWatermark; logic [8:0] TransmitData; logic [1:0] InterruptEnable, InterruptPending; - //bus interface signals + //Bus interface signals logic [7:0] Entry; logic Memwrite; logic [31:0] Din, Dout; + logic TransmitInactive; //High when there is no transmission, used as hardware interlock signal //FIFO FSM signals - logic TransmitWriteMark, TransmitReadMark, RecieveWriteMark, RecieveReadMark; + //Watermark signals - TransmitReadMark = ip[0], ReceiveWriteMark = ip[1] + logic TransmitWriteMark, TransmitReadMark, RecieveWriteMark, RecieveReadMark; logic TransmitFIFOWriteFull, TransmitFIFOReadEmpty; logic TransmitFIFOReadIncrement; logic TransmitFIFOWriteIncrement; logic ReceiveFIFOReadIncrement; - logic ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty; logic [7:0] TransmitFIFOReadData, ReceiveFIFOWriteData; logic [2:0] TransmitWriteWatermarkLevel, ReceiveReadWatermarkLevel; + logic [7:0] ReceiveShiftRegEndian; //reverses ReceiveShiftReg if Format[2] set (little endian transmission) - logic TransmitFIFOReadEmptyDelay; - logic [7:0] ReceiveShiftRegEndian; - - //transmission signals + //Transmission signals logic sck; - logic [11:0] DivCounter; - logic SCLKenable; - logic [8:0] Delay0Count; - logic [8:0] Delay1Count; - logic Delay0Compare; - logic Delay1Compare; - logic InterCSCompare; - logic [8:0] InterCSCount; - logic InterXFRCompare; - logic [8:0] InterXFRCount; - logic [3:0] ChipSelectInternal; - logic [4:0] FrameCount; - logic [4:0] FrameCompare; + logic [11:0] DivCounter; //counter for sck + logic SCLKenable; //flip flop enable high every sclk edge - logic FrameCompareBoolean; - logic [4:0] ReceivePenultimateFrame; - logic [4:0] ReceivePenultimateFrameCount; - logic ReceivePenultimateFrameBoolean; - logic [4:0] FrameCompareProtocol; - logic ReceiveShiftFull; - logic TransmitShiftEmpty; - logic HoldModeDeassert; + //Delay signals + logic [8:0] ImplicitDelay1; //Adds implicit delay to cs-sck delay counter based on phase + logic [8:0] ImplicitDelay2; //Adds implicit delay to sck-cs delay counter based on phase + logic [8:0] CS_SCKCount; //Counter for cs-sck delay + logic [8:0] SCK_CSCount; //Counter for sck-cs delay + logic [8:0] InterCSCount; //Counter for inter cs delay + logic [8:0] InterXFRCount; //Counter for inter xfr delay + logic CS_SCKCompare; //Boolean comparison signal, high when CS_SCKCount >= cs-sck delay + logic SCK_CSCompare; //Boolean comparison signal, high when SCK_CSCount >= sck-cs delay + logic InterCSCompare; //Boolean comparison signal, high when InterCSCount >= inter cs delay + logic InterXFRCompare; //Boolean comparison signal, high when InterXFRCount >= inter xfr delay + logic ZeroDelayHoldMode; //High when ChipSelectMode is hold and Delay1[15:8] (InterXFR delay) is 0 + //Frame counting signals + logic [3:0] FrameCount; //Counter for number of frames in transmission + logic FrameCompare; //Boolean comparison signal, high when FrameCount = Format[7:4] + logic [3:0] ReceivePenultimateFrame; //Frame number - 1 + logic [3:0] ReceivePenultimateFrameCount; //Counter + logic ReceivePenultimateFrameBoolean; //High when penultimate frame in transmission has been reached - //state fsm signals - logic Active; - logic Active0; - logic Inactive; + //State fsm signals + logic Active; //High when state is either Active1 or Active0 (during transmission) + logic Active0; //High when state is Active0 - //shift reg signals - logic TransmitFIFOWriteIncrementDelay; - logic sckPhaseSelect; - logic [7:0] TransmitShiftReg; - logic [7:0] ReceiveShiftReg; - logic SampleEdge; - logic [7:0] TransmitDataEndian; - logic TransmitShiftRegLoad; + //Shift reg signals + logic ShiftEdge; //Determines which edge of sck to shift from TransmitShiftReg + logic [7:0] TransmitShiftReg; //Transmit shift register + logic [7:0] ReceiveShiftReg; //Receive shift register + logic SampleEdge; //Determines which edge of sck to sample from ReceiveShiftReg + logic [7:0] TransmitDataEndian; //Reverses TransmitData from txFIFO if littleendian, since TransmitReg always shifts MSB + logic TransmitShiftRegLoad; //Determines when to load TransmitShiftReg + logic ReceiveShiftFull; //High when receive shift register is full + logic TransmitShiftEmpty; //High when transmit shift register is empty + logic ShiftIn; //Determines whether to shift from SPIIn or SPIOut (if SPI_LOOPBACK_TEST) + logic [3:0] LeftShiftAmount; //Determines left shift amount to left-align data when little endian + logic [7:0] ASR; //AlignedReceiveShiftReg //CS signals - logic [3:0] ChipSelectAuto, ChipSelectHold, CSoff; - logic ChipSelectHoldSingle; + logic [3:0] ChipSelectAuto; //Assigns ChipSelect value to selected CS signal based on CS ID + logic [3:0] ChipSelectInternal; //Defines what each ChipSelect signal should be based on transmission status and ChipSelectDef + logic DelayMode; //Determines where to place implicit half cycle delay based on sck phase for CS assertion - logic ReceiveShiftFullDelay; + //Miscellaneous signals delayed/early by 1 PCLK cycle + logic ReceiveShiftFullDelay; //Delays ReceiveShiftFull signal by 1 PCLK cycle + logic TransmitFIFOWriteIncrementDelay; //TransmitFIFOWriteIncrement delayed by 1 PCLK cycle + logic ReceiveShiftFullDelayPCLK; //ReceiveShiftFull delayed by 1 PCLK cycle + logic TransmitFIFOReadEmptyDelay; + logic SCLKenableEarly; //SCLKenable 1 PCLK cycle early, needed for on time register changes when ChipSelectMode is hold and Delay1[15:8] (InterXFR delay) is 0 - logic SCLKenableDelay; - logic shiftin; - logic [7:0] ReceiveShiftRegInvert; - logic ZeroDelayHoldMode; - logic TransmitInactive; - logic SCLKenableEarly; - logic ReceiveShiftFullDelayPCLK; - logic [3:0] LeftShiftAmount; - logic [7:0] ASR; // AlignedReceiveShiftReg - logic DelayMode; - logic [3:0] PWChipSelect; - - // APB access + //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 = TransmitInactive; // tie PREADY to transmission for hardware interlock - // account for subword read/write circuitry + //Account for subword read/write circuitry // -- Note SPI registers are 32 bits no matter what; access them with LW SW. assign Din = PWDATA[31:0]; if (P.XLEN == 64) assign PRDATA = {Dout, Dout}; else assign PRDATA = Dout; - // register access *** clean this up + //Register access always_ff@(posedge PCLK, negedge PRESETn) if (~PRESETn) begin SckDiv <= #1 12'd3; @@ -219,8 +210,8 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( 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 + //SPI enable generation, where SCLK = PCLK/(2*(SckDiv + 1)) + //Generates a high signal at the rising and falling edge of SCLK by counting from 0 to SckDiv assign SCLKenable = (DivCounter == SckDiv); assign SCLKenableEarly = ((DivCounter + 12'b1) == SckDiv); always_ff @(posedge PCLK, negedge PRESETn) @@ -229,23 +220,25 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( else DivCounter <= DivCounter + 12'b1; //Boolean logic that tracks frame progression - assign FrameCompare = {1'b0,Format[4:1]}; - assign FrameCompareBoolean = (FrameCount < FrameCompare); - assign ReceivePenultimateFrameCount = FrameCount + 5'b00001; - assign ReceivePenultimateFrameBoolean = (ReceivePenultimateFrameCount >= FrameCompare); + //assign FrameCompare = {1'b0,Format[4:1]}; mb not needed because of removal of dual/quad + assign FrameCompare = (FrameCount < Format[4:1]); + assign ReceivePenultimateFrameBoolean = ((FrameCount + 4'b0001) == Format[4:1]); - // Computing delays + //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 ImplicitDelay1 = SckMode[0] ? 9'b0 : 9'b1; + assign ImplicitDelay2 = SckMode[0] ? 9'b1 : 9'b0; + + assign CS_SCKCompare = CS_SCKCount >= (({Delay0[7:0], 1'b0}) + ImplicitDelay1); + assign SCK_CSCompare = SCK_CSCount >= (({Delay0[15:8], 1'b0}) + ImplicitDelay2); assign InterCSCompare = (InterCSCount >= ({Delay1[7:0],1'b0})); assign InterXFRCompare = (InterXFRCount >= ({Delay1[15:8], 1'b0})); - //calculate when tx/rx shift registers are full/empty + //Calculate when tx/rx shift registers are full/empty TransmitShiftFSM TransmitShiftFSM_1 (PCLK, PRESETn, TransmitFIFOReadEmpty, ReceivePenultimateFrameBoolean, Active0, TransmitShiftEmpty); ReceiveShiftFSM ReceiveShiftFSM_1 (PCLK, PRESETn, SCLKenable, ReceivePenultimateFrameBoolean, SampleEdge, SckMode[0], ReceiveShiftFull); - //calculate tx/rx fifo write and recieve increment signals + //Calculate tx/rx fifo write and recieve increment signals assign TransmitFIFOWriteIncrement = (Memwrite & (Entry == 8'h48) & ~TransmitFIFOWriteFull & TransmitInactive); always_ff @(posedge PCLK, negedge PRESETn) @@ -256,7 +249,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( if (~PRESETn) ReceiveFIFOReadIncrement <= 0; else ReceiveFIFOReadIncrement <= ((Entry == 8'h4C) & ~ReceiveFIFOReadEmpty & PSEL & ~ReceiveFIFOReadIncrement); - //tx/rx FIFOs + //Tx/Tx 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); @@ -280,36 +273,36 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( always_ff @(posedge PCLK, negedge PRESETn) if (~PRESETn) begin state <= CS_INACTIVE; - FrameCount <= 5'b0; + FrameCount <= 4'b0; /* verilator lint_off CASEINCOMPLETE */ end else if (SCLKenable) begin case (state) CS_INACTIVE: begin - Delay0Count <= 9'b1; - Delay1Count <= 9'b10; - FrameCount <= 5'b0; + CS_SCKCount <= 9'b1; + SCK_CSCount <= 9'b10; + FrameCount <= 4'b0; InterCSCount <= 9'b10; InterXFRCount <= 9'b1; if ((~TransmitFIFOReadEmpty | ~TransmitShiftEmpty) & ((|(Delay0[7:0])) | ~SckMode[0])) state <= DELAY_0; else if ((~TransmitFIFOReadEmpty | ~TransmitShiftEmpty)) state <= ACTIVE_0; end DELAY_0: begin - Delay0Count <= Delay0Count + 9'b1; - if (Delay0Compare) state <= ACTIVE_0; + CS_SCKCount <= CS_SCKCount + 9'b1; + if (CS_SCKCompare) state <= ACTIVE_0; end ACTIVE_0: begin - FrameCount <= FrameCount + 5'b1; + FrameCount <= FrameCount + 4'b1; state <= ACTIVE_1; end ACTIVE_1: begin InterXFRCount <= 9'b1; - if (FrameCompareBoolean) state <= ACTIVE_0; + if (FrameCompare) state <= ACTIVE_0; else if ((ChipSelectMode[1:0] == 2'b10) & ~|(Delay1[15:8]) & (~TransmitFIFOReadEmpty)) begin state <= ACTIVE_0; - Delay0Count <= 9'b1; - Delay1Count <= 9'b10; - FrameCount <= 5'b0; + CS_SCKCount <= 9'b1; + SCK_CSCount <= 9'b10; + FrameCount <= 4'b0; InterCSCount <= 9'b10; end else if (ChipSelectMode[1:0] == 2'b10) state <= INTER_XFR; @@ -317,17 +310,17 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( else state <= DELAY_1; end DELAY_1: begin - Delay1Count <= Delay1Count + 9'b1; - if (Delay1Compare) state <= INTER_CS; + SCK_CSCount <= SCK_CSCount + 9'b1; + if (SCK_CSCompare) 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; + CS_SCKCount <= 9'b1; + SCK_CSCount <= 9'b10; + FrameCount <= 4'b0; InterCSCount <= 9'b10; InterXFRCount <= InterXFRCount + 9'b1; if (InterXFRCompare & ~TransmitFIFOReadEmptyDelay) state <= ACTIVE_0; @@ -346,16 +339,15 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( 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); - // 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; - 2'b01: sckPhaseSelect = (sck & |(FrameCount) & SCLKenable); - 2'b10: sckPhaseSelect = sck & SCLKenable; - 2'b11: sckPhaseSelect = (~sck & |(FrameCount) & SCLKenable); - default: sckPhaseSelect = sck & SCLKenable; + 2'b00: ShiftEdge = ~sck & SCLKenable; + 2'b01: ShiftEdge = (sck & |(FrameCount) & SCLKenable); + 2'b10: ShiftEdge = sck & SCLKenable; + 2'b11: ShiftEdge = (~sck & |(FrameCount) & SCLKenable); + default: ShiftEdge = sck & SCLKenable; endcase //Transmit shift register @@ -363,32 +355,31 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( always_ff @(posedge PCLK, negedge PRESETn) if(~PRESETn) TransmitShiftReg <= 8'b0; else if (TransmitShiftRegLoad) TransmitShiftReg <= TransmitDataEndian; - else if (sckPhaseSelect & Active) TransmitShiftReg <= {TransmitShiftReg[6:0], 1'b0}; + else if (ShiftEdge & 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; + assign ShiftIn = P.SPI_LOOPBACK_TEST ? SPIOut : SPIIn; - // Receive shift register + //Receive shift register always_ff @(posedge PCLK, negedge PRESETn) if(~PRESETn) ReceiveShiftReg <= 8'b0; else if (SampleEdge & SCLKenable) begin if (~Active) ReceiveShiftReg <= 8'b0; - else ReceiveShiftReg <= {ReceiveShiftReg[6:0], shiftin}; + else ReceiveShiftReg <= {ReceiveShiftReg[6:0], ShiftIn}; end - // Aligns received data and reverses if little-endian + //Aligns received data and reverses if little-endian assign LeftShiftAmount = 4'h8 - Format[4:1]; assign 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 + //Interrupt logic: raise interrupt if any enabled interrupts are pending assign SPIIntr = |(InterruptPending & InterruptEnable); - // Chip select logic - + //Chip select logic always_comb case(ChipSelectID[1:0]) 2'b00: ChipSelectAuto = {ChipSelectDef[3], ChipSelectDef[2], ChipSelectDef[1], ChipSelectInternal[0]}; @@ -409,6 +400,13 @@ module SynchFIFO #(parameter M =3 , N= 8)( output logic wfull, rempty, output logic wwatermark, rwatermark); + /* Pointer FIFO using design elements from "Simulation and Synthesis Techniques + for Asynchronous FIFO Design" by Clifford E. Cummings. Namely, M bit read and write pointers + are an extra bit larger than address size to determine full/empty conditions. + Watermark comparisons use 2's complement subtraction between the M-1 bit pointers, + which are also used to address memory + */ + logic [N-1:0] mem[2**M]; logic [M:0] rptr, wptr; logic [M:0] rptrnext, wptrnext; @@ -416,7 +414,7 @@ module SynchFIFO #(parameter M =3 , N= 8)( 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; From 5ce16dcb63d00be5af778e669bc5cb2f0b82e112 Mon Sep 17 00:00:00 2001 From: naichewa Date: Thu, 9 Nov 2023 16:52:55 -0800 Subject: [PATCH 34/36] Cleanup --- src/uncore/spi_apb.sv | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/uncore/spi_apb.sv b/src/uncore/spi_apb.sv index 9840e4bd0..4db435be6 100644 --- a/src/uncore/spi_apb.sv +++ b/src/uncore/spi_apb.sv @@ -220,7 +220,6 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( else DivCounter <= DivCounter + 12'b1; //Boolean logic that tracks frame progression - //assign FrameCompare = {1'b0,Format[4:1]}; mb not needed because of removal of dual/quad assign FrameCompare = (FrameCount < Format[4:1]); assign ReceivePenultimateFrameBoolean = ((FrameCount + 4'b0001) == Format[4:1]); @@ -249,7 +248,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( if (~PRESETn) ReceiveFIFOReadIncrement <= 0; else ReceiveFIFOReadIncrement <= ((Entry == 8'h4C) & ~ReceiveFIFOReadEmpty & PSEL & ~ReceiveFIFOReadIncrement); - //Tx/Tx FIFOs + //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); @@ -273,7 +272,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) ( always_ff @(posedge PCLK, negedge PRESETn) if (~PRESETn) begin state <= CS_INACTIVE; - FrameCount <= 4'b0; + FrameCount <= 4'b0; /* verilator lint_off CASEINCOMPLETE */ end else if (SCLKenable) begin From 7e0058118753eb839ff624330e3341151b510141 Mon Sep 17 00:00:00 2001 From: David Harris Date: Fri, 10 Nov 2023 06:27:25 -0800 Subject: [PATCH 35/36] Add Svadu support and SPI to imperas configuration --- sim/imperas.ic | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sim/imperas.ic b/sim/imperas.ic index 33f2cc62a..259affc08 100644 --- a/sim/imperas.ic +++ b/sim/imperas.ic @@ -42,10 +42,14 @@ --override cpu/ignore_non_leaf_DAU=1 --override cpu/wfi_is_nop=T --override cpu/misa_Extensions_mask=0x0 ---override cpu/updatePTEA=T ---override cpu/updatePTED=T --override cpu/Sstc=T +# Enable SVADU hardware update of A/D bits when menvcfg.HADE=1 +--override cpu/Svadu=T +--override cpu/updatePTEA=F +--override cpu/updatePTED=F + + # THIS NEEDS FIXING to 16 --override cpu/PMP_registers=16 --override cpu/PMP_undefined=T @@ -71,7 +75,8 @@ --callcommand refRoot/cpu/setPMA -lo 0x0002000000 -hi 0x000200FFFF -attributes " rw--A- 1248 " # CLINT --callcommand refRoot/cpu/setPMA -lo 0x000C000000 -hi 0x000FFFFFFF -attributes " rw--A- --4- " # PLIC --callcommand refRoot/cpu/setPMA -lo 0x0010000000 -hi 0x0010000007 -attributes " rw--A- 1--- " # UART0 error - 0x10000000 - 0x100000FF ---callcommand refRoot/cpu/setPMA -lo 0x0010060000 -hi 0x00100600FF -attributes " rw--A- --4- " # GPIO error - 0x10006000 - 0x100060FF +--callcommand refRoot/cpu/setPMA -lo 0x0010060000 -hi 0x00100600FF -attributes " rw--A- --4- " # GPIO error - 0x10069000 - 0x100600FF +--callcommand refRoot/cpu/setPMA -lo 0x0010040000 -hi 0x0010040FFF -attributes " rw--A- --4- " # SPI error - 0x10040000 - 0x10040FFF --callcommand refRoot/cpu/setPMA -lo 0x0080000000 -hi 0x008FFFFFFF -attributes " rwx--- 1248 " # UNCORE_RAM # Enable the Imperas instruction coverage From 426aabbc1a50f39a56f2faa6b7c9db09b9d36706 Mon Sep 17 00:00:00 2001 From: David Harris Date: Fri, 10 Nov 2023 08:26:32 -0800 Subject: [PATCH 36/36] Imperas commenting --- sim/imperas.ic | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sim/imperas.ic b/sim/imperas.ic index 259affc08..adb10dcad 100644 --- a/sim/imperas.ic +++ b/sim/imperas.ic @@ -17,12 +17,14 @@ # More extensions --override cpu/Zcb=T + +# Cache block operations --override cpu/Zicbom=T --override cpu/Zicbop=T --override cpu/Zicboz=T ---override cpu/Svpbmt=T -#--override cpu/Svadu=T + # 64 KiB continuous huge pages supported +--override cpu/Svpbmt=T --override cpu/Svnapot_page_mask=65536