added working paging small kernel

This commit is contained in:
2026-03-29 17:59:39 +01:00
parent 4cea0232d4
commit a6decda220
17 changed files with 7322 additions and 533 deletions

View File

@@ -0,0 +1,40 @@
# scp encoding.h home-1:/home/akilan/
# scp entry.S home-1:/home/akilan/
# scp link.ld home-1:/home/akilan/
# scp riscv_test_p.h home-1:/home/akilan/
# scp riscv_test.h home-1:/home/akilan/
# scp string.c home-1:/home/akilan/
# scp vm.c home-1:/home/akilan/
# scp test.S home-1:/home/akilan/
# scp test_macros.h home-1:/home/akilan/
# GCC compile
# ssh home-1 'cd /home/akilan/ && export PATH=/opt/riscv/bin:$PATH && riscv64-unknown-elf-gcc -DENTROPY=0xf21e02b -mcmodel=medany -nostdlib -nostartfiles -ffreestanding -fno-builtin -mabi=lp64 -T link.ld vm.c string.c entry.S test.S -o testC'
# Clang compile (architecture Regular RISCV)
ssh home-1 'clang --target=riscv64-unknown-elf -DENTROPY=0xf21e02b --gcc-toolchain=/opt/riscv -mcmodel=medany -nostdlib -nostartfiles -ffreestanding -fno-builtin -mabi=lp64 -T link.ld vm.c string.c entry.S test.S -o testC'
# Clang using the cheri clang compiler
scp home-1:/home/akilan/testC .
export PATH=/home/akilan/cheri/output/sdk/bin/clang:$PATH
# riscv64-unknown-elf-gcc \
# -march=rv64imac \
# -mabi=lp64 \
# -nostartfiles \
# -fno-builtin \
# -T link.ld \
# entry.S vm.c string.c \
# clang \
# --target=riscv64-unknown-elf \
# -march=rv64imac \
# -mabi=lp64 \
# -nostdlib \
# -nostartfiles \
# -fuse-ld=lld \
# -T link.ld \
# entry.S vm.c string.c \
# -I. \
# -o output.elf

File diff suppressed because it is too large Load Diff

164
Tests/isa/Cprograms/entry.S Normal file
View File

@@ -0,0 +1,164 @@
#include "riscv_test.h"
#if __riscv_xlen == 64
# define STORE sd
# define LOAD ld
# define REGBYTES 8
#else
# define STORE sw
# define LOAD lw
# define REGBYTES 4
#endif
#define STACK_TOP (_end + RISCV_PGSIZE * 4)
.section ".text.init","ax",@progbits
.globl _start
.align 2
_start:
j handle_reset
/* NMI vector */
.align 2
nmi_vector:
j wtf
.align 2
trap_vector:
j wtf
handle_reset:
li x1, 0
li x2, 0
li x3, 0
li x4, 0
li x5, 0
li x6, 0
li x7, 0
li x8, 0
li x9, 0
li x10, 0
li x11, 0
li x12, 0
li x13, 0
li x14, 0
li x15, 0
li x16, 0
li x17, 0
li x18, 0
li x19, 0
li x20, 0
li x21, 0
li x22, 0
li x23, 0
li x24, 0
li x25, 0
li x26, 0
li x27, 0
li x28, 0
li x29, 0
li x30, 0
li x31, 0
INIT_RNMI
la t0, trap_vector
csrw mtvec, t0
la sp, STACK_TOP - SIZEOF_TRAPFRAME_T
csrr t0, mhartid
slli t0, t0, 12
add sp, sp, t0
csrw mscratch, sp
call extra_boot
la a0, userstart
j vm_boot
.globl pop_tf
pop_tf:
LOAD t0,33*REGBYTES(a0)
csrw sepc,t0
LOAD x1,1*REGBYTES(a0)
LOAD x2,2*REGBYTES(a0)
LOAD x3,3*REGBYTES(a0)
LOAD x4,4*REGBYTES(a0)
LOAD x5,5*REGBYTES(a0)
LOAD x6,6*REGBYTES(a0)
LOAD x7,7*REGBYTES(a0)
LOAD x8,8*REGBYTES(a0)
LOAD x9,9*REGBYTES(a0)
LOAD x11,11*REGBYTES(a0)
LOAD x12,12*REGBYTES(a0)
LOAD x13,13*REGBYTES(a0)
LOAD x14,14*REGBYTES(a0)
LOAD x15,15*REGBYTES(a0)
LOAD x16,16*REGBYTES(a0)
LOAD x17,17*REGBYTES(a0)
LOAD x18,18*REGBYTES(a0)
LOAD x19,19*REGBYTES(a0)
LOAD x20,20*REGBYTES(a0)
LOAD x21,21*REGBYTES(a0)
LOAD x22,22*REGBYTES(a0)
LOAD x23,23*REGBYTES(a0)
LOAD x24,24*REGBYTES(a0)
LOAD x25,25*REGBYTES(a0)
LOAD x26,26*REGBYTES(a0)
LOAD x27,27*REGBYTES(a0)
LOAD x28,28*REGBYTES(a0)
LOAD x29,29*REGBYTES(a0)
LOAD x30,30*REGBYTES(a0)
LOAD x31,31*REGBYTES(a0)
LOAD a0,10*REGBYTES(a0)
sret
.global trap_entry
.align 2
trap_entry:
csrrw sp, sscratch, sp
# save gprs
STORE x1,1*REGBYTES(sp)
STORE x3,3*REGBYTES(sp)
STORE x4,4*REGBYTES(sp)
STORE x5,5*REGBYTES(sp)
STORE x6,6*REGBYTES(sp)
STORE x7,7*REGBYTES(sp)
STORE x8,8*REGBYTES(sp)
STORE x9,9*REGBYTES(sp)
STORE x10,10*REGBYTES(sp)
STORE x11,11*REGBYTES(sp)
STORE x12,12*REGBYTES(sp)
STORE x13,13*REGBYTES(sp)
STORE x14,14*REGBYTES(sp)
STORE x15,15*REGBYTES(sp)
STORE x16,16*REGBYTES(sp)
STORE x17,17*REGBYTES(sp)
STORE x18,18*REGBYTES(sp)
STORE x19,19*REGBYTES(sp)
STORE x20,20*REGBYTES(sp)
STORE x21,21*REGBYTES(sp)
STORE x22,22*REGBYTES(sp)
STORE x23,23*REGBYTES(sp)
STORE x24,24*REGBYTES(sp)
STORE x25,25*REGBYTES(sp)
STORE x26,26*REGBYTES(sp)
STORE x27,27*REGBYTES(sp)
STORE x28,28*REGBYTES(sp)
STORE x29,29*REGBYTES(sp)
STORE x30,30*REGBYTES(sp)
STORE x31,31*REGBYTES(sp)
csrrw t0,sscratch,sp
STORE t0,2*REGBYTES(sp)
# get sr, epc, badvaddr, cause
csrr t0,sstatus
STORE t0,32*REGBYTES(sp)
csrr t0,sepc
STORE t0,33*REGBYTES(sp)
csrr t0,stval
STORE t0,34*REGBYTES(sp)
csrr t0,scause
STORE t0,35*REGBYTES(sp)
move a0, sp
j handle_trap

View File

@@ -0,0 +1,16 @@
OUTPUT_ARCH( "riscv" )
ENTRY(_start)
SECTIONS
{
. = 0x80000000;
.text.init : { *(.text.init) }
. = ALIGN(0x1000);
.tohost : { *(.tohost) }
. = ALIGN(0x1000);
.text : { *(.text) }
. = ALIGN(0x1000);
.data : { *(.data) }
.bss : { *(.bss) }
_end = .;
}

View File

