mirror of
https://github.com/openhwgroup/cvw
synced 2025-02-11 06:05:49 +00:00
Merge pull request #540 from davidharrishmc/dev
Fix Timer Interrupt Issue #530 and coverage/tlbNAPOT tests #457
This commit is contained in:
commit
b701cbf823
@ -35,7 +35,7 @@ localparam XLEN = 32'd32;
|
||||
// IEEE 754 compliance
|
||||
localparam IEEE754 = 0;
|
||||
|
||||
localparam MISA = (32'h00000104 | 1 << 1 | 1 << 20 | 1 << 18 | 1 << 12 | 1 << 0 | 1 <<3 | 1 << 5);
|
||||
localparam MISA = (32'h00000104 | 1 << 20 | 1 << 18 | 1 << 12 | 1 << 0 | 1 <<3 | 1 << 5);
|
||||
localparam ZICSR_SUPPORTED = 1;
|
||||
localparam ZIFENCEI_SUPPORTED = 1;
|
||||
localparam COUNTERS = 12'd32;
|
||||
|
@ -34,7 +34,7 @@ localparam XLEN = 32'd64;
|
||||
localparam IEEE754 = 0;
|
||||
|
||||
// MISA RISC-V configuration per specification
|
||||
localparam MISA = (32'h00000104 | 1 << 1 | 1 << 5 | 1 << 3 | 1 << 18 | 1 << 20 | 1 << 12 | 1 << 0);
|
||||
localparam MISA = (32'h00000104 | 1 << 5 | 1 << 3 | 1 << 18 | 1 << 20 | 1 << 12 | 1 << 0);
|
||||
localparam ZICSR_SUPPORTED = 1;
|
||||
localparam ZIFENCEI_SUPPORTED = 1;
|
||||
localparam COUNTERS = 12'd32;
|
||||
|
@ -17,7 +17,7 @@ all: riscoftests memfiles coveragetests
|
||||
|
||||
wally-riscv-arch-test: wallyriscoftests memfiles
|
||||
|
||||
coverage:
|
||||
coverage: cov/rv64gc_arch64i.ucdb
|
||||
#make -C ../tests/coverage --jobs
|
||||
#iter-elf.bash --cover --search ../tests/coverage
|
||||
vcover merge -out cov/cov.ucdb cov/rv64gc_arch64i.ucdb cov/rv64gc*.ucdb -logfile cov/log
|
||||
|
@ -51,9 +51,13 @@
|
||||
--override cpu/unaligned=T # Zicclsm (should be true)
|
||||
--override cpu/ignore_non_leaf_DAU=1
|
||||
--override cpu/wfi_is_nop=T
|
||||
--override cpu/misa_Extensions_mask=0x0
|
||||
--override cpu/misa_Extensions_mask=0x0 # MISA not writable
|
||||
--override cpu/Sstc=T
|
||||
|
||||
# unsuccessfully attempt to add B extension (DH 12/21/23)
|
||||
#--override cpu/add_Extensions="B"
|
||||
#--override cpu/misa_Extensions=0x0014112F
|
||||
|
||||
# Enable SVADU hardware update of A/D bits when menvcfg.ADUE=1
|
||||
--override cpu/Svadu=T
|
||||
#--override cpu/updatePTEA=F
|
||||
|
@ -37,17 +37,17 @@ module adrdecs import cvw::*; #(parameter cvw_t P) (
|
||||
|
||||
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[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, AccessRWXC, 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, AccessRWXC, Size, SUPPORTED_SIZE, SelRegions[7]);
|
||||
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[1]);
|
||||
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[2]);
|
||||
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, AccessRWXC, Size, SUPPORTED_SIZE, SelRegions[3]);
|
||||
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[4]);
|
||||
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, AccessRWXC, Size, SUPPORTED_SIZE, SelRegions[5]);
|
||||
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]);
|
||||
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[7]);
|
||||
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[8]);
|
||||
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[9]);
|
||||
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[10]);
|
||||
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[11]);
|
||||
|
||||
assign SelRegions[0] = ~|(SelRegions[11:1]); // none of the regions are selected
|
||||
endmodule
|
||||
|
@ -58,18 +58,18 @@ module pmachecker import cvw::*; #(parameter cvw_t P) (
|
||||
adrdecs #(P) adrdecs(PhysicalAddress, AccessRW, AccessRX, AccessRWXC, Size, SelRegions);
|
||||
|
||||
// Only non-core RAM/ROM memory regions are cacheable. PBMT can override cachable; NC and IO are uncachable
|
||||
assign CacheableRegion = SelRegions[9] | SelRegions[8] | SelRegions[7]; // exclusion-tag: unused-cachable
|
||||
assign CacheableRegion = SelRegions[3] | SelRegions[4] | SelRegions[5]; // 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[11] | SelRegions[10] | SelRegions[9] | SelRegions[8] | SelRegions[7]; // exclusion-tag: unused-idempotent
|
||||
assign IdempotentRegion = SelRegions[1] | SelRegions[2] | SelRegions[3] | SelRegions[4] | SelRegions[5]; // 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]; // exclusion-tag: unused-idempotent
|
||||
assign AtomicAllowed = SelRegions[1] | SelRegions[3] | SelRegions[5]; // exclusion-tag: unused-idempotent
|
||||
// Check if tightly integrated memories are selected
|
||||
assign SelTIM = SelRegions[11] | SelRegions[10]; // exclusion-tag: unused-idempotent
|
||||
assign SelTIM = SelRegions[1] | SelRegions[2]; // exclusion-tag: unused-idempotent
|
||||
|
||||
// Detect access faults
|
||||
assign PMAAccessFault = (SelRegions[0]) & AccessRWXC | AtomicAccessM & ~AtomicAllowed;
|
||||
|
@ -91,7 +91,7 @@ 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, HSELSPI} = HSELRegions[11:1];
|
||||
assign {HSELSPI, HSELEXTSDC, HSELPLIC, HSELUART, HSELGPIO, HSELCLINT, HSELRam, HSELBootRom, HSELEXT, HSELIROM, HSELDTIM} = HSELRegions[11:1];
|
||||
|
||||
// AHB -> APB bridge
|
||||
ahbapbbridge #(P, 5) ahbapbbridge (
|
||||
@ -180,7 +180,7 @@ module uncore import cvw::*; #(parameter cvw_t P)(
|
||||
// device is ready. Hense this register must be selectively enabled by HREADY.
|
||||
// However on reset None must be seleted.
|
||||
flopenl #(12) hseldelayreg(HCLK, ~HRESETn, HREADY, HSELRegions, 12'b1,
|
||||
{HSELDTIMD, HSELIROMD, HSELEXTD, HSELBootRomD, HSELRamD,
|
||||
HSELCLINTD, HSELGPIOD, HSELUARTD, HSELPLICD, HSELEXTSDCD, HSELSPID, HSELNoneD});
|
||||
{HSELSPID, HSELEXTSDCD, HSELPLICD, HSELUARTD, HSELGPIOD, HSELCLINTD,
|
||||
HSELRamD, HSELBootRomD, HSELEXTD, HSELIROMD, HSELDTIMD, HSELNoneD});
|
||||
flopenr #(1) hselbridgedelayreg(HCLK, ~HRESETn, HREADY, HSELBRIDGE, HSELBRIDGED);
|
||||
endmodule
|
||||
|
@ -205,12 +205,12 @@ module testbench;
|
||||
|
||||
end
|
||||
|
||||
always @(dut.core.MTimerInt) void'(rvvi.net_push("MTimerInterrupt", dut.core.MTimerInt));
|
||||
always @(dut.core.MExtInt) void'(rvvi.net_push("MExternalInterrupt", dut.core.MExtInt));
|
||||
always @(dut.core.SExtInt) void'(rvvi.net_push("SExternalInterrupt", dut.core.SExtInt));
|
||||
always @(dut.core.MSwInt) void'(rvvi.net_push("MSWInterrupt", dut.core.MSwInt));
|
||||
always @(dut.core.priv.priv.csr.csrs.csrs.STimerInt) void'(rvvi.net_push("STimerInterrupt", dut.core.priv.priv.csr.csrs.csrs.STimerInt));
|
||||
|
||||
always @(dut.core.priv.priv.csr.csri.MIP_REGW[7]) void'(rvvi.net_push("MTimerInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[7]));
|
||||
always @(dut.core.priv.priv.csr.csri.MIP_REGW[11]) void'(rvvi.net_push("MExternalInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[11]));
|
||||
always @(dut.core.priv.priv.csr.csri.MIP_REGW[9]) void'(rvvi.net_push("SExternalInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[9]));
|
||||
always @(dut.core.priv.priv.csr.csri.MIP_REGW[3]) void'(rvvi.net_push("MSWInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[3]));
|
||||
always @(dut.core.priv.priv.csr.csri.MIP_REGW[1]) void'(rvvi.net_push("SSWInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[1]));
|
||||
always @(dut.core.priv.priv.csr.csri.MIP_REGW[5]) void'(rvvi.net_push("STimerInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[5]));
|
||||
|
||||
final begin
|
||||
void'(rvviRefShutdown());
|
||||
|
@ -432,11 +432,12 @@ module testbench;
|
||||
end
|
||||
end
|
||||
|
||||
always @(dut.core.MTimerInt) void'(rvvi.net_push("MTimerInterrupt", dut.core.MTimerInt));
|
||||
always @(dut.core.MExtInt) void'(rvvi.net_push("MExternalInterrupt", dut.core.MExtInt));
|
||||
always @(dut.core.SExtInt) void'(rvvi.net_push("SExternalInterrupt", dut.core.SExtInt));
|
||||
always @(dut.core.MSwInt) void'(rvvi.net_push("MSWInterrupt", dut.core.MSwInt));
|
||||
always @(dut.core.priv.priv.csr.csrs.csrs.STimerInt) void'(rvvi.net_push("STimerInterrupt", dut.core.priv.priv.csr.csrs.csrs.STimerInt));
|
||||
always @(dut.core.priv.priv.csr.csri.MIP_REGW[7]) void'(rvvi.net_push("MTimerInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[7]));
|
||||
always @(dut.core.priv.priv.csr.csri.MIP_REGW[11]) void'(rvvi.net_push("MExternalInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[11]));
|
||||
always @(dut.core.priv.priv.csr.csri.MIP_REGW[9]) void'(rvvi.net_push("SExternalInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[9]));
|
||||
always @(dut.core.priv.priv.csr.csri.MIP_REGW[3]) void'(rvvi.net_push("MSWInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[3]));
|
||||
always @(dut.core.priv.priv.csr.csri.MIP_REGW[1]) void'(rvvi.net_push("SSWInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[1]));
|
||||
always @(dut.core.priv.priv.csr.csri.MIP_REGW[5]) void'(rvvi.net_push("STimerInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[5]));
|
||||
|
||||
final begin
|
||||
void'(rvviRefShutdown());
|
||||
|
@ -51,9 +51,11 @@ main:
|
||||
jal a1, looptest
|
||||
li a2, 0x40215240 # Test properly formed pages with 1 in PPN[3] that are not NAPOT
|
||||
jal a1, looptest
|
||||
# li t4, 0x1000 # address step size
|
||||
# li a2, 0x80216000 # Test NAPOT pages
|
||||
# jal a1, looptest
|
||||
li t4, 0x1000 # address step size
|
||||
li a2, 0x80216000 # Test NAPOT pages
|
||||
jal a1, looptest
|
||||
li a0, 3 # switch back to machine mode because code at 0x80000000 may not have clean page table entry
|
||||
ecall
|
||||
j done
|
||||
|
||||
looptest:
|
||||
@ -62,30 +64,64 @@ looptest:
|
||||
li t3, 35 # Max amount of Loops = 34
|
||||
li t5, 0x8082 # return instruction opcode
|
||||
|
||||
loop: bge t2, t3, looptesti # exit loop if i >= loops
|
||||
loop: bge t2, t3, finished # exit loop if i >= loops
|
||||
sw t5, 0(t0) # store a return at this address to exercise DTLB
|
||||
lw t1, 0(t0) # read it back
|
||||
fence.i # synchronize with I$
|
||||
jal changetoipfhandler # set up trap handler to return from instruction page fault if necessary
|
||||
jalr ra, t0 # jump to the return statement to exercise the ITLB
|
||||
jal changetodefaulthandler
|
||||
add t0, t0, t4
|
||||
addi t2, t2, 1
|
||||
j loop
|
||||
|
||||
looptesti:
|
||||
mv t0, a2 # base address
|
||||
li t2, 0 # i = 0
|
||||
fence.i # synchronize with I$
|
||||
|
||||
# Exercise itlb by jumping to each of the return statements
|
||||
loopi: bge t2, t3, finished # exit loop if i >= loops
|
||||
jalr ra, t0 # jump to the return statement to exercise the ITLB
|
||||
add t0, t0, t4
|
||||
addi t2, t2, 1
|
||||
j loopi
|
||||
|
||||
finished:
|
||||
jr a1
|
||||
|
||||
changetoipfhandler:
|
||||
li a0, 3
|
||||
ecall # switch to machine mode
|
||||
la a0, ipf_handler
|
||||
csrw mtvec, a0 # point to new handler
|
||||
li a0, 1
|
||||
ecall # switch back to supervisor mode
|
||||
ret
|
||||
|
||||
changetodefaulthandler:
|
||||
li a0, 3
|
||||
ecall # switch to machine mode
|
||||
la a0, trap_handler
|
||||
csrw mtvec, a0 # point to new handler
|
||||
li a0, 1
|
||||
ecall # switch back to supervisor mode
|
||||
ret
|
||||
|
||||
instructionpagefaulthandler:
|
||||
csrw mepc, ra # go back to calling function
|
||||
mret
|
||||
|
||||
.align 4 # trap handlers must be aligned to multiple of 4
|
||||
ipf_handler:
|
||||
# Load trap handler stack pointer tp
|
||||
csrrw tp, mscratch, tp # swap MSCRATCH and tp
|
||||
sd t0, 0(tp) # Save t0 and t1 on the stack
|
||||
sd t1, -8(tp)
|
||||
csrr t0, mcause # Check the cause
|
||||
li t1, 8 # is it an ecall trap?
|
||||
andi t0, t0, 0xFC # if CAUSE = 8, 9, or 11
|
||||
beq t0, t1, ecall # yes, take ecall
|
||||
csrr t0, mcause
|
||||
li t1, 12 # is it an instruction page fault
|
||||
beq t0, t1, ipf # yes, return to calling function
|
||||
j trap_return
|
||||
|
||||
ipf:
|
||||
csrw mepc, ra # return to calling function
|
||||
ld t1, -8(tp) # restore t1 and t0
|
||||
ld t0, 0(tp)
|
||||
csrrw tp, mscratch, tp # restore tp
|
||||
mret # return from trap
|
||||
|
||||
.data
|
||||
|
||||
.align 16
|
||||
|
Loading…
Reference in New Issue
Block a user