vendored riscv test env for common macro files

This commit is contained in:
Saad Khalid 2023-01-26 21:00:38 +00:00 committed by Greg Chadwick
parent d51437bcf9
commit 72e9bcd488
20 changed files with 1801 additions and 1633 deletions

View file

@ -10,6 +10,10 @@
RVTEST_RV64M
RVTEST_CODE_BEGIN
# setting machine handler
la t0, mtvec_handler
csrw mtvec, t0
# setting the PMP region
la t0, pmp_region_start
srli t1, t0, PMP_SHIFT
@ -23,8 +27,14 @@ RVTEST_CODE_BEGIN
# access across the boundary between PMP and non-PMP
lw t1, -2(t0)
j pass
TEST_PASSFAIL
.balign 256
mtvec_handler:
j fail
RVTEST_CODE_END
.data

View file

@ -17,6 +17,9 @@
ld_script: link.ld
includes: .
gcc_opts: -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
-I../../../vendor/riscv-test-env/
-I../../../vendor/riscv-test-env/p/
-I../../../vendor/riscv-tests/isa/macros/scalar/
rtl_test: core_ibex_base_test
rtl_params:
PMPEnable: 1
@ -28,3 +31,10 @@
iterations: 1
test_srcs: empty/empty.S
config: base
- test: access_pmp_overlap
desc: >
PMP access basic test
iterations: 1
test_srcs: access_pmp_overlap/access_pmp_overlap.S
config: base

View file

@ -1,3 +1,4 @@
// Copyright lowRISC contributors.
// Ibex specific macros
#define SIGNATURE_ADDR 0x8ffffff8

View file