@@ -0,0 +1,98 @@
// See LICENSE for license details.
#ifndef _ENV_VIRTUAL_SINGLE_CORE_H
#define _ENV_VIRTUAL_SINGLE_CORE_H
#include "riscv_test_p.h"
//-----------------------------------------------------------------------
// Begin Macro
//-----------------------------------------------------------------------
#undef RVTEST_FP_ENABLE
#define RVTEST_FP_ENABLE fssr x0
#undef RVTEST_VECTOR_ENABLE
#define RVTEST_VECTOR_ENABLE \
csrwi fcsr, 0; \
csrwi vcsr, 0;
#undef RVTEST_ZVE32X_ENABLE
#define RVTEST_ZVE32X_ENABLE \
csrwi vcsr, 0;
#undef RVTEST_CODE_BEGIN
#define RVTEST_CODE_BEGIN \
.text; \
.global extra_boot; \
extra_boot: \
EXTRA_INIT \
ret; \
.global trap_filter; \
trap_filter: \
FILTER_TRAP \
li a0, 0; \
ret; \
.global pf_filter; \
pf_filter: \
FILTER_PAGE_FAULT \
li a0, 0; \
ret; \
.global userstart; \
userstart: \
init
//-----------------------------------------------------------------------
// Pass/Fail Macro
//-----------------------------------------------------------------------
#undef RVTEST_PASS
#define RVTEST_PASS li a0, 1; scall
#undef RVTEST_FAIL
#define RVTEST_FAIL sll a0, TESTNUM, 1; 1:beqz a0, 1b; or a0, a0, 1; scall;
//-----------------------------------------------------------------------
// Data Section Macro
//-----------------------------------------------------------------------
#undef RVTEST_DATA_END
#define RVTEST_DATA_END
//-----------------------------------------------------------------------
// Supervisor mode definitions and macros
//-----------------------------------------------------------------------
#ifndef LFSR_BITS
#define LFSR_BITS 6
#endif
#define MAX_TEST_PAGES ((1 << LFSR_BITS)-1) // this must be the period of the LFSR below
#define LFSR_NEXT(x) (((((x)^((x)>>1)) & 1) << (LFSR_BITS-1)) | ((x) >> 1))
#define PGSHIFT 12
#define PGSIZE (1UL << PGSHIFT)
#define SIZEOF_TRAPFRAME_T ((__riscv_xlen / 8) * 36)
#ifndef __ASSEMBLER__
typedef unsigned long pte_t;
#define LEVELS (sizeof(pte_t) == sizeof(uint64_t) ? 3 : 2)
#define PTIDXBITS (PGSHIFT - (sizeof(pte_t) == 8 ? 3 : 2))
#define VPN_BITS (PTIDXBITS * LEVELS)
#define VA_BITS (VPN_BITS + PGSHIFT)
#define PTES_PER_PT (1UL << RISCV_PGLEVEL_BITS)
#define MEGAPAGE_SIZE (PTES_PER_PT * PGSIZE)
typedef struct
{
long gpr[32];
long sr;
long epc;
long badvaddr;
long cause;
} trapframe_t;
#endif
#endif

View File

@@ -0,0 +1,295 @@
// See LICENSE for license details.
#ifndef _ENV_PHYSICAL_SINGLE_CORE_H
#define _ENV_PHYSICAL_SINGLE_CORE_H
#include "encoding.h"
//-----------------------------------------------------------------------
// Begin Macro
//-----------------------------------------------------------------------
#define RVTEST_RV64U \
.macro init; \
.endm
#define RVTEST_RV64UF \
.macro init; \
RVTEST_FP_ENABLE; \
.endm
#define RVTEST_RV64UV \
.macro init; \
RVTEST_VECTOR_ENABLE; \
.endm
#define RVTEST_RV64UVX \
.macro init; \
RVTEST_ZVE32X_ENABLE; \
.endm
#define RVTEST_RV32U \
.macro init; \
.endm
#define RVTEST_RV32UF \
.macro init; \
RVTEST_FP_ENABLE; \
.endm
#define RVTEST_RV32UV \
.macro init; \
RVTEST_VECTOR_ENABLE; \
.endm
#define RVTEST_RV32UVX \
.macro init; \
RVTEST_ZVE32X_ENABLE; \
.endm
#define RVTEST_RV64M \
.macro init; \
RVTEST_ENABLE_MACHINE; \
.endm
#define RVTEST_RV64S \
.macro init; \
RVTEST_ENABLE_SUPERVISOR; \
.endm
#define RVTEST_RV32M \
.macro init; \
RVTEST_ENABLE_MACHINE; \
.endm
#define RVTEST_RV32S \
.macro init; \
RVTEST_ENABLE_SUPERVISOR; \
.endm
#if __riscv_xlen == 64
# define CHECK_XLEN li a0, 1; slli a0, a0, 31; bgez a0, 1f; RVTEST_PASS; 1:
#else
# define CHECK_XLEN li a0, 1; slli a0, a0, 31; bltz a0, 1f; RVTEST_PASS; 1:
#endif
#define INIT_XREG \
li x1, 0; \
li x2, 0; \
li x3, 0; \
li x4, 0; \
li x5, 0; \
li x6, 0; \
li x7, 0; \
li x8, 0; \
li x9, 0; \
li x10, 0; \
li x11, 0; \
li x12, 0; \
li x13, 0; \
li x14, 0; \
li x15, 0; \
li x16, 0; \
li x17, 0; \
li x18, 0; \
li x19, 0; \
li x20, 0; \
li x21, 0; \
li x22, 0; \
li x23, 0; \
li x24, 0; \
li x25, 0; \
li x26, 0; \
li x27, 0; \
li x28, 0; \
li x29, 0; \
li x30, 0; \
li x31, 0;
#define INIT_PMP \
la t0, 1f; \
csrw mtvec, t0; \
/* Set up a PMP to permit all accesses */ \
li t0, (1 << (31 + (__riscv_xlen / 64) * (53 - 31))) - 1; \
csrw pmpaddr0, t0; \
li t0, PMP_NAPOT | PMP_R | PMP_W | PMP_X; \
csrw pmpcfg0, t0; \
.align 2; \
1:
#define INIT_RNMI \
la t0, 1f; \
csrw mtvec, t0; \
csrwi CSR_MNSTATUS, MNSTATUS_NMIE; \
.align 2; \
1:
#define INIT_SATP \
la t0, 1f; \
csrw mtvec, t0; \
csrwi satp, 0; \
.align 2; \
1:
#define DELEGATE_NO_TRAPS \
csrwi mie, 0; \
la t0, 1f; \
csrw mtvec, t0; \
csrwi medeleg, 0; \
csrwi mideleg, 0; \
.align 2; \
1:
#define RVTEST_ENABLE_SUPERVISOR \
li a0, MSTATUS_MPP & (MSTATUS_MPP >> 1); \
csrs mstatus, a0; \
li a0, SIP_SSIP | SIP_STIP; \
csrs mideleg, a0; \
#define RVTEST_ENABLE_MACHINE \
li a0, MSTATUS_MPP; \
csrs mstatus, a0; \
#define RVTEST_FP_ENABLE \
li a0, MSTATUS_FS & (MSTATUS_FS >> 1); \
csrs mstatus, a0; \
csrwi fcsr, 0
#define RVTEST_VECTOR_ENABLE \
li a0, (MSTATUS_VS & (MSTATUS_VS >> 1)) | \
(MSTATUS_FS & (MSTATUS_FS >> 1)); \
csrs mstatus, a0; \
csrwi fcsr, 0; \
csrwi vcsr, 0;
#define RVTEST_ZVE32X_ENABLE \
li a0, (MSTATUS_VS & (MSTATUS_VS >> 1)); \
csrs mstatus, a0; \
csrwi vcsr, 0;
#define RISCV_MULTICORE_DISABLE \
csrr a0, mhartid; \
1: bnez a0, 1b
#define EXTRA_TVEC_USER
#define EXTRA_TVEC_MACHINE
#define EXTRA_INIT
#define EXTRA_INIT_TIMER
#define FILTER_TRAP
#define FILTER_PAGE_FAULT
#define INTERRUPT_HANDLER j other_exception /* No interrupts should occur */
#define RVTEST_CODE_BEGIN \
.section .text.init; \
.align 6; \
.weak stvec_handler; \
.weak mtvec_handler; \
.globl _start; \
_start: \
/* reset vector */ \
j reset_vector; \
.align 2; \
trap_vector: \
/* test whether the test came from pass/fail */ \
csrr t5, mcause; \
li t6, CAUSE_USER_ECALL; \
beq t5, t6, write_tohost; \
li t6, CAUSE_SUPERVISOR_ECALL; \
beq t5, t6, write_tohost; \
li t6, CAUSE_MACHINE_ECALL; \
beq t5, t6, write_tohost; \
/* if an mtvec_handler is defined, jump to it */ \
la t5, mtvec_handler; \
beqz t5, 1f; \
jr t5; \
/* was it an interrupt or an exception? */ \
1: csrr t5, mcause; \
bgez t5, handle_exception; \
INTERRUPT_HANDLER; \
handle_exception: \
/* we don't know how to handle whatever the exception was */ \
other_exception: \
/* some unhandlable exception occurred */ \
1: ori TESTNUM, TESTNUM, 1337; \
write_tohost: \
sw TESTNUM, tohost, t5; \
sw zero, tohost + 4, t5; \
j write_tohost; \
reset_vector: \
INIT_XREG; \
RISCV_MULTICORE_DISABLE; \
INIT_RNMI; \
INIT_SATP; \
INIT_PMP; \
DELEGATE_NO_TRAPS; \
li TESTNUM, 0; \
la t0, trap_vector; \
csrw mtvec, t0; \
CHECK_XLEN; \
/* if an stvec_handler is defined, delegate exceptions to it */ \
la t0, stvec_handler; \
beqz t0, 1f; \
csrw stvec, t0; \
li t0, (1 << CAUSE_LOAD_PAGE_FAULT) | \
(1 << CAUSE_STORE_PAGE_FAULT) | \
(1 << CAUSE_FETCH_PAGE_FAULT) | \
(1 << CAUSE_MISALIGNED_FETCH) | \
(1 << CAUSE_USER_ECALL) | \
(1 << CAUSE_BREAKPOINT); \
csrw medeleg, t0; \
1: csrwi mstatus, 0; \
init; \
EXTRA_INIT; \
EXTRA_INIT_TIMER; \
la t0, 1f; \
csrw mepc, t0; \
csrr a0, mhartid; \
mret; \
1:
//-----------------------------------------------------------------------
// End Macro
//-----------------------------------------------------------------------
#define RVTEST_CODE_END \
unimp
//-----------------------------------------------------------------------
// Pass/Fail Macro
//-----------------------------------------------------------------------
#define RVTEST_PASS \
fence; \
li TESTNUM, 1; \
li a7, 93; \
li a0, 0; \
ecall
#define TESTNUM gp
#define RVTEST_FAIL \
fence; \
1: beqz TESTNUM, 1b; \
sll TESTNUM, TESTNUM, 1; \
or TESTNUM, TESTNUM, 1; \
li a7, 93; \
addi a0, TESTNUM, 0; \
ecall
//-----------------------------------------------------------------------
// Data Section Macro
//-----------------------------------------------------------------------
#define EXTRA_DATA
#define RVTEST_DATA_BEGIN \
EXTRA_DATA \
.pushsection .tohost,"aw",@progbits; \
.align 6; .global tohost; tohost: .dword 0; .size tohost, 8; \
.align 6; .global fromhost; fromhost: .dword 0; .size fromhost, 8;\
.popsection; \
.align 4; .global begin_signature; begin_signature:
#define RVTEST_DATA_END .align 4; .global end_signature; end_signature:
#endif

