cvw/tests/wally-riscv-arch-test/riscv-test-suite/env/arch_test.h
2021-10-23 08:53:32 -07:00

1185 lines
50 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "encoding.h"
// TODO the following should come from the YAML.
#ifndef NUM_SPECD_INTCAUSES
#define NUM_SPECD_INTCAUSES 16
#endif
//#define RVTEST_FIXED_LEN
#ifndef UNROLLSZ
#define UNROLLSZ 5
#endif
// #ifndef rvtest_gpr_save
// #define rvtest_gpr_save
// #endif
#define TEST_CASE_1
//-----------------------------------------------------------------------
// RV Arch Test Macros
//-----------------------------------------------------------------------
#ifndef RVMODEL_SET_MSW_INT
#warning "RVMODEL_SET_MSW_INT is not defined by target. Declaring as empty macro"
#define RVMODEL_SET_MSW_INT
#endif
#ifndef RVMODEL_CLEAR_MSW_INT
#warning "RVMODEL_CLEAR_MSW_INT is not defined by target. Declaring as empty macro"
#define RVMODEL_CLEAR_MSW_INT
#endif
#ifndef RVMODEL_CLEAR_MTIMER_INT
#warning "RVMODEL_CLEAR_MTIMER_INT is not defined by target. Declaring as empty macro"
#define RVMODEL_CLEAR_MTIMER_INT
#endif
#ifndef RVMODEL_CLEAR_MEXT_INT
#warning "RVMODEL_CLEAR_MEXT_INT is not defined by target. Declaring as empty macro"
#define RVMODEL_CLEAR_MEXT_INT
#endif
#ifdef RVTEST_FIXED_LEN
#define LI(reg, val)\
.option push;\
.option norvc;\
.align UNROLLSZ;\
li reg,val;\
.align UNROLLSZ;\
.option pop;
#define LA(reg, val)\
.option push;\
.option norvc;\
.align UNROLLSZ;\
la reg,val;\
.align UNROLLSZ;\
.option pop;
#else
#define LI(reg,val);\
.option push;\
.option norvc;\
li reg,val;\
.option pop;
#define LA(reg,val);\
.option push;\
.option norvc;\
la reg,val;\
.option pop;
#endif
#if XLEN==64
#define SREG sd
#define LREG ld
#define REGWIDTH 8
#define MASK 0xFFFFFFFFFFFFFFFF
#else
#if XLEN==32
#define SREG sw
#define LREG lw
#define REGWIDTH 4
#define MASK 0xFFFFFFFF
#endif
#endif
#if FLEN==64
#define FLREG fld
#define FSREG fsd
#define FREGWIDTH 8
#else
#if FLEN==32
#define FLREG flw
#define FSREG fsw
#define FREGWIDTH 4
#endif
#endif
#if XLEN==64
#if FLEN==32
#define SREG sw
#define LREG lW
#define REGWIDTH 4
#define MASK 0xFFFFFFFF
#endif
#endif
#define MMODE_SIG 3
#define RLENG (REGWIDTH<<3)
#define RVTEST_ISA(_STR)
#ifndef DATA_REL_TVAL_MSK
#define DATA_REL_TVAL_MSK 0x0F05 << (REGWIDTH*8-16)
#endif
#ifndef CODE_REL_TVAL_MSK
#define CODE_REL_TVAL_MSK 0xD008 << (REGWIDTH*8-16)
#endif
// ----------------------------------- CODE BEGIN w/ TRAP HANDLER START ------------------------ //
.macro RVTEST_CODE_BEGIN
.align UNROLLSZ
.section .text.init;
.globl rvtest_init; \
rvtest_init:
#ifdef rvtest_mtrap_routine
LA(x1, rvtest_trap_prolog );
jalr ra, x1
rvtest_prolog_done:
#endif
LI (x1, (0xFEEDBEADFEEDBEAD & MASK));
LI (x2, (0xFF76DF56FF76DF56 & MASK));
LI (x3, (0x7FBB6FAB7FBB6FAB & MASK));
LI (x4, (0xBFDDB7D5BFDDB7D5 & MASK));
LA (x5, rvtest_code_begin);
LA (x6, rvtest_data_begin);
LI (x7, (0xB7FBB6FAB7FBB6FA & MASK));
LI (x8, (0x5BFDDB7D5BFDDB7D & MASK));
LI (x9, (0xADFEEDBEADFEEDBE & MASK));
LI (x10, (0x56FF76DF56FF76DF & MASK));
LI (x11, (0xAB7FBB6FAB7FBB6F & MASK));
LI (x12, (0xD5BFDDB7D5BFDDB7 & MASK));
LI (x13, (0xEADFEEDBEADFEEDB & MASK));
LI (x14, (0xF56FF76DF56FF76D & MASK));
LI (x15, (0xFAB7FBB6FAB7FBB6 & MASK));
#ifndef RVTEST_E
LI (x16, (0x7D5BFDDB7D5BFDDB & MASK));
LI (x17, (0xBEADFEEDBEADFEED & MASK));
LI (x18, (0xDF56FF76DF56FF76 & MASK));
LI (x19, (0x6FAB7FBB6FAB7FBB & MASK));
LI (x20, (0xB7D5BFDDB7D5BFDD & MASK));
LI (x21, (0xDBEADFEEDBEADFEE & MASK));
LI (x22, (0x6DF56FF76DF56FF7 & MASK));
LI (x23, (0xB6FAB7FBB6FAB7FB & MASK));
LI (x24, (0xDB7D5BFDDB7D5BFD & MASK));
LI (x25, (0xEDBEADFEEDBEADFE & MASK));
LI (x26, (0x76DF56FF76DF56FF & MASK));
LI (x27, (0xBB6FAB7FBB6FAB7F & MASK));
LI (x28, (0xDDB7D5BFDDB7D5BF & MASK));
LI (x29, (0xEEDBEADFEEDBEADF & MASK));
LI (x30, (0xF76DF56FF76DF56F & MASK));
LI (x31, (0xFBB6FAB7FBB6FAB7 & MASK));
#endif
.globl rvtest_code_begin
rvtest_code_begin:
.endm
// --------------------------------- CODE BEGIN w/ TRAP HANDLER END -----------------------------//
.macro RVTEST_CODE_END
.align 4;
.global rvtest_code_end
rvtest_code_end:
#ifdef rvtest_mtrap_routine
.option push
.option norvc
j exit_cleanup
rvtest_trap_prolog:
/******************************************************************************/
/**** Prolog, to be run before any tests ****/
/**** #include 1 copy of this per mode in rvmodel_boot code? ****/
/**** ------------------------------------------------------------------- ****/
/**** if xTVEC isn't completely RW, then we need to change the code at its ****/
/**** target. The entire trap trampoline and mtrap handler replaces the ****/
/**** area pointed to by mtvec, after saving its original contents first. ****/
/**** If it isn't possible to fully write that area, restore and fail. ****/
/******************************************************************************/
//trap_handler_prolog; enter with t1..t6 available
init_mscratch:
la t1, trapreg_sv
csrrw t1, CSR_MSCRATCH, t1 // swap old mscratch. mscratch not points to trapreg_sv
la t2, mscratch_save
SREG t1, 0(t2) // save old mscratch in mscratch_save region
csrr t1, CSR_MSCRATCH // read the trapreg_sv address
LA( t2, mtrap_sigptr ) // locate the start of the trap signature
SREG t2, 0(t1) // save mtrap_sigptr at first location of trapreg_sv
init_mtvec:
la t1, mtrampoline
la t4, mtvec_save
csrrw t2, CSR_MTVEC, t1 // swap mtvec and trap_trampoline
SREG t2, 0(t4) // save orig mtvec
csrr t3, CSR_MTVEC // now read new_mtval back
beq t3, t1, rvtest_prolog_done // if mtvec==trap_trampoline, mtvec is writable, continue
/****************************************************************/
/**** fixed mtvec, can't move it so move trampoline instead ****/
/**** t1=trampoline, t2=oldmtvec, t3=save area, t4=save end ****/
/****************************************************************/
// t2 = dut's original mtvec setting
// t1 = mtrampoline address
init_tramp: /**** copy trampoline at mtvec tgt ****/
csrw CSR_MTVEC, t2 // restore orig mtvec, will now attemp to copy trampoline to it
la t3, tramptbl_sv // addr of save area
addi t4, t3, NUM_SPECD_INTCAUSES*4 // end of save area
overwrite_tt: // now build new trampoline table with offsets base from curr mtvec
lw t6, 0(t2) // get original mtvec target
sw t6, 0(t3) // save it
lw t5, 0(t1) // get trampoline src
sw t5, 0(t2) // overwrite mtvec target
lw t6, 0(t2) // rd it back to make sure it was written
bne t6, t5, resto_tramp // table isn't fully writable, restore and give up
addi t1, t1, 4 // next src index
addi t2, t2, 4 // next tgt index
addi t3, t3, 4 // next save index
bne t3, t4, overwrite_tt // not done, loop
j rvtest_prolog_done
resto_tramp: // vector table not writeable, restore
LREG t1, 16(t4) // load mscratch_SAVE at fixed offset from table end
csrw CSR_MSCRATCH, t1 // restore mscratch
LREG t4, 8(t4) // load mtvec_SAVE (used as end of loop marker)
resto_loop: // goes backwards, t2= dest vec tbl ptr, t3=src save area ptr, t4=vec tbl begin
lw t6, 0(t3) // read saved tgt entry
sw t6, 0(t2) // restore original tgt
addi t2, t2, -4 // prev tgt index
addi t3, t3, -4 // prev save index
bne t2, t4, resto_loop // didn't restore to begining yet, loop
j rvtest_end // failure to replace trampoline
#define mhandler \
csrrw sp, CSR_MSCRATCH, sp; \
SREG t6, 6*REGWIDTH(sp); \
jal t6, common_prolog;
/**********************************************************************/
/**** This is the entry point for all m-modetraps, vectored or not.****/
/**** At entry, mscratch will contain a pointer to a scratch area. ****/
/**** This is an array of branches at 4B intevals that spreads out ****/
/**** to an array of 32B mhandler macros for specd int causes, and ****/
/**** to a return for anything above that (which causes a mismatch)****/
/**********************************************************************/
mtrampoline: // 64 or 32 entry table
value = 0
.rept NUM_SPECD_INTCAUSES // located at each possible int vectors
j mtrap_handler + 12*(value) //offset < +/- 1MB
value = value + 1
.endr
.rept RLENG-NUM_SPECD_INTCAUSES // fill at each impossible entry
mret
.endr
mtrap_handler: /* after executing, sp points to temp save area, t4 is PC */
.rept NUM_SPECD_INTCAUSES
mhandler
.endr
common_prolog:
la t5, common_mhandler
jr t5
/*********************************************************************/
/**** common code for all ints & exceptions, will fork to handle ****/
/**** each separately. The common handler first stores trap mode+ ****/
/**** vector, and mcause signatures. All traps have 4wd sigs, but ****/
/**** sw and timer ints only store 3 of the 4. ****/
/**** sig offset Exception ExtInt SWInt TimerInt ****/
/**** 0: tval IntID -1 -1 ****/
/**** 4: mepc mip mip mip ****/
/**** 8: <---------------------- mcause -------------> ****/
/**** 12: <--------------------- Vect+mode ----------> ****/
/*********************************************************************/
/* in general, CSRs loaded in t2, addresses into t3 */
common_mhandler: /* enter with link in t6 */
SREG t5, 5*REGWIDTH(sp)
SREG t4, 4*REGWIDTH(sp)
SREG t3, 3*REGWIDTH(sp)
SREG t2, 2*REGWIDTH(sp)
SREG t1, 1*REGWIDTH(sp) /* save other temporaries */
LREG t1, 0(sp) /* load trap sig pointer (runs backwards from DATA_END) */
LA( t3, mtrampoline)
sub t2, t6, t3 /* reloc “link” to 0..63 to show which int vector was taken */
addi t2, t2, MMODE_SIG /* insert mode# into 1:0 */
SREG t2, 0*REGWIDTH(t1) /* save 1st sig value, (vect, trapmode) */
sv_mcause:
csrr t2, CSR_MCAUSE
SREG t2, 1*REGWIDTH(t1) /* save 2nd sig value, (mcause) */
bltz t2, common_mint_handler /* this is a interrupt, not a trap */
/********************************************************************/
/**** This is the exceptions specific code, storing relative mepc****/
/**** & relative tval signatures. tval is relocated by code or ****/
/**** data start, or 0 depending on mcause. mepc signature value ****/
/**** is relocated by code start, and restored adjusted depending****/
/**** on op alignment so trapped op isn't re-executed. ****/
/********************************************************************/
common_mexcpt_handler:
csrr t2, CSR_MEPC
sv_mepc:
LA( t3, rvtest_prolog_done) /* offset to compensate for different loader offsets */
sub t4, t2, t3 /* convert mepc to rel offset of beginning of test*/
SREG t4, 2*REGWIDTH(t1) /* save 3rd sig value, (rel mepc) into trap signature area */
adj_mepc: //adj mepc so there is padding after op, and its 8B aligned
andi t4, t2, 0x2 /* set to 2 if mepc was misaligned */
sub t2, t2, t4 /* adjust mepc to prev 4B alignment */
addi t2, t2, 0x8 /* adjust mepc, so it skips past the op, has padding & is 4B aligned */
csrw CSR_MEPC, t2 /* restore adjusted value, has 1,2, or 3 bytes of padding */
/* calculate relative mtval if its an address (by code_begin or data_begin amt) */
/* note that masks that determine this are implementation specific from YAML */
/* masks are bit reversed, so mcause==0 bit is in MSB (so different for RV32 and RV64) */
adj_mtval:
csrr t2, CSR_MCAUSE /* code begin adjustment amount already in t3 */
LI(t4, CODE_REL_TVAL_MSK) /* trap#s 12, 3,1,0, -- adjust w/ code_begin */
sll t4, t4, t2 /* put bit# in MSB */
bltz t4, sv_mtval /* correct adjustment is code_begin in t3 */
LA( t3, mtrap_sigptr) /* adjustment assuming access is to signature region */
LI(t4, DATA_REL_TVAL_MSK) /* trap#s not 14, 11..8, 2 adjust w/ data_begin */
sll t4, t4, t2 /* put bit# in MSB */
bgez t4, no_adj /* correct adjustment is data_begin in t3 */
sigbound_chk:
csrr t4, CSR_MTVAL /* do a bounds check on mtval */
bge t3, t4, sv_mtval /* if mtval is greater than the rvmodel_data_begin then use that as anchor */
LA( t3, rvtest_data_begin) /* else change anchor to rvtest_data_begin */
blt t3, t4, sv_mtval /* before the signature, use data_begin adj */
mv t4, t3 /* use sig relative adjust */
no_adj:
LI(t3, 0) /* else zero adjustment amt */
// For Illegal op handling
addi t2, t2, -2 /* check if mcause==2 (illegal op) */
bnez t2, sv_mtval /* not illegal op, no special treatment */
csrr t2, CSR_MTVAL
bnez t2, sv_mtval /* mtval isnt zero, no special treatment */
illop:
LI(t5, 0x20000) /* get mprv mask */
csrrs t5, CSR_MSTATUS, t5 /* set mprv while saving the old value */
csrr t3, CSR_MEPC
lhu t2, 0(t3) /* load 1st 16b of opc w/ old priv, endianess*/
andi t4, t2, 0x3
addi t4, t4, -0x3 /* does opcode[1:0]==0b11? (Meaning >16b op) */
bnez t4, sv_mtval /* entire mtval is in tt2, adj amt will be set to zero */
lhu t4, 2(t3)
sll t4, t4, 16
or t3, t2, t4 /* get 2nd hwd, align it & insert it into opcode */
csrw CSR_MSTATUS, t5 /* restore mstatus */
/*******FIXME: this will not handle 48 or 64b opcodes in an RV64) ********/
sv_mtval:
csrr t2, CSR_MTVAL
sub t2, t2, t3 /* perform mtval adjust by either code or data position or zero*/
SREG t2, 3*REGWIDTH(t1) /* save 4th sig value, (rel mtval) into trap signature area */
resto_rtn: /* restore and return */
addi t1, t1,4*REGWIDTH /* adjust trap signature ptr (traps always save 4 words) */
SREG t1, 0*REGWIDTH(sp) /* save updated trap sig pointer (pts to trap_sigptr */
LREG t1, 1*REGWIDTH(sp)
LREG t2, 2*REGWIDTH(sp)
LREG t3, 3*REGWIDTH(sp)
LREG t4, 4*REGWIDTH(sp)
LREG t5, 5*REGWIDTH(sp)
LREG t6, 6*REGWIDTH(sp) /* restore temporaries */
csrrw sp, CSR_MSCRATCH, sp /* restore sp from scratch */
mret
common_mint_handler: /* t1 has sig ptr, t2 has mcause */
LI(t3, 1)
sll t3, t3, t2 /* create mask 1<<mcause */
csrrc t4, CSR_MIP, t3 /* read, then attempt to clear int pend bit */
csrrc t4, CSR_MIE, t3 /* read, then attempt to clear int pend bit */
sv_mip: /* note: clear has no effect on MxIP */
SREG t4, 2*REGWIDTH(t1) /* save 3rd sig value, (mip) */
/* case table branch to interrupt clearing code, depending on mcause */
slli t2, t2, 3 /* convert mcause to 8B offset */
LA( t3, clrint_tbl ) /* load jump table address */
add t3, t3, t2 /* index into to it, load vector, then jump to it */
LREG t3, 0(t3)
jr t3
clr_sw_int:
RVMODEL_CLEAR_MSW_INT
j resto_rtn
clr_tmr_int:
RVMODEL_CLEAR_MTIMER_INT
j resto_rtn
clr_ext_int:
RVMODEL_CLEAR_MEXT_INT
SREG t3, -3*REGWIDTH(t1) /* save 4rd sig value, (intID) */
j resto_rtn
.align 3
clrint_tbl:
.dword resto_rtn /* int cause 0 is reserved, just return */
.dword clr_sw_int /* int cause 1 Smode SW int */
.dword resto_rtn /* int cause 2 is reserved, just return */
.dword clr_sw_int /* int cause 3 Mmode SW int */
.dword resto_rtn /* int cause 4 is reserved, just return */
.dword clr_tmr_int /* int cause 5 Smode Tmr int */
.dword resto_rtn /* int cause 6 is reserved, just return */
.dword clr_tmr_int /* int cause 7 Mmode Tmr int */
.dword resto_rtn /* int cause 8 is reserved, just return */
.dword clr_ext_int /* int cause 9 Smode Ext int */
.dword resto_rtn /* int cause A is reserved, just return */
.dword clr_ext_int /* int cause B Mmode Ext int */
.dword resto_rtn /* int cause C is reserved, just return */
.dword resto_rtn /* int cause D is reserved, just return */
.dword resto_rtn /* int cause E is reserved, just return */
.dword resto_rtn /* int cause F is reserved, just return */
.dword resto_rtn /* int cause 10 is reserved, just return */
.dword resto_rtn /* int cause 11 is reserved, just return */
.dword resto_rtn /* int cause 12 is reserved, just return */
.dword resto_rtn /* int cause 13 is reserved, just return */
.dword resto_rtn /* int cause 14 is reserved, just return */
.dword resto_rtn /* int cause 15 is reserved, just return */
.dword resto_rtn /* int cause 16 is reserved, just return */
.dword resto_rtn /* int cause 17 is reserved, just return */
.dword resto_rtn /* int cause 18 is reserved, just return */
.dword resto_rtn /* int cause 19 is reserved, just return */
.dword resto_rtn /* int cause 1A is reserved, just return */
.dword resto_rtn /* int cause 1B is reserved, just return */
.dword resto_rtn /* int cause 1C is reserved, just return */
.dword resto_rtn /* int cause 1D is reserved, just return */
.dword resto_rtn /* int cause 1E is reserved, just return */
.dword resto_rtn /* int cause 1F is reserved, just return */
1: // xtvec_installed:
ret
// ----------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------
exit_cleanup://COMPLIANCE_HALT should get here
la t3, tramptbl_sv+ NUM_SPECD_INTCAUSES*4 // end of save area
la t5, mtvec_save
LREG t1, 8(t5)
csrw CSR_MSCRATCH, t1 // restore mscratch
LREG t4, 0(t5) // load orig mtvec
csrrw t2, CSR_MTVEC, t4 // restore mtvec (not redundant)
bne t4, t2, 1f// if saved!=mtvec, done, else need to restore
addi t2, t4, NUM_SPECD_INTCAUSES*4 // start pt is end of vect area
resto_vec: // goes backwards, t2= dest vec tbl ptr,
// t3=src save area ptr, t4=vec tbl begin
lw t6, 0(t3) // read saved tgt entry
sw t6, 0(t2) // restore original tgt
addi t2, t2, -4 // prev tgt index
addi t3, t3, -4 // prev save index
bne t2, t4, resto_vec // didn't get to end, continue
1:
rvtest_end:
.option pop
#endif
#ifdef rvtest_gpr_save
csrw CSR_MSCRATCH, x31 //save x31, get temp pointer
LA(x31, gpr_save)
SREG x0, 0*REGWIDTH(x31)
SREG x1, 1*REGWIDTH(x31)
SREG x2, 2*REGWIDTH(x31)
SREG x3, 3*REGWIDTH(x31)
SREG x4, 4*REGWIDTH(x31)
SREG x5, 5*REGWIDTH(x31)
SREG x6, 6*REGWIDTH(x31)
SREG x7, 7*REGWIDTH(x31)
SREG x8, 8*REGWIDTH(x31)
SREG x9, 9*REGWIDTH(x31)
SREG x10, 10*REGWIDTH(x31)
SREG x11, 11*REGWIDTH(x31)
SREG x12, 12*REGWIDTH(x31)
SREG x13, 13*REGWIDTH(x31)
SREG x14, 14*REGWIDTH(x31)
SREG x15, 15*REGWIDTH(x31)
SREG x16, 16*REGWIDTH(x31)
SREG x17, 17*REGWIDTH(x31)
SREG x18, 18*REGWIDTH(x31)
SREG x19, 19*REGWIDTH(x31)
SREG x20, 20*REGWIDTH(x31)
SREG x21, 21*REGWIDTH(x31)
SREG x22, 22*REGWIDTH(x31)
SREG x23, 23*REGWIDTH(x31)
SREG x24, 24*REGWIDTH(x31)
SREG x25, 25*REGWIDTH(x31)
SREG x26, 26*REGWIDTH(x31)
SREG x27, 27*REGWIDTH(x31)
SREG x28, 28*REGWIDTH(x31)
SREG x29, 29*REGWIDTH(x31)
SREG x30, 30*REGWIDTH(x31)
addi x30, x31, 0 // mv gpr pointer to x30
csrr x31, CSR_MSCRATCH // restore value of x31
SREG x31, 31*REGWIDTH(x30) // store x31
#endif
.endm
.macro RVTEST_DATA_BEGIN
.data
.align 4
.global rvtest_data_begin
rvtest_data_begin:
#ifdef rvtest_mtrap_routine
trapreg_sv:
.fill 7, REGWIDTH, 0xdeadbeef /* handler reg save area, 1 extra wd just in case */
tramptbl_sv: // save area of existing trampoline table
.rept NUM_SPECD_INTCAUSES
J .+0 /* prototype jump instruction, offset to be filled in */
.endr
mtvec_save:
.dword 0 /* save area for incoming mtvec */
mscratch_save:
.dword 0 /* save area for incoming mscratch */
#endif
.endm
.macro RVTEST_DATA_END
.global rvtest_data_end
rvtest_data_end:
.endm
#define RVTEST_CASE(_PNAME,_DSTR,...)
#define RVTEST_FP_ENABLE()\
LI x2, MSTATUS_FS;\
csrrs x3, mstatus,x0;\
or x2, x3, x2;\
csrrw x0,mstatus,x2;
#define RVTEST_SIGBASE(_R,_TAG) \
LA(_R,_TAG);\
.set offset,0;
.set offset,0;
#define _ARG5(_1ST,_2ND, _3RD,_4TH,_5TH,...) _5TH
#define _ARG4(_1ST,_2ND, _3RD,_4TH,...) _4TH
#define _ARG3(_1ST,_2ND, _3RD, ...) _3RD
#define _ARG2(_1ST,_2ND, ...) _2ND
#define _ARG1(_1ST,...) _1ST
#define NARG(...) _ARG5(__VA_OPT__(__VA_ARGS__,)4,3,2,1,0)
#define RVTEST_SIGUPD(_BR,_R,...)\
.if NARG(__VA_ARGS__) == 1;\
SREG _R,_ARG1(__VA_ARGS__,0)(_BR);\
.set offset,_ARG1(__VA_OPT__(__VA_ARGS__,)0)+REGWIDTH;\
.endif;\
.if NARG(__VA_ARGS__) == 0;\
SREG _R,offset(_BR);\
.set offset,offset+REGWIDTH;\
.endif;
#define RVTEST_SIGUPD_F(_BR,_R,_F,...)\
.if NARG(__VA_ARGS__) == 1;\
FSREG _R,_ARG1(__VA_ARGS__,0)(_BR);\
SREG _F,_ARG1(__VA_ARGS__,0)+REGWIDTH(_BR);\
.set offset,_ARG1(__VA_OPT__(__VA_ARGS__,)0)+(REGWIDTH+REGWIDTH);\
.endif;\
.if NARG(__VA_ARGS__) == 0;\
FSREG _R,offset(_BR);\
SREG _F,offset+REGWIDTH(_BR);\
.set offset,offset+(REGWIDTH+REGWIDTH);\
.endif;
#define RVTEST_SIGUPD_FID(_BR,_R,_F,...)\
.if NARG(__VA_ARGS__) == 1;\
SREG _R,_ARG1(__VA_ARGS__,0)(_BR);\
SREG _F,_ARG1(__VA_ARGS__,0)+REGWIDTH(_BR);\
.set offset,_ARG1(__VA_ARGS__,0)+(2*REGWIDTH);\
.endif;\
.if NARG(__VA_ARGS__) == 0;\
SREG _R,offset(_BR);\
SREG _F,offset+REGWIDTH(_BR);\
.set offset,offset+(2*REGWIDTH);\
.endif;
#define RVTEST_VALBASEUPD(_BR,...)\
.if NARG(__VA_ARGS__) == 0;\
addi _BR,_BR,2040;\
.endif;\
.if NARG(__VA_ARGS__) == 1;\
LA(_BR,_ARG1(__VA_ARGS__,x0));\
.endif;
#define RVTEST_VALBASEMOV(_NR,_BR)\
add _NR, _BR, x0;
/*
* RVTEST_BASEUPD(base reg) - updates the base register the last signature address + REGWIDTH
* RVTEST_BASEUPD(base reg, new reg) - moves value of the next signature region to update into new reg
* The hidden variable offset is reset always
*/
#define RVTEST_BASEUPD(_BR,...)\
.if NARG(__VA_ARGS__) == 0;\
addi _BR,_BR,offset;\
.endif;\
.if NARG(__VA_ARGS__) == 1;\
addi _ARG1(__VA_ARGS__,x0),_BR,offset;\
.endif;\
.set offset,0;
//------------------------------ BORROWED FROM ANDREW's RISC-V TEST MACROS -----------------------//
#define MASK_XLEN(x) ((x) & ((1 << (__riscv_xlen - 1) << 1) - 1))
#define SEXT_IMM(x) ((x) | (-(((x) >> 11) & 1) << 11))
#define TEST_JALR_OP(tempreg, rd, rs1, imm, swreg, offset,adj) \
5: ;\
LA(rd,5b ) ;\
.if adj & 1 == 1 ;\
LA(rs1, 3f-imm+adj-1 ) ;\
jalr rd, imm+1(rs1) ;\
.else ;\
LA(rs1, 3f-imm+adj) ;\
jalr rd, imm(rs1) ;\
.endif ;\
nop ;\
nop ;\
xori rd,rd, 0x2 ;\
j 4f ;\
;\
3: .if adj & 2 == 2 ;\
.fill 2,1,0x00 ;\
.endif ;\
xori rd,rd, 0x3 ;\
j 4f ;\
.if adj&2 == 2 ;\
.fill 2,1,0x00 ;\
.endif ;\
;\
4: LA(tempreg, 5b ) ;\
andi tempreg,tempreg,~(3) ;\
sub rd,rd,tempreg ;\
RVTEST_SIGUPD(swreg,rd,offset)
//SREG rd, offset(swreg);
#define TEST_JAL_OP(tempreg, rd, imm, label, swreg, offset, adj)\
5: ;\
LA(tempreg, 2f ) ;\
jalr x0,0(tempreg) ;\
6: LA(tempreg, 4f ) ;\
jalr x0,0(tempreg) ;\
1: .if adj & 2 == 2 ;\
.fill 2,1,0x00 ;\
.endif ;\
xori rd,rd, 0x1 ;\
beq x0,x0,6b ;\
.if adj & 2 == 2 ;\
.fill 2,1,0x00 ;\
.endif ;\
.if (imm/2) - 2 >= 0 ;\
.set num,(imm/2)-2 ;\
.else ;\
.set num,0 ;\
.endif ;\
.if label == 3f ;\
.set num,0 ;\
.endif ;\
.rept num ;\
nop ;\
.endr ;\
;\
2: jal rd, label+(adj) ;\
.if adj & 2 == 2 ;\
nop ;\
nop ;\
.endif ;\
xori rd,rd, 0x2 ;\
j 4f ;\
.if (imm/2) - 3 >= 0 ;\
.set num,(imm/2)-3 ;\
.else ;\
.set num,0 ;\
.endif ;\
.if label == 1b ;\
.set num,0 ;\
.endif ;\
.rept num ;\
nop ;\
.endr ;\
3: .if adj & 2 == 2 ;\
.fill 2,1,0x00 ;\
.endif ;\
xori rd,rd, 0x3 ;\
LA(tempreg, 4f ) ;\
jalr x0,0(tempreg) ;\
.if adj&2 == 2 ;\
.fill 2,1,0x00 ;\
.endif ;\
4: LA(tempreg, 5b ) ;\
andi tempreg,tempreg,~(3) ;\
sub rd,rd,tempreg ;\
RVTEST_SIGUPD(swreg,rd,offset)
//SREG rd, offset(swreg);
#define TEST_BRANCH_OP(inst, tempreg, reg1, reg2, val1, val2, imm, label, swreg, offset,adj) \
LI(reg1, MASK_XLEN(val1)) ;\
LI(reg2, MASK_XLEN(val2)) ;\
addi tempreg,x0,0 ;\
j 2f ;\
;\
1: .if adj & 2 == 2 ;\
.fill 2,1,0x00 ;\
.endif ;\
addi tempreg,tempreg, 0x1 ;\
j 4f ;\
.if adj & 2 == 2 ;\
.fill 2,1,0x00 ;\
.endif ;\
.if (imm/2) - 2 >= 0 ;\
.set num,(imm/2)-2 ;\
.else ;\
.set num,0 ;\
.endif ;\
.if label == 3f ;\
.set num,0 ;\
.endif ;\
.rept num ;\
nop ;\
.endr ;\
;\
2: inst reg1, reg2, label+adj ;\
addi tempreg, tempreg,0x2 ;\
j 4f ;\
.if (imm/4) - 3 >= 0 ;\
.set num,(imm/4)-3 ;\
.else ;\
.set num,0 ;\
.endif ;\
.if label == 1b ;\
.set num,0 ;\
.endif ;\
.rept num ;\
nop ;\
.endr ;\
;\
3: .if adj & 2 == 2 ;\
.fill 2,1,0x00 ;\
.endif ;\
addi tempreg, tempreg,0x3 ;\
j 4f ;\
.if adj&2 == 2 ;\
.fill 2,1,0x00 ;\
.endif ;\
;\
4: RVTEST_SIGUPD(swreg,tempreg,offset)
//SREG tempreg, offset(swreg);
#define TEST_STORE(swreg,testreg,index,rs1,rs2,rs2_val,imm_val,offset,inst,adj) ;\
LI(rs2,rs2_val) ;\
addi rs1,swreg,offset+adj ;\
LI(testreg,imm_val) ;\
sub rs1,rs1,testreg ;\
inst rs2, imm_val(rs1) ;\
nop ;\
nop
#define TEST_LOAD(swreg,testreg,index,rs1,destreg,imm_val,offset,inst,adj) ;\
LA(rs1,rvtest_data+(index*4)+adj-imm_val) ;\
inst destreg, imm_val(rs1) ;\
nop ;\
nop ;\
RVTEST_SIGUPD(swreg,destreg,offset)
//SREG destreg, offset(swreg);
#define TEST_STORE_F(swreg,testreg,index,rs1,rs2,rs2_val,imm_val,offset,inst,adj,flagreg) ;\
LI(flagreg,rs2_val) ;\
fmv.w.x rs2, flagreg ;\
addi rs1,swreg,offset+adj ;\
LI(testreg,imm_val) ;\
sub rs1,rs1,testreg ;\
inst rs2, imm_val(rs1) ;\
nop ;\
nop ;\
csrrs flagreg, fflags, x0 ;\
RVTEST_SIGUPD(swreg,flagreg,offset)
#define TEST_LOAD_F(swreg,testreg,index,rs1,destreg,imm_val,offset,inst,adj,flagreg) ;\
LA(rs1,rvtest_data+(index*4)+adj-imm_val) ;\
inst destreg, imm_val(rs1) ;\
nop ;\
nop ;\
csrrs flagreg, fflags, x0 ;\
RVTEST_SIGUPD_F(swreg,destreg,flagreg,offset)
#define TEST_CSR_FIELD(ADDRESS,TEMP_REG,MASK_REG,NEG_MASK_REG,VAL,DEST_REG,OFFSET,BASE_REG) \
LI(TEMP_REG,VAL);\
and TEMP_REG,TEMP_REG,MASK_REG;\
csrr DEST_REG,ADDRESS;\
and DEST_REG,DEST_REG,NEG_MASK_REG;\
or TEMP_REG,TEMP_REG,DEST_REG;\
csrw ADDRESS,TEMP_REG;\
csrr DEST_REG,ADDRESS;\
RVTEST_SIGUPD(BASE_REG,DEST_REG,OFFSET)
#define TEST_CASE(testreg, destreg, correctval, swreg, offset, code... ) \
code; \
RVTEST_SIGUPD(swreg,destreg,offset); \
RVMODEL_IO_ASSERT_GPR_EQ(testreg, destreg, correctval)
#define TEST_CASE_F(testreg, destreg, correctval, swreg, flagreg, offset, code... ) \
code; \
RVTEST_SIGUPD_F(swreg,destreg,flagreg,offset); \
RVMODEL_IO_ASSERT_GPR_EQ(testreg, destreg, correctval)
#define TEST_CASE_FID(testreg, destreg, correctval, swreg, flagreg, offset, code... ) \
code; \
RVTEST_SIGUPD_FID(swreg,destreg,flagreg,offset); \
RVMODEL_IO_ASSERT_GPR_EQ(testreg, destreg, correctval)
#define TEST_AUIPC(inst, destreg, correctval, imm, swreg, offset, testreg) \
TEST_CASE(testreg, destreg, correctval, swreg, offset, \
LA testreg, 1f; \
1: \
inst destreg, imm; \
sub destreg, destreg, testreg; \
)
//Tests for a instructions with register-immediate operand
#define TEST_IMM_OP( inst, destreg, reg, correctval, val, imm, swreg, offset, testreg) \
TEST_CASE(testreg, destreg, correctval, swreg, offset, \
LI(reg, MASK_XLEN(val)); \
inst destreg, reg, SEXT_IMM(imm); \
)
//Tests for floating-point instructions with a single register operand
#define TEST_FPSR_OP( inst, destreg, freg, rm, correctval, valaddr_reg, val_offset, flagreg, swreg, offset, testreg) \
TEST_CASE_F(testreg, destreg, correctval, swreg, flagreg, offset, \
FLREG freg, val_offset(valaddr_reg); \
csrrwi x0, frm, rm; \
inst destreg, freg; \
csrrs flagreg, fflags, x0; \
)
//Tests for floating-point instructions with a single register operand and integer destination register
#define TEST_FPID_OP( inst, destreg, freg, rm, correctval, valaddr_reg, val_offset, flagreg, swreg, offset, testreg) \
TEST_CASE_FID(testreg, destreg, correctval, swreg, flagreg, offset, \
FLREG freg, val_offset(valaddr_reg); \
csrrwi x0, frm, rm; \
inst destreg, freg; \
csrrs flagreg, fflags, x0; \
)
//Tests for floating-point instructions with a single register operand and integer operand register
#define TEST_FPIO_OP( inst, destreg, freg, rm, correctval, valaddr_reg, val_offset, flagreg, swreg, offset, testreg) \
TEST_CASE_F(testreg, destreg, correctval, swreg, flagreg, offset, \
LREG freg, val_offset(valaddr_reg); \
csrrwi x0, frm, rm; \
inst destreg, freg; \
csrrs flagreg, fflags, x0; \
)
//Tests for a instructions with register-register operand
#define TEST_RRI_OP(inst, destreg, reg1, reg2, imm, correctval, val1, val2, swreg, offset, testreg) \
TEST_CASE(testreg, destreg, correctval, swreg, offset, \
LI(reg1, MASK_XLEN(val1)); \
LI(reg2, MASK_XLEN(val2)); \
inst destreg, reg1, reg2, imm; \
)
//Tests for a instructions with register-register operand
#define TEST_RI_OP(inst, destreg, reg1, reg2, imm, correctval, val1, val2, swreg, offset, testreg) \
TEST_CASE(testreg, destreg, correctval, swreg, offset, \
LI(reg1, MASK_XLEN(val1)); \
LI(reg2, MASK_XLEN(val2)); \
inst destreg, reg1, reg2, imm; \
)
//Tests for a instructions with register-register operand
#define TEST_RR_OP(inst, destreg, reg1, reg2, correctval, val1, val2, swreg, offset, testreg) \
TEST_CASE(testreg, destreg, correctval, swreg, offset, \
LI(reg1, MASK_XLEN(val1)); \
LI(reg2, MASK_XLEN(val2)); \
inst destreg, reg1, reg2; \
)
//Tests for floating-point instructions with register-register operand
#define TEST_FPRR_OP(inst, destreg, freg1, freg2, rm, correctval, valaddr_reg, val_offset, flagreg, swreg, offset, testreg) \
TEST_CASE_F(testreg, destreg, correctval, swreg, flagreg, offset, \
FLREG freg1, val_offset(valaddr_reg); \
FLREG freg2, val_offset+FREGWIDTH(valaddr_reg); \
csrrwi x0, frm, rm; \
inst destreg, freg1, freg2; \
csrrs flagreg, fflags, x0; \
)
//Tests for floating-point CMP instructions with register-register operand
#define TEST_FCMP_OP(inst, destreg, freg1, freg2, correctval, valaddr_reg, val_offset, flagreg, swreg, offset, testreg) \
TEST_CASE_FID(testreg, destreg, correctval, swreg, flagreg, offset, \
FLREG freg1, val_offset(valaddr_reg); \
FLREG freg2, val_offset+FREGWIDTH(valaddr_reg); \
inst destreg, freg1, freg2; \
csrrs flagreg, fflags, x0; \
)
//Tests for floating-point R4 type instructions
#define TEST_FPR4_OP(inst, destreg, freg1, freg2, freg3, rm, correctval, valaddr_reg, val_offset, flagreg, swreg, offset, testreg) \
TEST_CASE_F(testreg, destreg, correctval, swreg, flagreg, offset, \
FLREG freg1, val_offset(valaddr_reg); \
FLREG freg2, val_offset+FREGWIDTH(valaddr_reg); \
FLREG freg3, val_offset+2*FREGWIDTH(valaddr_reg); \
csrrwi x0, frm, rm; \
inst destreg, freg1, freg2, freg3; \
csrrs flagreg, fflags, x0; \
)
#define TEST_CNOP_OP( inst, testreg, imm_val, swreg, offset) \
TEST_CASE(testreg, x0, 0, swreg, offset, \
inst imm_val; \
)
#define TEST_CMV_OP( inst, destreg, reg, correctval, val2, swreg, offset, testreg) \
TEST_CASE(testreg, destreg, correctval, swreg, offset, \
LI(reg, MASK_XLEN(val2)); \
inst destreg, reg; \
)
#define TEST_CR_OP( inst, destreg, reg, correctval, val1, val2, swreg, offset, testreg) \
TEST_CASE(testreg, destreg, correctval, swreg, offset, \
LI(reg, MASK_XLEN(val2)); \
LI(destreg, MASK_XLEN(val1)); \
inst destreg, reg; \
)
#define TEST_CI_OP( inst, destreg, correctval, val, imm, swreg, offset, testreg) \
TEST_CASE(testreg, destreg, correctval, swreg, offset, \
LI(destreg, MASK_XLEN(val)); \
inst destreg, imm; \
)
#define TEST_CADDI4SPN_OP( inst, destreg, correctval, imm, swreg, offset, testreg) \
TEST_CASE(testreg, destreg, correctval, swreg, offset, \
LI(x2, 0); \
inst destreg, x2,imm; \
)
#define TEST_CBRANCH_OP(inst, tempreg, reg2, val2, imm, label, swreg, offset) \
LI(reg2, MASK_XLEN(val2)) ;\
j 2f ;\
addi tempreg, x0,0 ;\
.option push ;\
.option norvc ;\
1: addi tempreg, tempreg,0x1 ;\
j 4f ;\
.option pop ;\
.if (imm/2) - 4 >= 0 ;\
.set num,(imm/2)-4 ;\
.else ;\
.set num,0 ;\
.endif ;\
.if label == 3f ;\
.set num,0 ;\
.endif ;\
.rept num ;\
c.nop ;\
.endr ;\
2: inst reg2, label ;\
.option push ;\
.option norvc ;\
addi tempreg, tempreg, 0x2 ;\
j 4f ;\
.option pop ;\
.if (imm/2) - 5 >= 0 ;\
.set num,(imm/2)-5 ;\
.else ;\
.set num,0 ;\
.endif ;\
.if label == 1b ;\
.set num,0 ;\
.endif ;\
.rept num ;\
c.nop ;\
.endr ;\
;\
3: addi tempreg, tempreg ,0x3 ;\
;\
4: RVTEST_SIGUPD(swreg,tempreg,offset)
//SREG tempreg, offset(swreg);
#define TEST_CJ_OP(inst, tempreg, imm, label, swreg, offset) \
.option push ;\
.option norvc ;\
j 2f ;\
addi tempreg,x0,0 ;\
1: addi tempreg, tempreg,0x1 ;\
j 4f ;\
.option pop ;\
.if (imm/2) - 4 >= 0 ;\
.set num,(imm/2)-4 ;\
.else ;\
.set num,0 ;\
.endif ;\
.if label == 3f ;\
.set num,0 ;\
.endif ;\
.rept num ;\
c.nop ;\
.endr ;\
2: inst label ;\
.option push ;\
.option norvc ;\
addi tempreg, tempreg, 0x2 ;\
j 4f ;\
.option pop ;\
.if (imm/2) - 5 >= 0 ;\
.set num,(imm/2)-5 ;\
.else ;\
.set num,0 ;\
.endif ;\
.if label == 1b ;\
.set num,0 ;\
.endif ;\
.rept num ;\
c.nop ;\
.endr ;\
;\
3: addi tempreg, tempreg, 0x3 ;\
;\
4: RVTEST_SIGUPD(swreg,tempreg,offset)
//SREG tempreg, offset(swreg);
#define TEST_CJAL_OP(inst, tempreg, imm, label, swreg, offset) \
5: ;\
j 2f ;\
;\
.option push ;\
.option norvc ;\
1: xori x1,x1, 0x1 ;\
j 4f ;\
.option pop ;\
.if (imm/2) - 4 >= 0 ;\
.set num,(imm/2)-4 ;\
.else ;\
.set num,0 ;\
.endif ;\
.if label == 3f ;\
.set num,0 ;\
.endif ;\
.rept num ;\
c.nop ;\
.endr ;\
2: inst label ;\
.option push ;\
.option norvc ;\
xori x1,x1, 0x2 ;\
j 4f ;\
.option pop ;\
.if (imm/2) - 5 >= 0 ;\
.set num,(imm/2)-5 ;\
.else ;\
.set num,0 ;\
.endif ;\
.if label == 1b ;\
.set num,0 ;\
.endif ;\
.rept num ;\
c.nop ;\
.endr ;\
;\
3: xori x1,x1, 0x3 ;\
;\
4: LA(tempreg, 5b) ;\
andi tempreg,tempreg,~(3) ;\
sub x1,x1,tempreg ;\
RVTEST_SIGUPD(swreg,x1,offset)
//SREG x1, offset(swreg);
#define TEST_CJR_OP(tempreg, rs1, swreg, offset) \
5: ;\
LA(rs1, 3f) ;\
;\
2: c.jr rs1 ;\
xori rs1,rs1, 0x2 ;\
j 4f ;\
;\
3: xori rs1,rs1, 0x3 ;\
;\
4: LA(tempreg, 5b) ;\
andi tempreg,tempreg,~(3) ;\
sub rs1,rs1,tempreg ;\
RVTEST_SIGUPD(swreg,rs1,offset)
//SREG rs1, offset(swreg);
#define TEST_CJALR_OP(tempreg, rs1, swreg, offset) \
5: ;\
LA(rs1, 3f ) ;\
;\
2: c.jalr rs1 ;\
xori x1,x1, 0x2 ;\
j 4f ;\
;\
3: xori x1,x1, 0x3 ;\
;\
4: LA(tempreg, 5b ) ;\
andi tempreg,tempreg,~(3) ;\
sub x1,x1,tempreg ;\
RVTEST_SIGUPD(swreg,x1,offset)
//SREG x1, offset(swreg);
//--------------------------------- Migration aliases ------------------------------------------
#ifdef RV_COMPLIANCE_RV32M
#warning "RV_COMPLIANCE_RV32M macro will be deprecated."
#define RVMODEL_BOOT \
RVTEST_IO_INIT; \
RV_COMPLIANCE_RV32M ; \
RV_COMPLIANCE_CODE_BEGIN
#endif
#define SWSIG(a, b)
#ifdef RV_COMPLIANCE_DATA_BEGIN
#warning "RV_COMPLIANCE_DATA_BEGIN macro deprecated in v0.2. Please use RVMODEL_DATA_BEGIN instead"
#define RVMODEL_DATA_BEGIN \
RV_COMPLIANCE_DATA_BEGIN
#endif
#ifdef RV_COMPLIANCE_DATA_END
#warning "RV_COMPLIANCE_DATA_END macro deprecated in v0.2. Please use RVMODEL_DATA_END instead"
#define RVMODEL_DATA_END \
RV_COMPLIANCE_DATA_END
#endif
#ifdef RV_COMPLIANCE_HALT
#warning "RV_COMPLIANCE_HALT macro deprecated in v0.2. Please use RVMODEL_HALT instead"
#define RVMODEL_HALT \
RV_COMPLIANCE_HALT
#endif
#ifdef RVTEST_IO_ASSERT_GPR_EQ
#warning "RVTEST_IO_ASSERT_GPR_EQ macro deprecated in v0.2. Please use RVMODEL_IO_ASSERT_GPR_EQ instead"
#define RVMODEL_IO_ASSERT_GPR_EQ(_SP, _R, _I) \
RVTEST_IO_ASSERT_GPR_EQ(_SP,_R, _I)
#endif
#ifdef RVTEST_IO_WRITE_STR
#warning "RVTEST_IO_WRITE_STR macro deprecated in v0.2. Please use RVMODEL_IO_WRITE_STR instead"
#define RVMODEL_IO_WRITE_STR(_SP, _STR) \
RVTEST_IO_WRITE_STR(_SP, _STR)
#endif
#ifdef RVTEST_IO_INIT
#warning "RVTEST_IO_INIT is deprecated in v0.2. Please use RVMODEL_BOOT for initialization"
#endif
#ifdef RVTEST_IO_CHECK
#warning "RVTEST_IO_CHECK is deprecated in v0.2.
#endif