@ -1,754 +0,0 @@
// See LICENSE for license details.
// clang-format off
#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
#-----------------------------------------------------------------------
# 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 x1, MASK_XLEN(val1); \
inst x14, x1, SEXT_IMM(imm); \
)
#define TEST_IMM_SRC1_EQ_DEST( testnum, inst, result, val1, imm ) \
TEST_CASE( testnum, x1, result, \
li x1, MASK_XLEN(val1); \
inst x1, x1, 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 x1, MASK_XLEN(val1); \
li x2, MASK_XLEN(val2); \
inst x14, x1, x2; \
)
#define TEST_RR_SRC1_EQ_DEST( testnum, inst, result, val1, val2 ) \
TEST_CASE( testnum, x1, result, \
li x1, MASK_XLEN(val1); \
li x2, MASK_XLEN(val2); \
inst x1, x1, x2; \
)
#define TEST_RR_SRC2_EQ_DEST( testnum, inst, result, val1, val2 ) \
TEST_CASE( testnum, x2, result, \
li x1, MASK_XLEN(val1); \
li x2, MASK_XLEN(val2); \
inst x2, x1, x2; \
)
#define TEST_RR_SRC12_EQ_DEST( testnum, inst, result, val1 ) \
TEST_CASE( testnum, x1, result, \
li x1, MASK_XLEN(val1); \
inst x1, x1, x1; \
)
#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 x1, base; \
inst x14, offset(x1); \
)
#define TEST_ST_OP( testnum, load_inst, store_inst, result, offset, base ) \
TEST_CASE( testnum, x14, result, \
la x1, base; \
li x2, result; \
la x15, 7f; /* Tell the exception handler how to skip this test. */ \
store_inst x2, offset(x1); \
load_inst x14, offset(x1); \
j 8f; \
7: \
/* Set up the correct result for TEST_CASE(). */ \
mv x14, x2; \
8: \
)
#define TEST_LD_DEST_BYPASS( testnum, nop_cycles, inst, result, offset, base ) \
test_ ## testnum: \
li TESTNUM, testnum; \
li x4, 0; \
1: la x1, base; \
inst x14, offset(x1); \
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 x1, base; \
TEST_INSERT_NOPS_ ## nop_cycles \
inst x14, offset(x1); \
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 x1, result; \
TEST_INSERT_NOPS_ ## src1_nops \
la x2, base; \
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_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_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
#-----------------------------------------------------------------------
#define qNaNh 0h:7e00
#define sNaNh 0h:7c01
#define qNaNf 0f:7fc00000
#define sNaNf 0f:7f800001
#define qNaN 0d:7ff8000000000000
#define sNaN 0d:7ff0000000000001
#define TEST_FP_OP_H_INTERNAL( testnum, flags, result, val1, val2, val3, code... ) \
test_ ## testnum: \
li TESTNUM, testnum; \
la a0, test_ ## testnum ## _data ;\
flh f0, 0(a0); \
flh f1, 2(a0); \
flh f2, 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: \
.float16 val1; \
.float16 val2; \
.float16 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 f0, 0(a0); \
flw f1, 4(a0); \
flw f2, 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: \
.float val1; \
.float val2; \
.float 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 f0, 0(a0); \
fld f1, 8(a0); \
fld f2, 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: \
.double val1; \
.double val2; \
.double 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 f0, 0(a0); \
fld f1, 8(a0); \
fld f2, 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: \
.double val1; \
.double val2; \
.double val3; \
.result; \
.popsection
#define TEST_FCVT_S_D32( testnum, result, val1 ) \
TEST_FP_OP_D32_INTERNAL( testnum, 0, double result, val1, 0.0, 0.0, \
fcvt.s.d f3, f0; fcvt.d.s f3, f3; fsd f3, 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, val1, 0.0, 0.0, \
fcvt.s.d f3, f0; fcvt.d.s f3, f3; fmv.x.d a0, f3)
#define TEST_FCVT_D_S( testnum, result, val1 ) \
TEST_FP_OP_S_INTERNAL( testnum, 0, float result, val1, 0.0, 0.0, \
fcvt.d.s f3, f0; fcvt.s.d f3, f3; fmv.x.s a0, f3)
#define TEST_FCVT_H_S( testnum, result, val1 ) \
TEST_FP_OP_H_INTERNAL( testnum, 0, float16 result, val1, 0.0, 0.0, \
fcvt.s.h f3, f0; fcvt.h.s f3, f3; fmv.x.h a0, f3)
#define TEST_FCVT_H_D( testnum, result, val1 ) \
TEST_FP_OP_H_INTERNAL( testnum, 0, float16 result, val1, 0.0, 0.0, \
fcvt.d.h f3, f0; fcvt.h.d f3, f3; fmv.x.h a0, f3)
#define TEST_FP_OP1_H( testnum, inst, flags, result, val1 ) \
TEST_FP_OP_H_INTERNAL( testnum, flags, float16 result, val1, 0.0, 0.0, \
inst f3, f0; fmv.x.h a0, f3;)
#define TEST_FP_OP1_S( testnum, inst, flags, result, val1 ) \
TEST_FP_OP_S_INTERNAL( testnum, flags, float result, val1, 0.0, 0.0, \
inst f3, f0; fmv.x.s a0, f3)
#define TEST_FP_OP1_D32( testnum, inst, flags, result, val1 ) \
TEST_FP_OP_D32_INTERNAL( testnum, flags, double result, val1, 0.0, 0.0, \
inst f3, f0; fsd f3, 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, val1, 0.0, 0.0, \
inst f3, f0; fmv.x.d a0, f3)
#define TEST_FP_OP1_S_DWORD_RESULT( testnum, inst, flags, result, val1 ) \
TEST_FP_OP_S_INTERNAL( testnum, flags, dword result, val1, 0.0, 0.0, \
inst f3, f0; fmv.x.s a0, f3)
#define TEST_FP_OP1_H_DWORD_RESULT( testnum, inst, flags, result, val1 ) \
TEST_FP_OP_H_INTERNAL( testnum, flags, word result, val1, 0.0, 0.0, \
inst f3, f0; fmv.x.h a0, f3)
#define TEST_FP_OP1_D32_DWORD_RESULT( testnum, inst, flags, result, val1 ) \
TEST_FP_OP_D32_INTERNAL( testnum, flags, dword result, val1, 0.0, 0.0, \
inst f3, f0; fsd f3, 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, val1, 0.0, 0.0, \
inst f3, f0; fmv.x.d a0, f3)
#define TEST_FP_OP2_S( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_S_INTERNAL( testnum, flags, float result, val1, val2, 0.0, \
inst f3, f0, f1; fmv.x.s a0, f3)
#define TEST_FP_OP2_H( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_H_INTERNAL( testnum, flags, float16 result, val1, val2, 0.0, \
inst f3, f0, f1; fmv.x.h a0, f3)
#define TEST_FP_OP2_D32( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_D32_INTERNAL( testnum, flags, double result, val1, val2, 0.0, \
inst f3, f0, f1; fsd f3, 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_D( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_D_INTERNAL( testnum, flags, double result, val1, val2, 0.0, \
inst f3, f0, f1; fmv.x.d a0, f3)
#define TEST_FP_OP3_S( testnum, inst, flags, result, val1, val2, val3 ) \
TEST_FP_OP_S_INTERNAL( testnum, flags, float result, val1, val2, val3, \
inst f3, f0, f1, f2; fmv.x.s a0, f3)
#define TEST_FP_OP3_H( testnum, inst, flags, result, val1, val2, val3 ) \
TEST_FP_OP_H_INTERNAL( testnum, flags, float16 result, val1, val2, val3, \
inst f3, f0, f1, f2; fmv.x.h a0, f3)
#define TEST_FP_OP3_D32( testnum, inst, flags, result, val1, val2, val3 ) \
TEST_FP_OP_D32_INTERNAL( testnum, flags, double result, val1, val2, val3, \
inst f3, f0, f1, f2; fsd f3, 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, val1, val2, val3, \
inst f3, f0, f1, f2; fmv.x.d a0, f3)
#define TEST_FP_INT_OP_S( testnum, inst, flags, result, val1, rm ) \
TEST_FP_OP_S_INTERNAL( testnum, flags, word result, val1, 0.0, 0.0, \
inst a0, f0, rm)
#define TEST_FP_INT_OP_H( testnum, inst, flags, result, val1, rm ) \
TEST_FP_OP_H_INTERNAL( testnum, flags, word result, val1, 0.0, 0.0, \
inst a0, f0, rm)
#define TEST_FP_INT_OP_D32( testnum, inst, flags, result, val1, rm ) \
TEST_FP_OP_D32_INTERNAL( testnum, flags, dword result, val1, 0.0, 0.0, \
inst a0, f0, f1; li t2, 0)
#define TEST_FP_INT_OP_D( testnum, inst, flags, result, val1, rm ) \
TEST_FP_OP_D_INTERNAL( testnum, flags, dword result, val1, 0.0, 0.0, \
inst a0, f0, rm)
#define TEST_FP_CMP_OP_S( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_S_INTERNAL( testnum, flags, word result, val1, val2, 0.0, \
inst a0, f0, f1)
#define TEST_FP_CMP_OP_H( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_H_INTERNAL( testnum, flags, hword result, val1, val2, 0.0, \
inst a0, f0, f1)
#define TEST_FP_CMP_OP_D32( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_D32_INTERNAL( testnum, flags, dword result, val1, val2, 0.0, \
inst a0, f0, f1; li t2, 0)
#define TEST_FP_CMP_OP_D( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_D_INTERNAL( testnum, flags, dword result, val1, val2, 0.0, \
inst a0, f0, f1)
#define TEST_FCLASS_S(testnum, correct, input) \
TEST_CASE(testnum, a0, correct, li a0, input; fmv.s.x fa0, a0; \
fclass.s a0, fa0)
#define TEST_FCLASS_D32(testnum, correct, input) \
TEST_CASE(testnum, a0, correct, \
la a0, test_ ## testnum ## _data ;\
fld fa0, 0(a0); \
fclass.d a0, fa0) \
.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 fa0, a0; \
fclass.d a0, fa0)
#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 f0, a0; \
fsflags x0; \
fmv.x.s a0, f0; \
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 f0, a0; \
fsflags x0; \
fmv.x.h a0, f0; \
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 f0, a1; \
\
fsd f0, 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 f0, a0; \
fsflags x0; \
fmv.x.d a0, f0; \
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