View File

@@ -0,0 +1,114 @@
#include <string.h>
#include <stdint.h>
#include <ctype.h>
void* memcpy(void* dest, const void* src, size_t len)
{
if ((((uintptr_t)dest | (uintptr_t)src | len) & (sizeof(uintptr_t)-1)) == 0) {
const uintptr_t* s = src;
uintptr_t *d = dest;
while (d < (uintptr_t*)(dest + len))
*d++ = *s++;
} else {
const char* s = src;
char *d = dest;
while (d < (char*)(dest + len))
*d++ = *s++;
}
return dest;
}
void* memset(void* dest, int byte, size_t len)
{
if ((((uintptr_t)dest | len) & (sizeof(uintptr_t)-1)) == 0) {
uintptr_t word = byte & 0xFF;
word |= word << 8;
word |= word << 16;
word |= word << 16 << 16;
uintptr_t *d = dest;
while (d < (uintptr_t*)(dest + len))
*d++ = word;
} else {
char *d = dest;
while (d < (char*)(dest + len))
*d++ = byte;
}
return dest;
}
size_t strlen(const char *s)
{
const char *p = s;
while (*p)
p++;
return p - s;
}
int strcmp(const char* s1, const char* s2)
{
unsigned char c1, c2;
do {
c1 = *s1++;
c2 = *s2++;
} while (c1 != 0 && c1 == c2);
return c1 - c2;
}
int memcmp(const void* s1, const void* s2, size_t n)
{
if ((((uintptr_t)s1 | (uintptr_t)s2) & (sizeof(uintptr_t)-1)) == 0) {
const uintptr_t* u1 = s1;
const uintptr_t* u2 = s2;
const uintptr_t* end = u1 + (n / sizeof(uintptr_t));
while (u1 < end) {
if (*u1 != *u2)
break;
u1++;
u2++;
}
n -= (const void*)u1 - s1;
s1 = u1;
s2 = u2;
}
while (n--) {
unsigned char c1 = *(const unsigned char*)s1++;
unsigned char c2 = *(const unsigned char*)s2++;
if (c1 != c2)
return c1 - c2;
}
return 0;
}
char* strcpy(char* dest, const char* src)
{
char* d = dest;
while ((*d++ = *src++))
;
return dest;
}
long atol(const char* str)
{
long res = 0;
int sign = 0;
while (*str == ' ')
str++;
if (*str == '-' || *str == '+') {
sign = *str == '-';
str++;
}
while (*str) {
res *= 10;
res += *str++ - '0';
}
return sign ? -res : res;
}

View File

@@ -0,0 +1,25 @@
#include "riscv_test.h"
#include "test_macros.h"
RVTEST_RV64U # Define TVM used by program.
# Test code region.
RVTEST_CODE_BEGIN # Start of test code.
RVTEST_PASS # Signal success.
fail:
RVTEST_FAIL
RVTEST_CODE_END # End of test code.
# Input data section.
# This section is optional, and this data is NOT saved in the output.
.data
.align 3
testdata:
.dword 41
# Output data section.
RVTEST_DATA_BEGIN # Start of test output data region.
.align 3
result:
.dword -1
RVTEST_DATA_END # End of test output data region.

BIN
Tests/isa/Cprograms/testC Executable file

Binary file not shown.

View File

