forked from Github_Repos/cvw
1185 lines
50 KiB
C
1185 lines
50 KiB
C
|
#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 it’s 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 isn’t 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
|