View file

@ -0,0 +1,89 @@
diff --git a/p/riscv_test.h b/p/riscv_test.h
index fe14f086..18fdc0a7 100644
--- a/p/riscv_test.h
+++ b/p/riscv_test.h
@@ -1,9 +1,11 @@
// See LICENSE for license details.
+// clang-format off
#ifndef _ENV_PHYSICAL_SINGLE_CORE_H
#define _ENV_PHYSICAL_SINGLE_CORE_H
-#include "../encoding.h"
+#include "encoding.h"
+#include "ibex_macros.h"
//-----------------------------------------------------------------------
// Begin Macro
@@ -190,14 +192,13 @@ handle_exception: \
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_SATP; \
+ /*INIT_SATP; Ibex doesn't support supervisor mode */ \
INIT_PMP; \
- DELEGATE_NO_TRAPS; \
+ /*DELEGATE_NO_TRAPS; Ibex doesn't support supervisor mode */ \
li TESTNUM, 0; \
la t0, trap_vector; \
csrw mtvec, t0; \
@@ -212,7 +213,7 @@ reset_vector: \
(1 << CAUSE_MISALIGNED_FETCH) | \
(1 << CAUSE_USER_ECALL) | \
(1 << CAUSE_BREAKPOINT); \
- csrw medeleg, t0; \
+ /*csrw medeleg, t0; Ibex doesn't support supervisor mode */ \
1: csrwi mstatus, 0; \
init; \
EXTRA_INIT; \
@@ -236,20 +237,24 @@ reset_vector: \
#define RVTEST_PASS \
fence; \
- li TESTNUM, 1; \
- li a7, 93; \
- li a0, 0; \
- ecall
+ li x2, SIGNATURE_ADDR; \
+ li x1, (FINISHED_IRQ << 8) | CORE_STATUS; \
+ sw x1, 0(x2); \
+ li x1, (TEST_PASS << 8) | TEST_RESULT; \
+ sw x1, 0(x2); \
+ 2:; \
+ j 2b;
#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
+ li x2, SIGNATURE_ADDR; \
+ li x1, (FINISHED_IRQ << 8) | CORE_STATUS; \
+ sw x1, 0(x2); \
+ li x1, (TEST_FAIL << 8) | TEST_RESULT; \
+ sw x1, 0(x2); \
+ 2:; \
+ j 2b;
//-----------------------------------------------------------------------
// Data Section Macro
@@ -260,8 +265,8 @@ reset_vector: \
#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;\
+ .align 6; .global tohost; tohost: .dword 0; \
+ .align 6; .global fromhost; fromhost: .dword 0; \
.popsection; \
.align 4; .global begin_signature; begin_signature:

24
vendor/riscv-test-env/LICENSE vendored Normal file
View file

@ -0,0 +1,24 @@
Copyright (c) 2012-2015, The Regents of the University of California (Regents).
All Rights Reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the Regents nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

17
vendor/riscv-test-env/p/link.ld vendored Normal file
View file

@ -0,0 +1,17 @@
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

@ -5,6 +5,7 @@
#define _ENV_PHYSICAL_SINGLE_CORE_H
#include "encoding.h"
#include "ibex_macros.h"
//-----------------------------------------------------------------------
// Begin Macro

17
vendor/riscv-test-env/pm/link.ld vendored Normal file
View file

@ -0,0 +1,17 @@
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 = .;
}

11
vendor/riscv-test-env/pm/riscv_test.h vendored Normal file
View file

@ -0,0 +1,11 @@
// See LICENSE for license details.
#ifndef _ENV_PHYSICAL_MULTI_CORE_H
#define _ENV_PHYSICAL_MULTI_CORE_H
#include "../p/riscv_test.h"
#undef RISCV_MULTICORE_DISABLE
#define RISCV_MULTICORE_DISABLE
#endif

17
vendor/riscv-test-env/pt/link.ld vendored Normal file
View file

@ -0,0 +1,17 @@
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 = .;
}

69
vendor/riscv-test-env/pt/riscv_test.h vendored Normal file
View file