@@ -0,0 +1,832 @@
// See LICENSE for license details.
#ifndef __TEST_MACROS_SCALAR_H
#define __TEST_MACROS_SCALAR_H
#-----------------------------------------------------------------------
# Helper macros
#-----------------------------------------------------------------------
#define MASK_XLEN(x) ((x) & ((1 << (__riscv_xlen - 1) << 1) - 1))
#define TEST_CASE( testnum, testreg, correctval, code... ) \
test_ ## testnum: \
li TESTNUM, testnum; \
code; \
li x7, MASK_XLEN(correctval); \
bne testreg, x7, fail;
# We use a macro hack to simpify code generation for various numbers
# of bubble cycles.
#define TEST_INSERT_NOPS_0
#define TEST_INSERT_NOPS_1 nop; TEST_INSERT_NOPS_0
#define TEST_INSERT_NOPS_2 nop; TEST_INSERT_NOPS_1
#define TEST_INSERT_NOPS_3 nop; TEST_INSERT_NOPS_2
#define TEST_INSERT_NOPS_4 nop; TEST_INSERT_NOPS_3
#define TEST_INSERT_NOPS_5 nop; TEST_INSERT_NOPS_4
#define TEST_INSERT_NOPS_6 nop; TEST_INSERT_NOPS_5
#define TEST_INSERT_NOPS_7 nop; TEST_INSERT_NOPS_6
#define TEST_INSERT_NOPS_8 nop; TEST_INSERT_NOPS_7
#define TEST_INSERT_NOPS_9 nop; TEST_INSERT_NOPS_8
#define TEST_INSERT_NOPS_10 nop; TEST_INSERT_NOPS_9
#if __riscv_xlen == 64
#define LOAD_PTR ld
#define STORE_PTR sd
#else
#define LOAD_PTR lw
#define STORE_PTR sw
#endif
#-----------------------------------------------------------------------
# RV64UI MACROS
#-----------------------------------------------------------------------
#-----------------------------------------------------------------------
# Tests for instructions with immediate operand
#-----------------------------------------------------------------------
#define SEXT_IMM(x) ((x) | (-(((x) >> 11) & 1) << 11))
#define TEST_IMM_OP( testnum, inst, result, val1, imm ) \
TEST_CASE( testnum, x14, result, \
li x13, MASK_XLEN(val1); \
inst x14, x13, SEXT_IMM(imm); \
)
#define TEST_IMM_SRC1_EQ_DEST( testnum, inst, result, val1, imm ) \
TEST_CASE( testnum, x11, result, \
li x11, MASK_XLEN(val1); \
inst x11, x11, SEXT_IMM(imm); \
)
#define TEST_IMM_DEST_BYPASS( testnum, nop_cycles, inst, result, val1, imm ) \
TEST_CASE( testnum, x6, result, \
li x4, 0; \
1: li x1, MASK_XLEN(val1); \
inst x14, x1, SEXT_IMM(imm); \
TEST_INSERT_NOPS_ ## nop_cycles \
addi x6, x14, 0; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
)
#define TEST_IMM_SRC1_BYPASS( testnum, nop_cycles, inst, result, val1, imm ) \
TEST_CASE( testnum, x14, result, \
li x4, 0; \
1: li x1, MASK_XLEN(val1); \
TEST_INSERT_NOPS_ ## nop_cycles \
inst x14, x1, SEXT_IMM(imm); \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
)
#define TEST_IMM_ZEROSRC1( testnum, inst, result, imm ) \
TEST_CASE( testnum, x1, result, \
inst x1, x0, SEXT_IMM(imm); \
)
#define TEST_IMM_ZERODEST( testnum, inst, val1, imm ) \
TEST_CASE( testnum, x0, 0, \
li x1, MASK_XLEN(val1); \
inst x0, x1, SEXT_IMM(imm); \
)
#-----------------------------------------------------------------------
# Tests for an instruction with register operands
#-----------------------------------------------------------------------
#define TEST_R_OP( testnum, inst, result, val1 ) \
TEST_CASE( testnum, x14, result, \
li x1, val1; \
inst x14, x1; \
)
#define TEST_R_SRC1_EQ_DEST( testnum, inst, result, val1 ) \
TEST_CASE( testnum, x1, result, \
li x1, val1; \
inst x1, x1; \
)
#define TEST_R_DEST_BYPASS( testnum, nop_cycles, inst, result, val1 ) \
TEST_CASE( testnum, x6, result, \
li x4, 0; \
1: li x1, val1; \
inst x14, x1; \
TEST_INSERT_NOPS_ ## nop_cycles \
addi x6, x14, 0; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
)
#-----------------------------------------------------------------------
# Tests for an instruction with register-register operands
#-----------------------------------------------------------------------
#define TEST_RR_OP( testnum, inst, result, val1, val2 ) \
TEST_CASE( testnum, x14, result, \
li x11, MASK_XLEN(val1); \
li x12, MASK_XLEN(val2); \
inst x14, x11, x12; \
)
#define TEST_RR_SRC1_EQ_DEST( testnum, inst, result, val1, val2 ) \
TEST_CASE( testnum, x11, result, \
li x11, MASK_XLEN(val1); \
li x12, MASK_XLEN(val2); \
inst x11, x11, x12; \
)
#define TEST_RR_SRC2_EQ_DEST( testnum, inst, result, val1, val2 ) \
TEST_CASE( testnum, x12, result, \
li x11, MASK_XLEN(val1); \
li x12, MASK_XLEN(val2); \
inst x12, x11, x12; \
)
#define TEST_RR_SRC12_EQ_DEST( testnum, inst, result, val1 ) \
TEST_CASE( testnum, x11, result, \
li x11, MASK_XLEN(val1); \
inst x11, x11, x11; \
)
#define TEST_RR_DEST_BYPASS( testnum, nop_cycles, inst, result, val1, val2 ) \
TEST_CASE( testnum, x6, result, \
li x4, 0; \
1: li x1, MASK_XLEN(val1); \
li x2, MASK_XLEN(val2); \
inst x14, x1, x2; \
TEST_INSERT_NOPS_ ## nop_cycles \
addi x6, x14, 0; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
)
#define TEST_RR_SRC12_BYPASS( testnum, src1_nops, src2_nops, inst, result, val1, val2 ) \
TEST_CASE( testnum, x14, result, \
li x4, 0; \
1: li x1, MASK_XLEN(val1); \
TEST_INSERT_NOPS_ ## src1_nops \
li x2, MASK_XLEN(val2); \
TEST_INSERT_NOPS_ ## src2_nops \
inst x14, x1, x2; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
)
#define TEST_RR_SRC21_BYPASS( testnum, src1_nops, src2_nops, inst, result, val1, val2 ) \
TEST_CASE( testnum, x14, result, \
li x4, 0; \
1: li x2, MASK_XLEN(val2); \
TEST_INSERT_NOPS_ ## src1_nops \
li x1, MASK_XLEN(val1); \
TEST_INSERT_NOPS_ ## src2_nops \
inst x14, x1, x2; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
)
#define TEST_RR_ZEROSRC1( testnum, inst, result, val ) \
TEST_CASE( testnum, x2, result, \
li x1, MASK_XLEN(val); \
inst x2, x0, x1; \
)
#define TEST_RR_ZEROSRC2( testnum, inst, result, val ) \
TEST_CASE( testnum, x2, result, \
li x1, MASK_XLEN(val); \
inst x2, x1, x0; \
)
#define TEST_RR_ZEROSRC12( testnum, inst, result ) \
TEST_CASE( testnum, x1, result, \
inst x1, x0, x0; \
)
#define TEST_RR_ZERODEST( testnum, inst, val1, val2 ) \
TEST_CASE( testnum, x0, 0, \
li x1, MASK_XLEN(val1); \
li x2, MASK_XLEN(val2); \
inst x0, x1, x2; \
)
#-----------------------------------------------------------------------
# Test memory instructions
#-----------------------------------------------------------------------
#define TEST_LD_OP( testnum, inst, result, offset, base ) \
TEST_CASE( testnum, x14, result, \
li x15, result; /* Tell the exception handler the expected result. */ \
la x2, base; \
inst x14, offset(x2); \
)
#define TEST_ST_OP( testnum, load_inst, store_inst, result, offset, base ) \
TEST_CASE( testnum, x14, result, \
la x2, base; \
li x1, result; \
la x15, 7f; /* Tell the exception handler how to skip this test. */ \
store_inst x1, offset(x2); \
load_inst x14, offset(x2); \
j 8f; \
7: \
/* Set up the correct result for TEST_CASE(). */ \
mv x14, x1; \
8: \
)
#define TEST_LD_DEST_BYPASS( testnum, nop_cycles, inst, result, offset, base ) \
test_ ## testnum: \
li TESTNUM, testnum; \
li x4, 0; \
1: la x13, base; \
inst x14, offset(x13); \
TEST_INSERT_NOPS_ ## nop_cycles \
addi x6, x14, 0; \
li x7, result; \
bne x6, x7, fail; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b; \
#define TEST_LD_SRC1_BYPASS( testnum, nop_cycles, inst, result, offset, base ) \
test_ ## testnum: \
li TESTNUM, testnum; \
li x4, 0; \
1: la x13, base; \
TEST_INSERT_NOPS_ ## nop_cycles \
inst x14, offset(x13); \
li x7, result; \
bne x14, x7, fail; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
#define TEST_ST_SRC12_BYPASS( testnum, src1_nops, src2_nops, load_inst, store_inst, result, offset, base ) \
test_ ## testnum: \
li TESTNUM, testnum; \
li x4, 0; \
1: li x13, result; \
TEST_INSERT_NOPS_ ## src1_nops \
la x12, base; \
TEST_INSERT_NOPS_ ## src2_nops \
store_inst x13, offset(x12); \
load_inst x14, offset(x12); \
li x7, result; \
bne x14, x7, fail; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
#define TEST_ST_SRC21_BYPASS( testnum, src1_nops, src2_nops, load_inst, store_inst, result, offset, base ) \
test_ ## testnum: \
li TESTNUM, testnum; \
li x4, 0; \
1: la x2, base; \
TEST_INSERT_NOPS_ ## src1_nops \
li x1, result; \
TEST_INSERT_NOPS_ ## src2_nops \
store_inst x1, offset(x2); \
load_inst x14, offset(x2); \
li x7, result; \
bne x14, x7, fail; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
#define TEST_LD_ST_BYPASS(testnum, load_inst, store_inst, result, offset, base) \
test_ ## testnum: \
li TESTNUM, testnum; \
la x2, base; \
li x1, result; \
store_inst x1, offset(x2); \
load_inst x14, offset(x2); \
store_inst x14, offset(x2); \
load_inst x2, offset(x2); \
li x7, result; \
bne x2, x7, fail; \
la x2, base; \
STORE_PTR x2,8(x2); \
LOAD_PTR x4,8(x2); \
store_inst x1, offset(x4); \
bne x4, x2, fail; \
load_inst x14, offset(x4); \
bne x14, x7, fail; \
#define TEST_ST_LD_BYPASS(testnum, load_inst, store_inst, result, offset, base) \
test_ ## testnum: \
li TESTNUM, testnum; \
la x2, base; \
li x1, result; \
store_inst x1, offset(x2); \
load_inst x14, offset(x2); \
li x7, result; \
bne x14, x7, fail; \
#define TEST_BR2_OP_TAKEN(testnum, inst, val1, val2 ) \
test_ ## testnum: \
li TESTNUM, testnum; \
li x1, val1; \
li x2, val2; \
inst x1, x2, 2f; \
bne x0, TESTNUM, fail; \
1: bne x0, TESTNUM, 3f; \
2: inst x1, x2, 1b; \
bne x0, TESTNUM, fail; \
3:
#define TEST_BR2_OP_NOTTAKEN( testnum, inst, val1, val2 ) \
test_ ## testnum: \
li TESTNUM, testnum; \
li x1, val1; \
li x2, val2; \
inst x1, x2, 1f; \
bne x0, TESTNUM, 2f; \
1: bne x0, TESTNUM, fail; \
2: inst x1, x2, 1b; \
3:
#define TEST_BR2_SRC12_BYPASS( testnum, src1_nops, src2_nops, inst, val1, val2 ) \
test_ ## testnum: \
li TESTNUM, testnum; \
li x4, 0; \
1: li x1, val1; \
TEST_INSERT_NOPS_ ## src1_nops \
li x2, val2; \
TEST_INSERT_NOPS_ ## src2_nops \
inst x1, x2, fail; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
#define TEST_BR2_SRC21_BYPASS( testnum, src1_nops, src2_nops, inst, val1, val2 ) \
test_ ## testnum: \
li TESTNUM, testnum; \
li x4, 0; \
1: li x2, val2; \
TEST_INSERT_NOPS_ ## src1_nops \
li x1, val1; \
TEST_INSERT_NOPS_ ## src2_nops \
inst x1, x2, fail; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
#-----------------------------------------------------------------------
# Test jump instructions
#-----------------------------------------------------------------------
#define TEST_JR_SRC1_BYPASS( testnum, nop_cycles, inst ) \
test_ ## testnum: \
li TESTNUM, testnum; \
li x4, 0; \
1: la x6, 2f; \
TEST_INSERT_NOPS_ ## nop_cycles \
inst x6; \
bne x0, TESTNUM, fail; \
2: addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
#define TEST_JALR_SRC1_BYPASS( testnum, nop_cycles, inst ) \
test_ ## testnum: \
li TESTNUM, testnum; \
li x4, 0; \
1: la x6, 2f; \
TEST_INSERT_NOPS_ ## nop_cycles \
inst x13, x6, 0; \
bne x0, TESTNUM, fail; \
2: addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
#-----------------------------------------------------------------------
# RV64UF MACROS
#-----------------------------------------------------------------------
#-----------------------------------------------------------------------
# Tests floating-point instructions
#-----------------------------------------------------------------------
# 16-bit half precision (float16)
#define qNaNh 0x7e00
#define sNaNh 0x7c01
#define Infh 0x7c00
#define nInfh 0xfc00
# 32-bit single precision (float)
#define qNaNf 0x7fc00000
#define sNaNf 0x7f800001
#define Inff 0x7f800000
#define nInff 0xff800000
# 64-bit double precision (double)
#define qNaNd 0x7ff8000000000000
#define sNaNd 0x7ff0000000000001
#define Infd 0x7ff0000000000000
#define nInfd 0xfff0000000000000
#define TEST_FP_OP_H_INTERNAL( testnum, flags, result, val1, val2, val3, code... ) \
test_ ## testnum: \
li TESTNUM, testnum; \
la a0, test_ ## testnum ## _data ;\
flh f10, 0(a0); \
flh f11, 2(a0); \
flh f12, 4(a0); \
lh a3, 6(a0); \
code; \
fsflags a1, x0; \
li a2, flags; \
bne a0, a3, fail; \
bne a1, a2, fail; \
.pushsection .data; \
.align 1; \
test_ ## testnum ## _data: \
.val1; \
.val2; \
.val3; \
.result; \
.popsection
#define TEST_FP_OP_S_INTERNAL( testnum, flags, result, val1, val2, val3, code... ) \
test_ ## testnum: \
li TESTNUM, testnum; \
la a0, test_ ## testnum ## _data ;\
flw f10, 0(a0); \
flw f11, 4(a0); \
flw f12, 8(a0); \
lw a3, 12(a0); \
code; \
fsflags a1, x0; \
li a2, flags; \
bne a0, a3, fail; \
bne a1, a2, fail; \
.pushsection .data; \
.align 2; \
test_ ## testnum ## _data: \
.val1; \
.val2; \
.val3; \
.result; \
.popsection
#define TEST_FP_OP_D_INTERNAL( testnum, flags, result, val1, val2, val3, code... ) \
test_ ## testnum: \
li TESTNUM, testnum; \
la a0, test_ ## testnum ## _data ;\
fld f10, 0(a0); \
fld f11, 8(a0); \
fld f12, 16(a0); \
ld a3, 24(a0); \
code; \
fsflags a1, x0; \
li a2, flags; \
bne a0, a3, fail; \
bne a1, a2, fail; \
.pushsection .data; \
.align 3; \
test_ ## testnum ## _data: \
.val1; \
.val2; \
.val3; \
.result; \
.popsection
// TODO: assign a separate mem location for the comparison address?
#define TEST_FP_OP_D32_INTERNAL( testnum, flags, result, val1, val2, val3, code... ) \
test_ ## testnum: \
li TESTNUM, testnum; \
la a0, test_ ## testnum ## _data ;\
fld f10, 0(a0); \
fld f11, 8(a0); \
fld f12, 16(a0); \
lw a3, 24(a0); \
lw t1, 28(a0); \
code; \
fsflags a1, x0; \
li a2, flags; \
bne a0, a3, fail; \
bne t1, t2, fail; \
bne a1, a2, fail; \
.pushsection .data; \
.align 3; \
test_ ## testnum ## _data: \
.val1; \
.val2; \
.val3; \
.result; \
.popsection
#define TEST_FCVT_S_D32( testnum, result, val1 ) \
TEST_FP_OP_D32_INTERNAL( testnum, 0, double result, double val1, double 0, double 0, \
fcvt.s.d f13, f10; fcvt.d.s f13, f13; fsd f13, 0(a0); lw t2, 4(a0); lw a0, 0(a0))
#define TEST_FCVT_S_D( testnum, result, val1 ) \
TEST_FP_OP_D_INTERNAL( testnum, 0, double result, double val1, double 0, double 0, \
fcvt.s.d f13, f10; fcvt.d.s f13, f13; fmv.x.d a0, f13)
#define TEST_FCVT_D_S( testnum, result, val1 ) \
TEST_FP_OP_S_INTERNAL( testnum, 0, float result, float val1, float 0, float 0, \
fcvt.d.s f13, f10; fcvt.s.d f13, f13; fmv.x.s a0, f13)
#define TEST_FCVT_H_S( testnum, result, val1 ) \
TEST_FP_OP_H_INTERNAL( testnum, 0, float16 result, float16 val1, float16 0, float16 0, \
fcvt.s.h f13, f10; fcvt.h.s f13, f13; fmv.x.h a0, f13)
#define TEST_FCVT_H_D( testnum, result, val1 ) \
TEST_FP_OP_H_INTERNAL( testnum, 0, float16 result, float16 val1, float16 0, float16 0, \
fcvt.d.h f13, f10; fcvt.h.d f13, f13; fmv.x.h a0, f13)
#define TEST_FP_OP1_H( testnum, inst, flags, result, val1 ) \
TEST_FP_OP_H_INTERNAL( testnum, flags, float16 result, float16 val1, float16 0, float16 0, \
inst f13, f10; fmv.x.h a0, f13;)
#define TEST_FP_OP1_S( testnum, inst, flags, result, val1 ) \
TEST_FP_OP_S_INTERNAL( testnum, flags, float result, float val1, float 0, float 0, \
inst f13, f10; fmv.x.s a0, f13)
#define TEST_FP_OP1_D32( testnum, inst, flags, result, val1 ) \
TEST_FP_OP_D32_INTERNAL( testnum, flags, double result, double val1, double 0, double 0, \
inst f13, f10; fsd f13, 0(a0); lw t2, 4(a0); lw a0, 0(a0))
// ^: store computation result in address from a0, load high-word into t2
#define TEST_FP_OP1_D( testnum, inst, flags, result, val1 ) \
TEST_FP_OP_D_INTERNAL( testnum, flags, double result, double val1, double 0, double 0, \
inst f13, f10; fmv.x.d a0, f13)
#define TEST_FP_OP1_S_DWORD_RESULT( testnum, inst, flags, result, val1 ) \
TEST_FP_OP_S_INTERNAL( testnum, flags, dword result, float val1, float 0, float 0, \
inst f13, f10; fmv.x.s a0, f13)
#define TEST_FP_OP1_H_DWORD_RESULT( testnum, inst, flags, result, val1 ) \
TEST_FP_OP_H_INTERNAL( testnum, flags, word result, float16 val1, float16 0, float16 0, \
inst f13, f10; fmv.x.h a0, f13)
#define TEST_FP_OP1_D32_DWORD_RESULT( testnum, inst, flags, result, val1 ) \
TEST_FP_OP_D32_INTERNAL( testnum, flags, dword result, double val1, double 0, double 0, \
inst f13, f10; fsd f13, 0(a0); lw t2, 4(a0); lw a0, 0(a0))
// ^: store computation result in address from a0, load high-word into t2
#define TEST_FP_OP1_D_DWORD_RESULT( testnum, inst, flags, result, val1 ) \
TEST_FP_OP_D_INTERNAL( testnum, flags, dword result, double val1, double 0, double 0, \
inst f13, f10; fmv.x.d a0, f13)
#define TEST_FP_OP2_S( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_S_INTERNAL( testnum, flags, float result, float val1, float val2, float 0, \
inst f13, f10, f11; fmv.x.s a0, f13)
#define TEST_FP_OP2_S_HEX( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_S_INTERNAL( testnum, flags, word result, word val1, word val2, float 0, \
inst f13, f10, f11; fmv.x.s a0, f13)
#define TEST_FP_OP2_H( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_H_INTERNAL( testnum, flags, float16 result, float16 val1, float16 val2, float16 0, \
inst f13, f10, f11; fmv.x.h a0, f13)
#define TEST_FP_OP2_H_HEX( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_H_INTERNAL( testnum, flags, half result, half val1, half val2, float16 0, \
inst f13, f10, f11; fmv.x.h a0, f13)
#define TEST_FP_OP2_D32( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_D32_INTERNAL( testnum, flags, double result, double val1, double val2, double 0, \
inst f13, f10, f11; fsd f13, 0(a0); lw t2, 4(a0); lw a0, 0(a0))
// ^: store computation result in address from a0, load high-word into t2
#define TEST_FP_OP2_D32_HEX( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_D32_INTERNAL( testnum, flags, dword result, dword val1, dword val2, double 0, \
inst f13, f10, f11; fsd f13, 0(a0); lw t2, 4(a0); lw a0, 0(a0))
#define TEST_FP_OP2_D( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_D_INTERNAL( testnum, flags, double result, double val1, double val2, double 0, \
inst f13, f10, f11; fmv.x.d a0, f13)
#define TEST_FP_OP2_D_HEX( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_D_INTERNAL( testnum, flags, dword result, dword val1, dword val2, double 0, \
inst f13, f10, f11; fmv.x.d a0, f13)
#define TEST_FP_OP3_S( testnum, inst, flags, result, val1, val2, val3 ) \
TEST_FP_OP_S_INTERNAL( testnum, flags, float result, float val1, float val2, float val3, \
inst f13, f10, f11, f12; fmv.x.s a0, f13)
#define TEST_FP_OP3_H( testnum, inst, flags, result, val1, val2, val3 ) \
TEST_FP_OP_H_INTERNAL( testnum, flags, float16 result, float16 val1, float16 val2, float16 val3, \
inst f13, f10, f11, f12; fmv.x.h a0, f13)
#define TEST_FP_OP3_D32( testnum, inst, flags, result, val1, val2, val3 ) \
TEST_FP_OP_D32_INTERNAL( testnum, flags, double result, double val1, double val2, double val3, \
inst f13, f10, f11, f12; fsd f13, 0(a0); lw t2, 4(a0); lw a0, 0(a0))
// ^: store computation result in address from a0, load high-word into t2
#define TEST_FP_OP3_D( testnum, inst, flags, result, val1, val2, val3 ) \
TEST_FP_OP_D_INTERNAL( testnum, flags, double result, double val1, double val2, double val3, \
inst f13, f10, f11, f12; fmv.x.d a0, f13)
#define TEST_FP_INT_OP_S( testnum, inst, flags, result, val1, rm ) \
TEST_FP_OP_S_INTERNAL( testnum, flags, word result, float val1, float 0, float 0, \
inst a0, f10, rm)
#define TEST_FP_INT_OP_H( testnum, inst, flags, result, val1, rm ) \
TEST_FP_OP_H_INTERNAL( testnum, flags, word result, float16 val1, float16 0, float16 0, \
inst a0, f10, rm)
#define TEST_FP_INT_OP_D32( testnum, inst, flags, result, val1, rm ) \
TEST_FP_OP_D32_INTERNAL( testnum, flags, dword result, double val1, double 0, double 0, \
inst a0, f10, rm; li t2, ((result) << 32 >> 63) * -1)
#define TEST_FP_INT_OP_D( testnum, inst, flags, result, val1, rm ) \
TEST_FP_OP_D_INTERNAL( testnum, flags, dword result, double val1, double 0, double 0, \
inst a0, f10, rm)
#define TEST_FP_CMP_OP_S( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_S_INTERNAL( testnum, flags, word result, float val1, float val2, float 0, \
inst a0, f10, f11)
#define TEST_FP_CMP_OP_S_HEX( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_S_INTERNAL( testnum, flags, word result, word val1, word val2, float 0, \
inst a0, f10, f11)
#define TEST_FP_CMP_OP_H( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_H_INTERNAL( testnum, flags, hword result, float16 val1, float16 val2, float16 0, \
inst a0, f10, f11)
#define TEST_FP_CMP_OP_H_HEX( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_H_INTERNAL( testnum, flags, hword result, half val1, half val2, float16 0, \
inst a0, f10, f11)
#define TEST_FP_CMP_OP_D32( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_D32_INTERNAL( testnum, flags, dword result, double val1, double val2, double 0, \
inst a0, f10, f11; li t2, 0)
#define TEST_FP_CMP_OP_D32_HEX( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_D32_INTERNAL( testnum, flags, dword result, dword val1, dword val2, double 0, \
inst a0, f10, f11; li t2, 0)
#define TEST_FP_CMP_OP_D( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_D_INTERNAL( testnum, flags, dword result, double val1, double val2, double 0, \
inst a0, f10, f11)
#define TEST_FP_CMP_OP_D_HEX( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_D_INTERNAL( testnum, flags, dword result, dword val1, dword val2, double 0, \
inst a0, f10, f11)
#define TEST_FCLASS_S(testnum, correct, input) \
TEST_CASE(testnum, a0, correct, li a0, input; fmv.s.x f10, a0; \
fclass.s a0, f10)
#define TEST_FCLASS_D32(testnum, correct, input) \
TEST_CASE(testnum, a0, correct, \
la a0, test_ ## testnum ## _data ;\
fld f10, 0(a0); \
fclass.d a0, f10) \
.pushsection .data; \
.align 3; \
test_ ## testnum ## _data: \
.dword input; \
.popsection
#define TEST_FCLASS_D(testnum, correct, input) \
TEST_CASE(testnum, a0, correct, li a0, input; fmv.d.x f10, a0; \
fclass.d a0, f10)
#define TEST_INT_FP_OP_S( testnum, inst, result, val1 ) \
test_ ## testnum: \
li TESTNUM, testnum; \
la a0, test_ ## testnum ## _data ;\
lw a3, 0(a0); \
li a0, val1; \
inst f10, a0; \
fsflags x0; \
fmv.x.s a0, f10; \
bne a0, a3, fail; \
.pushsection .data; \
.align 2; \
test_ ## testnum ## _data: \
.float result; \
.popsection
#define TEST_INT_FP_OP_H( testnum, inst, result, val1 ) \
test_ ## testnum: \
li TESTNUM, testnum; \
la a0, test_ ## testnum ## _data ;\
lh a3, 0(a0); \
li a0, val1; \
inst f10, a0; \
fsflags x0; \
fmv.x.h a0, f10; \
bne a0, a3, fail; \
.pushsection .data; \
.align 1; \
test_ ## testnum ## _data: \
.float16 result; \
.popsection
#define TEST_INT_FP_OP_D32( testnum, inst, result, val1 ) \
test_ ## testnum: \
li TESTNUM, testnum; \
la a0, test_ ## testnum ## _data ;\
lw a3, 0(a0); \
lw a4, 4(a0); \
li a1, val1; \
inst f10, a1; \
\
fsd f10, 0(a0); \
lw a1, 4(a0); \
lw a0, 0(a0); \
\
fsflags x0; \
bne a0, a3, fail; \
bne a1, a4, fail; \
.pushsection .data; \
.align 3; \
test_ ## testnum ## _data: \
.double result; \
.popsection
#define TEST_INT_FP_OP_D( testnum, inst, result, val1 ) \
test_ ## testnum: \
li TESTNUM, testnum; \
la a0, test_ ## testnum ## _data ;\
ld a3, 0(a0); \
li a0, val1; \
inst f10, a0; \
fsflags x0; \
fmv.x.d a0, f10; \
bne a0, a3, fail; \
.pushsection .data; \
.align 3; \
test_ ## testnum ## _data: \
.double result; \
.popsection
// We need some special handling here to allow 64-bit comparison in 32-bit arch
// TODO: find a better name and clean up when intended for general usage?
#define TEST_CASE_D32( testnum, testreg1, testreg2, correctval, code... ) \
test_ ## testnum: \
code; \
la x15, test_ ## testnum ## _data ; \
lw x7, 0(x15); \
lw x15, 4(x15); \
li TESTNUM, testnum; \
bne testreg1, x7, fail;\
bne testreg2, x15, fail;\
.pushsection .data; \
.align 3; \
test_ ## testnum ## _data: \
.dword correctval; \
.popsection
// ^ x14 is used in some other macros, to avoid issues we use x15 for upper word
#define MISALIGNED_LOAD_HANDLER \
li t0, CAUSE_MISALIGNED_LOAD; \
csrr t1, mcause; \
bne t0, t1, fail; \
\
/* We got a misaligned exception. Pretend we handled it in software */ \
/* by loading the correct result here. */ \
mv a4, a5; \
\
/* And skip this instruction */ \
csrr t0, mepc; \
addi t0, t0, 4; \
csrw mepc, t0; \
mret
#define MISALIGNED_STORE_HANDLER \
li t0, CAUSE_MISALIGNED_STORE; \
csrr t1, mcause; \
bne t0, t1, fail; \
\
/* We got a misaligned exception. Skip this test. */ \
csrw mepc, x15; \
mret
#-----------------------------------------------------------------------
# Pass and fail code (assumes test num is in TESTNUM)
#-----------------------------------------------------------------------
#define TEST_PASSFAIL \
bne x0, TESTNUM, pass; \
fail: \
RVTEST_FAIL; \
pass: \
RVTEST_PASS \
#-----------------------------------------------------------------------
# Test data section
#-----------------------------------------------------------------------
#define TEST_DATA
#endif

331
Tests/isa/Cprograms/vm.c Normal file
View File

@@ -0,0 +1,331 @@
// See LICENSE for license details.
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "riscv_test.h"
#define SYS_write 64
#if __riscv_xlen == 32
# define SATP_MODE_CHOICE SATP_MODE_SV32
#elif defined(Sv48)
# define SATP_MODE_CHOICE SATP_MODE_SV48
#else
# define SATP_MODE_CHOICE SATP_MODE_SV39
#endif
void trap_entry();
void pop_tf(trapframe_t*);
extern volatile uint64_t tohost;
extern volatile uint64_t fromhost;
static void do_tohost(uint64_t tohost_value)
{
while (tohost)
fromhost = 0;
tohost = tohost_value;
}
#define pa2kva(pa) ((void*)(pa) - DRAM_BASE - MEGAPAGE_SIZE)
#define uva2kva(pa) ((void*)(pa) - MEGAPAGE_SIZE)
#define flush_page(addr) asm volatile ("sfence.vma %0" : : "r" (addr) : "memory")
static uint64_t lfsr63(uint64_t x)
{
uint64_t bit = (x ^ (x >> 1)) & 1;
return (x >> 1) | (bit << 62);
}
static void cputchar(int x)
{
#if __riscv_xlen == 32
// HTIF devices are not supported on RV32, so proxy a write system call
volatile uint64_t syscall_struct[8];
volatile int buff = x;
syscall_struct[0] = SYS_write;
syscall_struct[1] = 1;
syscall_struct[2] = (uintptr_t)&buff;
syscall_struct[3] = 1;
do_tohost((uintptr_t)&syscall_struct);
// Wait for response as struct has to be read by HTIF
while(!fromhost);
#else
do_tohost(0x0101000000000000 | (unsigned char)x);
#endif
}
static void cputstring(const char* s)
{
while (*s)
cputchar(*s++);
}
static void terminate(int code)
{
do_tohost(code);
while (1);
}
void wtf()
{
terminate(841);
}
#define stringify1(x) #x
#define stringify(x) stringify1(x)
#define assert(x) do { \
if (x) break; \
cputstring("Assertion failed: " stringify(x) "\n"); \
terminate(3); \
} while(0)
#define l1pt pt[0]
#define user_l2pt pt[1]
#if SATP_MODE_CHOICE == SATP_MODE_SV48
# define NPT 6
# define kernel_l2pt pt[2]
# define kernel_l3pt pt[3]
# define user_l3pt pt[4]
# define user_llpt pt[5]
#elif SATP_MODE_CHOICE == SATP_MODE_SV39
# define NPT 4
# define kernel_l2pt pt[2]
# define user_llpt pt[3]
#elif SATP_MODE_CHOICE == SATP_MODE_SV32
# define NPT 2
# define user_llpt user_l2pt
#else
# error Unknown SATP_MODE_CHOICE
#endif
pte_t pt[NPT][PTES_PER_PT] __attribute__((aligned(PGSIZE)));
typedef struct { pte_t addr; void* next; } freelist_t;
freelist_t user_mapping[MAX_TEST_PAGES];
freelist_t freelist_nodes[MAX_TEST_PAGES];
freelist_t *freelist_head, *freelist_tail;
void printhex(uint64_t x)
{
char str[17];
for (int i = 0; i < 16; i++)
{
str[15-i] = (x & 0xF) + ((x & 0xF) < 10 ? '0' : 'a'-10);
x >>= 4;
}
str[16] = 0;
cputstring(str);
}
static void evict(unsigned long addr)
{
assert(addr >= PGSIZE && addr < MAX_TEST_PAGES * PGSIZE);
addr = addr/PGSIZE*PGSIZE;
freelist_t* node = &user_mapping[addr/PGSIZE];
if (node->addr)
{
// check accessed and dirty bits
assert(user_llpt[addr/PGSIZE] & PTE_A);
uintptr_t sstatus = set_csr(sstatus, SSTATUS_SUM);
if (memcmp((void*)addr, uva2kva(addr), PGSIZE)) {
assert(user_llpt[addr/PGSIZE] & PTE_D);
memcpy(uva2kva(addr), (void*)addr, PGSIZE);
}
write_csr(sstatus, sstatus);
user_mapping[addr/PGSIZE].addr = 0;
if (freelist_tail == 0)
freelist_head = freelist_tail = node;
else
{
freelist_tail->next = node;
freelist_tail = node;
}
}
}
extern int pf_filter(uintptr_t addr, uintptr_t *pte, int *copy);
extern int trap_filter(trapframe_t *tf);
void handle_fault(uintptr_t addr, uintptr_t cause)
{
uintptr_t filter_encodings = 0;
int copy_page = 1;
assert(addr >= PGSIZE && addr < MAX_TEST_PAGES * PGSIZE);
addr = addr/PGSIZE*PGSIZE;
if (user_llpt[addr/PGSIZE]) {
if (!(user_llpt[addr/PGSIZE] & PTE_A)) {
user_llpt[addr/PGSIZE] |= PTE_A;
} else {
assert(!(user_llpt[addr/PGSIZE] & PTE_D) && cause == CAUSE_STORE_PAGE_FAULT);
user_llpt[addr/PGSIZE] |= PTE_D;
}
flush_page(addr);
return;
}
freelist_t* node = freelist_head;
assert(node);
freelist_head = node->next;
if (freelist_head == freelist_tail)
freelist_tail = 0;
uintptr_t new_pte = (node->addr >> PGSHIFT << PTE_PPN_SHIFT) | PTE_V | PTE_U | PTE_R | PTE_W | PTE_X;
if (pf_filter(addr, &filter_encodings, &copy_page)) {
new_pte = (node->addr >> PGSHIFT << PTE_PPN_SHIFT) | filter_encodings;
}
user_llpt[addr/PGSIZE] = new_pte | PTE_A | PTE_D;
flush_page(addr);
assert(user_mapping[addr/PGSIZE].addr == 0);
user_mapping[addr/PGSIZE] = *node;
uintptr_t sstatus = set_csr(sstatus, SSTATUS_SUM);
memcpy((void*)addr, uva2kva(addr), PGSIZE);
write_csr(sstatus, sstatus);
user_llpt[addr/PGSIZE] = new_pte;
flush_page(addr);
asm volatile ("fence.i");
}
void handle_trap(trapframe_t* tf)
{
if (trap_filter(tf)) {
pop_tf(tf);
}
if (tf->cause == CAUSE_USER_ECALL)
{
int n = tf->gpr[10];
for (long i = 1; i < MAX_TEST_PAGES; i++)
evict(i*PGSIZE);
terminate(n);
}
else if (tf->cause == CAUSE_ILLEGAL_INSTRUCTION)
{
assert(tf->epc % 4 == 0);
int* fssr;
asm ("jal %0, 1f; fssr x0; 1:" : "=r"(fssr));
if (*(int*)tf->epc == *fssr)
terminate(1); // FP test on non-FP hardware. "succeed."
else
assert(!"illegal instruction");
tf->epc += 4;
}
else if (tf->cause == CAUSE_FETCH_PAGE_FAULT || tf->cause == CAUSE_LOAD_PAGE_FAULT || tf->cause == CAUSE_STORE_PAGE_FAULT)
handle_fault(tf->badvaddr, tf->cause);
else
assert(!"unexpected exception");
pop_tf(tf);
}
static void coherence_torture()
{
// cause coherence misses without affecting program semantics
uint64_t random = ENTROPY;
while (1) {
uintptr_t paddr = DRAM_BASE + ((random % (2 * (MAX_TEST_PAGES + 1) * PGSIZE)) & -4);
#ifdef __riscv_atomic
if (random & 1) // perform a no-op write
asm volatile ("amoadd.w zero, zero, (%0)" :: "r"(paddr));
else // perform a read
#endif
asm volatile ("lw zero, (%0)" :: "r"(paddr));
random = lfsr63(random);
}
}
void vm_boot(uintptr_t test_addr)
{
uint64_t random = ENTROPY;
if (read_csr(mhartid) > 0)
coherence_torture();
_Static_assert(SIZEOF_TRAPFRAME_T == sizeof(trapframe_t), "???");
#if (MAX_TEST_PAGES > PTES_PER_PT) || (DRAM_BASE % MEGAPAGE_SIZE) != 0
# error
#endif
// map user to lowermost megapage
l1pt[0] = ((pte_t)user_l2pt >> PGSHIFT << PTE_PPN_SHIFT) | PTE_V;
// map kernel to uppermost megapage
#if SATP_MODE_CHOICE == SATP_MODE_SV48
l1pt[PTES_PER_PT-1] = ((pte_t)kernel_l2pt >> PGSHIFT << PTE_PPN_SHIFT) | PTE_V;
kernel_l2pt[PTES_PER_PT-1] = ((pte_t)kernel_l3pt >> PGSHIFT << PTE_PPN_SHIFT) | PTE_V;
kernel_l3pt[PTES_PER_PT-1] = (DRAM_BASE/RISCV_PGSIZE << PTE_PPN_SHIFT) | PTE_V | PTE_R | PTE_W | PTE_X | PTE_A | PTE_D;
user_l2pt[0] = ((pte_t)user_l3pt >> PGSHIFT << PTE_PPN_SHIFT) | PTE_V;
user_l3pt[0] = ((pte_t)user_llpt >> PGSHIFT << PTE_PPN_SHIFT) | PTE_V;
#elif SATP_MODE_CHOICE == SATP_MODE_SV39
l1pt[PTES_PER_PT-1] = ((pte_t)kernel_l2pt >> PGSHIFT << PTE_PPN_SHIFT) | PTE_V;
kernel_l2pt[PTES_PER_PT-1] = (DRAM_BASE/RISCV_PGSIZE << PTE_PPN_SHIFT) | PTE_V | PTE_R | PTE_W | PTE_X | PTE_A | PTE_D;
user_l2pt[0] = ((pte_t)user_llpt >> PGSHIFT << PTE_PPN_SHIFT) | PTE_V;
#elif SATP_MODE_CHOICE == SATP_MODE_SV32
l1pt[PTES_PER_PT-1] = (DRAM_BASE/RISCV_PGSIZE << PTE_PPN_SHIFT) | PTE_V | PTE_R | PTE_W | PTE_X | PTE_A | PTE_D;
#else
# error
#endif
uintptr_t vm_choice = SATP_MODE_CHOICE;
uintptr_t satp_value = ((uintptr_t)l1pt >> PGSHIFT)
| (vm_choice * (SATP_MODE & ~(SATP_MODE<<1)));
write_csr(satp, satp_value);
if (read_csr(satp) != satp_value)
assert(!"unsupported satp mode");
flush_page(DRAM_BASE);
// Set up PMPs if present, ignoring illegal instruction trap if not.
uintptr_t pmpc = PMP_NAPOT | PMP_R | PMP_W | PMP_X;
uintptr_t pmpa = ((uintptr_t)1 << (__riscv_xlen == 32 ? 31 : 53)) - 1;
asm volatile ("la t0, 1f\n\t"
"csrrw t0, mtvec, t0\n\t"
"csrw pmpaddr0, %1\n\t"
"csrw pmpcfg0, %0\n\t"
".align 2\n\t"
"1: csrw mtvec, t0"
: : "r" (pmpc), "r" (pmpa) : "t0");
// set up supervisor trap handling
write_csr(stvec, pa2kva(trap_entry));
write_csr(sscratch, pa2kva(read_csr(mscratch)));
write_csr(medeleg,
(1 << CAUSE_USER_ECALL) |
(1 << CAUSE_FETCH_PAGE_FAULT) |
(1 << CAUSE_LOAD_PAGE_FAULT) |
(1 << CAUSE_STORE_PAGE_FAULT));
// FPU on; accelerator on; vector unit on
write_csr(mstatus, MSTATUS_FS | MSTATUS_XS | MSTATUS_VS);
write_csr(mie, 0);
random = 1 + (random % MAX_TEST_PAGES);
freelist_head = pa2kva((void*)&freelist_nodes[0]);
freelist_tail = pa2kva(&freelist_nodes[MAX_TEST_PAGES-1]);
for (long i = 0; i < MAX_TEST_PAGES; i++)
{
freelist_nodes[i].addr = DRAM_BASE + (MAX_TEST_PAGES + random)*PGSIZE;
freelist_nodes[i].next = pa2kva(&freelist_nodes[i+1]);
random = LFSR_NEXT(random);
}
freelist_nodes[MAX_TEST_PAGES-1].next = 0;
trapframe_t tf;
memset(&tf, 0, sizeof(tf));
tf.epc = test_addr - DRAM_BASE;
pop_tf(&tf);
}