@ -0,0 +1,69 @@
// See LICENSE for license details.
#ifndef _ENV_PHYSICAL_SINGLE_CORE_TIMER_H
#define _ENV_PHYSICAL_SINGLE_CORE_TIMER_H
#include "../p/riscv_test.h"
#define TIMER_INTERVAL 2
#undef EXTRA_INIT_TIMER
#define EXTRA_INIT_TIMER \
li a0, MIP_MTIP; \
csrs mie, a0; \
csrr a0, mtime; \
addi a0, a0, TIMER_INTERVAL; \
csrw mtimecmp, a0; \
#if SSTATUS_XS != 0x18000
# error
#endif
#define XS_SHIFT 15
#undef INTERRUPT_HANDLER
#define INTERRUPT_HANDLER \
slli t5, t5, 1; \
srli t5, t5, 1; \
add t5, t5, -IRQ_M_TIMER; \
bnez t5, other_exception; /* other interrups shouldn't happen */\
csrr t5, mtime; \
addi t5, t5, TIMER_INTERVAL; \
csrw mtimecmp, t5; \
mret; \
//-----------------------------------------------------------------------
// Data Section Macro
//-----------------------------------------------------------------------
#undef EXTRA_DATA
#define EXTRA_DATA \
.align 3; \
regspill: \
.dword 0xdeadbeefcafebabe; \
.dword 0xdeadbeefcafebabe; \
.dword 0xdeadbeefcafebabe; \
.dword 0xdeadbeefcafebabe; \
.dword 0xdeadbeefcafebabe; \
.dword 0xdeadbeefcafebabe; \
.dword 0xdeadbeefcafebabe; \
.dword 0xdeadbeefcafebabe; \
.dword 0xdeadbeefcafebabe; \
.dword 0xdeadbeefcafebabe; \
.dword 0xdeadbeefcafebabe; \
.dword 0xdeadbeefcafebabe; \
.dword 0xdeadbeefcafebabe; \
.dword 0xdeadbeefcafebabe; \
.dword 0xdeadbeefcafebabe; \
.dword 0xdeadbeefcafebabe; \
.dword 0xdeadbeefcafebabe; \
.dword 0xdeadbeefcafebabe; \
.dword 0xdeadbeefcafebabe; \
.dword 0xdeadbeefcafebabe; \
.dword 0xdeadbeefcafebabe; \
.dword 0xdeadbeefcafebabe; \
.dword 0xdeadbeefcafebabe; \
.dword 0xdeadbeefcafebabe; \
evac: \
.skip 32768; \
#endif

162
vendor/riscv-test-env/v/entry.S vendored Normal file
View file

@ -0,0 +1,162 @@
#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 + 4096)
.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
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

17
vendor/riscv-test-env/v/link.ld vendored Normal file
View file

@ -0,0 +1,17 @@
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 = .;
}

80
vendor/riscv-test-env/v/riscv_test.h vendored Normal file
View file

@ -0,0 +1,80 @@
// See LICENSE for license details.
#ifndef _ENV_VIRTUAL_SINGLE_CORE_H
#define _ENV_VIRTUAL_SINGLE_CORE_H
#include "../p/riscv_test.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_CODE_BEGIN
#define RVTEST_CODE_BEGIN \
.text; \
.global extra_boot; \
extra_boot: \
EXTRA_INIT \
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
//-----------------------------------------------------------------------
#define MAX_TEST_PAGES 63 // this must be the period of the LFSR below
#define LFSR_NEXT(x) (((((x)^((x)>>1)) & 1) << 5) | ((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

114
vendor/riscv-test-env/v/string.c vendored Normal file
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;
}

300
vendor/riscv-test-env/v/vm.c vendored Normal file
View file

@ -0,0 +1,300 @@
// See LICENSE for license details.
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "riscv_test.h"
#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)
{
do_tohost(0x0101000000000000 | (unsigned char)x);
}
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;
}
}
}
void handle_fault(uintptr_t addr, uintptr_t cause)
{
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;
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 (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");
// 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);
}

15
vendor/riscv_test_env.lock.hjson vendored Normal file
View file

@ -0,0 +1,15 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
// This file is generated by the util/vendor script. Please do not modify it
// manually.
{
upstream:
{
url: https://github.com/riscv/riscv-test-env
rev: 34a1175291f9531e85afdb89aaa77707f45fc8e4
}
patch_dir: "patches/riscv_test_env"
}

12
vendor/riscv_test_env.vendor.hjson vendored Normal file
View file

@ -0,0 +1,12 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
{
name: "riscv-test-env",
target_dir: "riscv-test-env",
upstream: {
url: "https://github.com/riscv/riscv-test-env",
rev: "master",
},
}