// ----------- // Copyright (c) 2020-2023. RISC-V International. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause // ----------- // This file is divided into the following sections: // RV Arch Test Constants // general test and helper macros, required, optional, or just useful // _ARGn, SIG[BASE/UPD[_F/ID]],BASEUPD,BIT,LA ,LI,RVTEST_[INIT/SAVE]_GPRS, XCSR_RENAME // RV ARCH Test Interrupt Macros ****FIXME:spec which regs must not be altered // primary macros used by handle: RVTEST_TRAP{_PROLOG/_HANDLER/_EPILOG/SAVEAREA} // required test format spec macros: RVTEST_{Code/DATA/SIG}{_BEGIN/_END} // macros from Andrew Waterman's risc-v test macros // deprecated macro name aliases, just for migration ease // The resulting memory layout of the trap handler is (MACRO_NAME, label [function]) //**************************************************************** // (code section) // RVMODEL_BOOT // rvtest_entry_point: [boot code] // RVTEST_CODE_BEGIN // rvtest_init: [TRAP_PROLOG] (m, ms, or msv) // [INIT_GPRS] // rvtest_code_begin: //***************************** //********(body of tests)****** //***************************** // RVTEST_CODE_END // rvtest_code_end: [*optional* SAVE_GPRS routine] // [RVTEST_GOTO_MMODE ] **FIXME** this won't work if MMU enabled unless VA=PA // cleanup_epilogs [TRAP_EPILOG (m, ms, or msv)] (jump to exit_cleanup) // [TRAP_HANDLER (m, ms, or msv)] // exit_cleanup: [RVMODEL_HALT macro or a branch to it.] // //--------------------------------this could start a new section-------------------------------- // (Data section) - align to 4K boundary // RVTEST_DATA_BEGIN //************************************** //*****(Ld/St test data is here)******** //************************************** // //************************************** //*****(trap handler data is here)****** //************************************** // // rvtest_trap_sig: [global trap signature start (shared by all modes) inited to mtrap_sigptr] **FIXME: needs VA=PA // RVTEST_TRAP_SAVEAREA [handler sv area(m, ms, or msv) temp reg save, CSRs, tramp table, ptrs] // rvtest_data_begin: [input data (shared by all modes)] // RVTEST_DATA_END // rvtest_data_end: // RVTEST_ROOT_PG_TBL [sets up identity map (VA=PA) // sroot_pg_tbl: (if smode) // vroot_pg_tbl: (if hypervisor) //--------------------------------this could start a new section-------------------------------- // RVTEST_SIG_BEGIN // RVMODEL_DATA_BEGIN // rvtest_sig_begin: [beginning of signature, used by signature dump, can be used by tests] // mtrap_sigptr: [global trap signature start (shared by all modes)] - defined by tests // gpr_save: [gpr save area (optional, enabled if rvtest_gpr_save is defined)] // RVTEST_SIG_END // rvtest_sig_end: [global test end signature (shared by all modes)] (shouldn't matter what RVMODEL_DATA_END does) // RVMODEL_DATA_END //--------------------------------end of test-------------------------------- /* The following macros are optional if interrupt tests are enabled (defaulted if not defined): RVMODEL_SET_[M/V/S]_[SW]_INT RVMODEL_CLR_[M/V/S]_[SW/TIMTER/EXT]_INT rvtest_[M/V/S]trap_routine GOTO_[M/S/U]MODE, INSTANTIATE_MODE_MACRO (prolog/handler/epilog/savearea) The following macro is optional, and defaults to fence.i if not defined RVMODEL.FENCEI The following variables are used if interrupt tests are enabled (defaulted if not defined): NUM_SPECD_INTCAUSES The following variables are optional if exception tests are enabled (defaulted if not defined): DATA_REL_TVAL_MSK CODE_REL_TVAL_MSK The following variables are optional: rvtest_gpr_save: if defined, stores GPR contents into signature at test end (for debug) The following labels are required and defined by required macros: rvtest_code_begin: defined by RVTEST_CODE_BEGIN macro (boot code can precede this) rvtest_code_end: defined by RVTEST_CODE_END macro (trap handlers follow this) rvtest_data_begin: defined by RVTEST_DATA_BEGIN macro rvtest_data_end: defined by RVTEST_DATA_END macro rvtest_sig_begin: defined by RVTEST_SIG_BEGIN macro (after RVMODEL_DATA_BEGIN) defines signature begin rvtest_sig_end: defined by RVTEST_SIG_END macro (before RVMODEL_DATA_END) defines signature end rvtest_Sroot_pg_tbl: defined by RVTEST_PTE_IDENT_MAP macro inside RVTEST_DATA_BEGIN if Smode implemented rvtest_Vroot_pg_tbl: defined by RVTEST_PTE_IDENT_MAP macro inside RVTEST_DATA_BEGIN if VSmode implemented labels/variables that must be defined by the DUT in model specific macros or #defines mtrap_sigptr: defined by test if traps are possible, else is defaulted */ // don't put C-style macros (#define xxx) inside assembly macros; C-style is evaluated before assembly #include "encoding.h" #include "test_macros.h" #define RVTEST_ISA(_STR) //empty macro used by framework #define T1 x6 #define T2 x7 #define T3 x8 #define T4 x9 #define T5 x10 #define T6 x11 #define MIN(a,b) (((a)<(b))?(a):(b)) #define MAX(a,b) (((a)>(b))?(a):(b)) #define BIT(addr, bit) (((addr)>>(bit))&1) #define MASK (((1<<(XLEN-1))-1) + (1<<(XLEN-1))) // XLEN bits of 1s #define MASK_XLEN(val) val&MASK // shortens 64b values to XLEN when XLEN==32 #define REGWIDTH (XLEN>>3) // in units of #bytes #define WDSZ 32 #define WDSGN ( WDSZ -1) #define WDMSK ( (1 << WDSZ) -1) #define SEXT_WRD(x) ((x & WDMSK) | (-BIT((x), WRDSGN)<< WRDSZ)) #define IMMSZ 12 #define IMMSGN (IMMSZ -1) #define IMMMSK ( (1 << IMMSZ)-1) #define SEXT_IMM(x) ((x & IMMMSK) | (-BIT((x), IMMSGN)<< IMMSZ)) #define LIMMSZ (WDSZ - IMMSZ) #define LIMMSGN (LIMMSZ -1) #define LIMMMSK ( (1 <> 3) // in units of #bytes #define WDBYTMSK (WDBYTSZ-1) #define ALIGNSZ ((XLEN>>5)+2) // log2(XLEN): 2,3,4 for XLEN 32,64,128 #if XLEN>FLEN #define SIGALIGN REGWIDTH #else #define SIGALIGN FREGWIDTH #endif #ifndef RVMODEL_MTVEC_ALIGN #define MTVEC_ALIGN 6 // ensure that a trampoline is on a typical cacheline boundary, just in case #else #define MTVEC_ALIGN RVMODEL_MTVEC_ALIGN //Let the model defined value be used for required trap handler alignment based on implemented MTVEC #endif //============================================================================== // this section has RV Arch Test Constants, mostly YAML based. // It ensures they're defined & defaulted if necessary) //============================================================================== // set defaults #ifndef NUM_SPECD_INTCAUSES #define NUM_SPECD_INTCAUSES 16 #define INT_CAUSE_MSK ((1<<4)-1) #endif // set defaults #ifndef NUM_SPECD_EXCPTCAUSES #define NUM_SPECD_EXCPTCAUSES 16 #define EXCPT_CAUSE_MSK ((1<<4)-1) #endif // set defaults #ifndef RVMODEL_CBZ_BLOCKSIZE #define RVMODEL_CBZ_BLOCKSIZE 64 #endif // set defaults #ifndef RVMODEL_CMO_BLOCKSIZE #define RVMODEL_CMO_BLOCKSIZE 64 #endif //========================================================================================== // By default, ZIFENCE is defined as nop for the implementation that does not support Zifencei // Implementations that support Zifencei may use the fence.i instruction. // This only gets executed if xTVEC is not writable to point to the trap trampoline, // and if it isn't writable, the model better have the zifencei extension implemented. //========================================================================================== #ifndef RVMODEL_FENCEI #ifndef ZIFENCE #define RVMODEL_FENCEI nop // make sure ifetches get new code #else #define RVMODEL_FENCEI fence.i #endif #endif #ifndef UNROLLSZ #define UNROLLSZ 5 #endif // **Note** that this is different that previous DATA_REL_TVAL_MASK! This is the OR of Code_Rel+Data_Rel // if xTVAL is set to zero for some cause, then the corresponding bit in SET_REL_TVAL_MSK should be cleared #ifndef SET_REL_TVAL_MSK #define SET_REL_TVAL_MSK ((1<>IMMSGN)==0) /* fits 12b signed imm (properly sgnext)? */ ;\ li reg, imm12 /* yes, <= 12bit, will be simple li */ ;\ .else ;\ lui reg, (((immx>>IMMSZ)+cry) & LIMMMSK) /* <= 32b, use lui/addi */ ;\ .if ((imm&IMMMSK)!=0) /* but skip this if lower bits are zero */ ;\ addi reg, reg, imm12 ;\ .endif ;\ .endif #else #define LI(reg, imm) ;\ .option push ;\ .option norvc ;\ .set immx, (imm & MASK) /* trim to XLEN (noeffect on RV64) */ ;\ /***************** used in loop that detects bitmasks */ ;\ .set edge1, 1 /* 1st "1" bit pos scanning r to l */ ;\ .set edge2, 0 /* 1st "0" bit pos scanning r to l */ ;\ .set fnd1, -1 /* found 1st "1" bit pos scanning r to l */ ;\ .set fnd2, -1 /* found 1st "0" bit pos scanning r to l */ ;\ .set imme, ((immx^(-BIT(immx,0 )))&MASK) /* cvt to even, cvt back at end */ ;\ .set pos, 0 ;\ /***************** used in code that checks for 32b immediates */ ;\ .set absimm, ((immx^(-BIT(immx,XLEN-1)))&MASK) /* cvt to posnum to simplify code */ ;\ .set cry, (BIT(immx, IMMSGN)) ;\ .set imm12, (SEXT_IMM(immx)) ;\ /***************** used in code that gnerates bitmasks */ ;\ .set even, (1-BIT(imm, 0)) /* imm has at least 1 trailing zero */ ;\ .set cryh, (BIT(immx, IMMSGN+32)) ;\ /******** loop finding rising/falling edge fm LSB-MSB given even operand ****/ ;\ .rept XLEN ;\ .if (fnd1<0) /* looking for first edge? */ ;\ .if (BIT(imme,pos)==1) /* look for falling edge[pos] */ ;\ .set edge1,pos /* fnd falling edge, don’t chk for more */ ;\ .set fnd1,0 ;\ .endif ;\ .elseif (fnd2<0) /* looking for second edge? */ ;\ .if (BIT(imme,pos)==0) /* yes, found rising edge[pos]? */ ;\ .set edge2, pos /* fnd rising edge, don’t chk for more */ ;\ .set fnd2,0 ;\ .endif ;\ .endif ;\ .set pos, pos+1 /* keep looking (even if already found) */ ;\ .endr ;\ /***************** used in code that generates shifted 32b values */ ;\ .set immxsh, (immx>>edge1) /* *sh variables only used if positive */ ;\ .set imm12sh,(SEXT_IMM(immxsh))/* look @1st 12b of shifted imm val */ ;\ .set crysh, (BIT(immxsh, IMMSGN)) ;\ .set absimmsh, immxsh /* pos, no inversion needed, just shift */ ;\ /*******does it fit into std li or lui+li sequence****************************/ ;\ .if ((absimm>>IMMSGN)==0) /* fits 12b signed imm (properly sgnext)? */ ;\ li reg, imm12 /* yes, <= 12bit, will be simple li */ ;\ .elseif ((absimm+ (cry << IMMSZ) >> WDSGN)==0)/*fits 32b sgnimm?(w/ sgnext)?*/;\ lui reg, (((immx>>IMMSZ)+cry) & LIMMMSK) /* <= 32b, use lui/addi */ ;\ .if ((imm&IMMMSK)!=0) /* but skip this if lower bits are zero */ ;\ addi reg, reg, imm12 ;\ .endif ;\ /*********** look for 0->1->0 masks, or inverse sgl/multbit *************/ ;\ .elseif ( even && (fnd2<0)) /* only rising edge, so 111000 */ ;\ li reg, -1 ;\ slli reg, reg, edge1 /* make 111s --> 000s mask */ ;\ .elseif (!even && (fnd2<0)) /* only falling edge, so 000111 */ ;\ li reg, -1 ;\ srli reg, reg, XLEN-edge1 /* make 000s --> 111s mask */ ;\ .elseif (imme == (1<>IMMSGN)==0))/* fits 12b after shift? */ ;\ li reg, imm12sh /* <= 12bit, will be simple li */ ;\ slli reg, reg, edge1 /* add trailing zeros */ ;\ .elseif ((immx==imme)&&(((absimmsh>>WDSGN)+crysh)==0)) /* fits 32 <>IMMSZ)+crysh)&LIMMMSK /* <=32b, use lui/addi */ ;\ .if ((imm12sh&IMMMSK)!=0) /* but skip this if low bits ==0 */ ;\ addi reg, reg, imm12sh ;\ .endif ;\ slli reg, reg, edge1 /* add trailing zeros */ ;\ .else /* give up, use fixed 8op sequence*/ ;\ /******* TBD add sp case of zero short imms, rmv add/merge shifts ******/ ;\ lui reg, ((immx>>(XLEN-LIMMSZ))+cryh)&LIMMMSK /* 1st 20b (63:44) */ ;\ addi reg, reg, SEXT_IMM(immx>>32) /* nxt 12b (43:32) */ ;\ slli reg, reg, 11 /* following are <12b, don't need SEXT */ ;\ addi reg, reg, (immx>>21) & (IMMMSK>>1) /* nxt 11b (31:21) */ ;\ slli reg, reg, 11 /* mk room for 11b */ ;\ addi reg, reg, (immx>>10) & (IMMMSK>>1) /* nxt 11b (20:10) */ ;\ slli reg, reg, 10 /* mk room for 10b */ ;\ .if ((imm&(IMMMSK>>2))!=0) /* but skip this if lower bits are zero */ ;\ addi reg, reg, (immx) & (IMMMSK>>2) /* lst 10b (09:00) */ ;\ .endif ;\ .if (XLEN==32) ;\ .warning "Should never get here for RV32" ;\ .endif ;\ .endif ;\ .option pop #endif /**** fixed length LA macro; alignment and rvc/norvc unknown before execution ****/ #define LA(reg,val) ;\ .option push ;\ .option rvc ;\ .align UNROLLSZ ;\ .option norvc ;\ la reg,val ;\ .align UNROLLSZ ;\ .option pop #define ADDI(dst, src, imm) /* helper*/ ;\ .if ((imm<=2048) & (imm>=-2048)) ;\ addi dst, src, imm ;\ .else ;\ LI( dst, imm) ;\ addi dst, src, dst ;\ .endif /*****************************************************************/ /**** initialize regs, just to make sure you catch any errors ****/ /*****************************************************************/ /* init regs, to ensure you catch any errors */ .macro RVTEST_INIT_GPRS LI (x1, (0xFEEDBEADFEEDBEAD & MASK)) LI (x2, (0xFF76DF56FF76DF56 & MASK)) LI (x3, (0x7FBB6FAB7FBB6FAB & MASK)) LI (x4, (0xBFDDB7D5BFDDB7D5 & MASK)) LI (x5, (0xDFEEDBEADFEEDBEA & MASK)) LI (x6, (0x6FF76DF56FF76DF5 & MASK)) 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 .endm /******************************************************************************/ /**** this is a helper macro that conditionally instantiates the macros ****/ /**** PROLOG/HANDLER/EPILOG/SAVEAREA depending on test type & mode support ****/ /******************************************************************************/ .macro INSTANTIATE_MODE_MACRO MACRO_NAME #ifdef rvtest_mtrap_routine \MACRO_NAME M // actual m-mode prolog/epilog/handler code #ifdef rvtest_strap_routine \MACRO_NAME S // actual s-mode prolog/epilog/handler code #ifdef rvtest_vtrap_routine \MACRO_NAME V // actual v-mode prolog/epilog/handler code #endif #endif #endif .endm /**************************************************************************/ /**** this is a helper macro defaulting the int macro if its undefined ****/ /**** It builds the macro name from arguments prefix, mode, and type ****/ /**** The macro names are RV_MODEL_SET_[M/S/V][SW/TMR,EXT] ****/ /**** and RV_MODEL_CLR_[M/S/V][SW] ****/ /**************************************************************************/ .macro DFLT_INT_MACRO MACRO_NAME .set MACRO_NAME_, \MACRO_NAME .ifndef MACRO_NAME_ .warning "MACRO_NAME_ is not defined by target. Executing this will end test." #define MACRO_NAME_ j cleanup_epilogs .endif .endm /******************************************************************************/ /**** These macros enable parameterization of trap handlers for each mode ****/ /******************************************************************************/ .macro _XCSR_RENAME_V .set CSR_XSTATUS, CSR_VSSTATUS /****FIXME? is the right substitution? ****/ .set CSR_XEDELEG, CSR_HEDELEG /****FIXME? is the right substitution? ****/ .set CSR_XIE, CSR_HIE .set CSR_XIP, CSR_HIP .set CSR_XCAUSE, CSR_VSCAUSE .set CSR_XEPC, CSR_VSEPC .set CSR_XSATP, CSR_VSATP .set CSR_XSCRATCH,CSR_VSSCRATCH .set CSR_XTVAL, CSR_VSTVAL .set CSR_XTVEC, CSR_VSTVEC .endm .macro _XCSR_RENAME_S .set CSR_XSTATUS, CSR_SSTATUS .set CSR_XEDELEG, CSR_SEDELEG .set CSR_XIE, CSR_SIE .set CSR_XIP, CSR_SIP .set CSR_XCAUSE, CSR_SCAUSE .set CSR_XEPC, CSR_SEPC .set CSR_XSATP, CSR_SATP .set CSR_XSCRATCH,CSR_SSCRATCH .set CSR_XTVAL, CSR_STVAL .set CSR_XTVEC, CSR_STVEC .endm .macro _XCSR_RENAME_M .set CSR_XSTATUS, CSR_MSTATUS .set CSR_XEDELEG, CSR_MEDELEG .set CSR_XIE, CSR_MIE .set CSR_XIP, CSR_MIP .set CSR_XCAUSE, CSR_MCAUSE .set CSR_XEPC, CSR_MEPC .set CSR_XSATP, CSR_SATP .set CSR_XSCRATCH,CSR_MSCRATCH .set CSR_XTVAL, CSR_MTVAL .set CSR_XTVEC, CSR_MTVEC .endm /******************************************************************************/ /**** this is a helper macro that creates CSR aliases so code that ****/ /**** accesses CSRs when V=1 in different modes can share the code ****/ /******************************************************************************/ .macro XCSR_RENAME __MODE__ // enable CSR names to be parameterized, V,S merged .ifc \__MODE__ , M _XCSR_RENAME_M .endif .ifc \__MODE__ , S _XCSR_RENAME_S .endif .ifc \__MODE__ , V _XCSR_RENAME_S .endif .endm /******************************************************************************/ /**** this is a helper macro that creates CSR aliases so code that ****/ /**** accesses CSRs when V=1 in different modes can share the code ****/ /**** this verasion treats Vmodes separately as opposed to XCSR_RENAME ****/ /**** this is used when the using it is run from Mmode ****/ /******************************************************************************/ .macro XCSR_VRENAME __MODE__ // enable CSR names to be parameterized, V,S separate .ifc \__MODE__ , M _XCSR_RENAME_M .endif .ifc \__MODE__ , S _XCSR_RENAME_S .endif .ifc \__MODE__ , V _XCSR_RENAME_V .endif .endm //////////////////////////////////////////////////////////////////////////////////////// //**** This is a helper macro that saves GPRs. Normally used only inside CODE_END ****// //**** Note: this needs a temp scratch register, & there isn't anything that will ****// //**** will work, so we always trash some register, determined by macro param ****// //**** NOTE: Only be use for debug! Xregs containing addresses won't be relocated ****// //////////////////////////////////////////////////////////////////////////////////////// #define RVTEST_SAVE_GPRSM(_BR, _LBL, ...) ;\ .option push ;\ .option norvc ;\ .set __SV_MASK__, -1 /* default to save all */ ;\ .if NARG(__VA_ARGS__) == 1 ;\ .set __SV_MASK__, _ARG1(__VA_OPT__(__VA_ARGS__,0)) ;\ .endif ;\ .set offset, 0 ;\ LA(_BR, _LBL) ;\ .if (__SV_MASK__ & (0x2)) == 0x2 ;\ RVTEST_SIGUPD(_BR, x1) ;\ .endif ;\ .if (__SV_MASK__ & (0x4)) == 0x4 ;\ RVTEST_SIGUPD(_BR, x2) ;\ .endif ;\ .if (__SV_MASK__ & (0x8)) == 0x8 ;\ RVTEST_SIGUPD(_BR, x3) ;\ .endif ;\ .if (__SV_MASK__ & (0x10)) == 0x10 ;\ RVTEST_SIGUPD(_BR, x4) ;\ .endif ;\ .if (__SV_MASK__ & (0x20)) == 0x20 ;\ RVTEST_SIGUPD(_BR, x5) ;\ .endif ;\ .if (__SV_MASK__ & (0x40)) == 0x40 ;\ RVTEST_SIGUPD(_BR, x6) ;\ .endif ;\ .if (__SV_MASK__ & (0x80)) == 0x80 ;\ RVTEST_SIGUPD(_BR, x7) ;\ .endif ;\ .if (__SV_MASK__ & (0x100)) == 0x100 ;\ RVTEST_SIGUPD(_BR, x8) ;\ .endif ;\ .if (__SV_MASK__ & (0x200)) == 0x200 ;\ RVTEST_SIGUPD(_BR, x9) ;\ .endif ;\ .if (__SV_MASK__ & (0x400)) == 0x400 ;\ RVTEST_SIGUPD(_BR, x10) ;\ .endif ;\ .if (__SV_MASK__ & (0x800)) == 0x800 ;\ RVTEST_SIGUPD(_BR, x11) ;\ .endif ;\ .if (__SV_MASK__ & (0x1000)) == 0x1000 ;\ RVTEST_SIGUPD(_BR, x12) ;\ .endif ;\ .if (__SV_MASK__ & (0x2000)) == 0x2000 ;\ RVTEST_SIGUPD(_BR, x13) ;\ .endif ;\ .if (__SV_MASK__ & (0x4000)) == 0x4000 ;\ RVTEST_SIGUPD(_BR, x14) ;\ .endif ;\ .if (__SV_MASK__ & (0x8000)) == 0x8000 ;\ RVTEST_SIGUPD(_BR, x15) ;\ .endif ;\ #ifndef RVTEST_E ;\ .if (__SV_MASK__ & (0x10000)) == 0x10000 ;\ RVTEST_SIGUPD(_BR, x16) ;\ .endif ;\ .if (__SV_MASK__ & (0x20000)) == 0x20000 ;\ RVTEST_SIGUPD(_BR, x17) ;\ .endif ;\ .if (__SV_MASK__ & (0x40000)) == 0x40000 ;\ RVTEST_SIGUPD(_BR, x18) ;\ .endif ;\ .if (__SV_MASK__ & (0x80000)) == 0x80000 ;\ RVTEST_SIGUPD(_BR, x19) ;\ .endif ;\ .if (__SV_MASK__ & (0x100000)) == 0x100000 ;\ RVTEST_SIGUPD(_BR, x20) ;\ .endif ;\ .if (__SV_MASK__ & (0x200000)) == 0x200000 ;\ RVTEST_SIGUPD(_BR, x21) ;\ .endif ;\ .if (__SV_MASK__ & (0x400000)) == 0x400000 ;\ RVTEST_SIGUPD(_BR, x22) ;\ .endif ;\ .if (__SV_MASK__ & (0x800000)) == 0x800000 ;\ RVTEST_SIGUPD(_BR, x23) ;\ .endif ;\ .if (__SV_MASK__ & (0x1000000)) == 0x1000000 ;\ RVTEST_SIGUPD(_BR, x24) ;\ .endif ;\ .if (__SV_MASK__ & (0x2000000)) == 0x2000000 ;\ RVTEST_SIGUPD(_BR, x25) ;\ .endif ;\ .if (__SV_MASK__ & (0x4000000)) == 0x4000000 ;\ RVTEST_SIGUPD(_BR, x26) ;\ .endif ;\ .if (__SV_MASK__ & (0x8000000)) == 0x8000000 ;\ RVTEST_SIGUPD(_BR, x27) ;\ .endif ;\ .if (__SV_MASK__ & (0x10000000)) == 0x10000000 ;\ RVTEST_SIGUPD(_BR, x28) ;\ .endif ;\ .if (__SV_MASK__ & (0x20000000)) == 0x20000000 ;\ RVTEST_SIGUPD(_BR, x29) ;\ .endif ;\ .if (__SV_MASK__ & (0x40000000)) == 0x40000000 ;\ RVTEST_SIGUPD(_BR, x30) ;\ .endif ;\ .if (__SV_MASK__ & (0x80000000)) == 0x80000000 ;\ RVTEST_SIGUPD(_BR, x31) ;\ .endif ;\ .option pop ;\ #endif /********************* REQUIRED FOR NEW TESTS *************************/ /**** new macro encapsulating RVMODEL_DATA_BEGIN (signature area) ****/ /**** defining rvtest_sig_begin: label to enabling direct stores ****/ /**** into the signature area to be properly relocated ****/ /**********************************************************************/ #define RVTEST_SIG_BEGIN ;\ .global rvtest_sig_begin /* defines beginning of signature area */ ;\ RVMODEL_DATA_BEGIN /* model specific stuff */ ;\ sig_begin_canary: ;\ CANARY ;\ rvtest_sig_begin: // Tests allocate normal signature space here, then define // the mtrap_sigptr: label to separate normal and trap // signature space, then allocate trap signature space /********************* REQUIRED FOR NEW TESTS *************************/ /**** new macro definong start of trap signature area ****/ /**** defining rvtest_sig_end: label to enabling direct stores ****/ /**** into the signature area to be properLY relocated ****/ /**********************************************************************/ #define RVTEST_TSIG_BEGIN ;\ .global rvtest_tsig_begin /* defines beginning of trap sig area */ ;\ ;\ tsig_begin_canary: ;\ CANARY ;\ mtrap_sigptr: .fill 3*(XLEN/32),4,0xdeadbeef ;\ tsig_end_canary: ;\ CANARY /********************* REQUIRED FOR NEW TESTS *************************/ /**** new macro encapsulating RVMODEL_SIG_END (signature area) ****/ /**** defining rvtest_sig_end: label to enabling direct stores ****/ /**** into the signature area to be properLY relocated ****/ /**********************************************************************/ #define RVTEST_SIG_END ;\ .global rvtest_sig_end /* defines beginning of trap sig area */ ;\ ;\ #ifdef rvtest_gpr_save ;\ gpr_save: ;\ .fill 32*(XLEN/32),4,0xdeadbeef ;\ #endif ;\ ;\ sig_end_canary: ;\ CANARY ;\ CANARY /* add one extra word of guardband */ ;\ rvtest_sig_end: ;\ RVMODEL_DATA_END /* model specific stuff */ /***********************************************************************************/ /**** At end of test, this code is entered. It sets a register x2 to 0 and by ****/ /**** default executes an ecall. The handler checks if the cause of the trap ****/ /**** was ecall, w/ x2=0, and divert a special rtn_fm_mmode handler. That code ****/ /**** determines the caller's mode, uses it to select it's CODE_BEGIN, and uses ****/ /**** to calculate it offset from Mmode's CODE_BEGIN, adjusts MEPC by that amt ****/ /**** to convert it to an Mmode address, restores saved regs, and branches to ****/ /**** the relocated addr+4, immediately following the ECALL, but now in Mmode ****/ /**** **NOTE**: this destroys T2 and clears x2 (AKA sp) ****/ /**** **NOTE**: this works from any mode but MUST not be used if ****/ /**** medeleg[]==1 to prevent infinite delegation loops. ****/ /**** **NOTE: tests that set medeleg[GOTO_M_OP_cause] must replace GOTO_M_OP ****/ /**** with an op that causes a different exception cause that isn't delegated. ****/ /***********************************************************************************/ .macro RVTEST_GOTO_MMODE .option push .option norvc #ifdef rvtest_mtrap_routine /**** this can be empty if no Umode ****/ li x2, 0 /* Ecall w/x2=0 is handled specially to rtn here */ // Note that if illegal op trap is delegated , this may infinite loop // The solution is either for test to disable delegation, or to // redefine the GOTO_M_OP to be an op that will trap to mmode GOTO_M_OP /* ECALL: traps always, but returns immediately to */ /* the next op if x2=0, else handles trap normally */ #endif .option pop .endm /**** This is a helper macro that causes harts to transition from ****/ /**** M-mode to a lower priv mode at the instruction that follows ****/ /**** the macro invocation. Legal params are VS,HS,VU,HU,S,U. ****/ /**** The H,U variations leave V unchanged. This uses T4 only. ****/ /**** NOTE: this MUST be executed in M-mode. Precede with GOTO_MMODE ****/ /**** FIXME - SATP & VSATP must point to the identity map page table ****/ #define HSmode 0x9 #define HUmode 0x8 #define VUmode 0x4 #define VSmode 0x5 #define Smode 0x1 #define Umode 0x0 .macro RVTEST_GOTO_LOWER_MODE LMODE .option push .option norvc // first, clear MSTATUS.PP (and .MPV if it will be changed_ // then set them to the values that represent the lower mode #if (XLEN==32) .if ((\LMODE\()==VUmode) | (\LMODE\()==VSmode)) csrsi CSR_MSTATUS, MSTATUS_MPV /* set V */ .elseif ((\LMODE\()==HUmode) | (\LMODE\()==HSmode)) csrci CSR_MSTATUS, MSTATUS_MPV /* clr V */ .endif /* lv V unchged for S or U */ LI( T4, MSTATUS_MPP) csrc CSR_MSTATUS, T4 /* clr PP always */ .if ((\LMODE\()==VSmode) || (\LMODE\()==HSmode) || (\LMODE\()==Smode)) LI( T4, MPP_SMODE) /* val for Smode */ csrs CSR_MSTATUS, T4 /* set in PP */ .endif // do the same if XLEN=64 #else /* XLEN=64, maybe 128? FIXME for 128 */ .if ((\LMODE\()==Smode) || (\LMODE\()==Umode)) /* lv V unchanged here */ LI( T4, MSTATUS_MPP) /* but always clear PP */ .else LI( T4, (MSTATUS_MPP | MSTATUS_MPV)) /* clr V and P */ .endif csrc CSR_MSTATUS, T4 /* clr PP to umode & maybe Vmode */ .if (!((\LMODE\()==HUmode) || (\LMODE\()==Umode))) /* lv pp unchged, v=0 or unchged */ .if (\LMODE\()==VSmode) LI( T4, (MPP_SMODE | MSTATUS_MPV)) /* val for pp & v */ .elseif ((\LMODE\()==HSmode) || (\LMODE\()==Smode)) LI( T4, (MPP_SMODE)) /* val for pp only */ .else /* only VU left; set MPV only */ li T4, 1 /* optimize for single bit */ slli T4, T4, 32+MPV_LSB /* val for v only */ .endif csrs CSR_MSTATUS, T4 /* set correct mode and Vbit */ .endif #endif csrr sp, CSR_MSCRATCH /* ensure sp points to Mmode datae area */ /**** mstatus MPV and PP now set up to desired mode ****/ /**** set MEPC to mret+4; requires relocating the pc ****/ .if (\LMODE\() == Vmode) // get trapsig_ptr & init val up 2 save areas (M<-S<-V) LREG T1, code_bgn_off + 2*sv_area_sz(sp) .elseif (\LMODE\() == Smode || \LMODE\() == Umode) // get trapsig_ptr & init val up 1 save areas (M<-S) LREG T1, code_bgn_off + 1*sv_area_sz(sp) .else // get trapsig ptr & init val for this Mmode, (M) LREG T1, code_bgn_off + 0*sv_area_sz(sp) .endif LREG T4, code_bgn_off(sp) sub T1, T1,T4 /* calc addr delta between this mode (M) and lower mode code */ addi T1, T1, 4*WDBYTSZ /* bias by # ops after auipc continue executing at mret+4 */ auipc T4, 0 add T4, T4, T1 /* calc addr after mret in LMODE's VM */ csrrw T4, CSR_MEPC, T4 /* set rtn addr to mret+4 in LMODE's VM */ mret /* transition to desired mode */ .option pop .endm // end of RVTEST_GOTO_LOWER_MODE //============================================================================== // Helper macro to set defaults for undefined interrupt set/clear // macros. This is used to populated the interrupt vector table. // These are only used during interrupt testing, so it is safe to // define them as empty macros if and only if that particular interrupt // isn't being tested //============================================================================== //**************************************************************** #define RVTEST_DFLT_INT_HNDLR j cleanup_epilogs //Mmode interrupts #ifndef RVMODEL_SET_MSW_INT //.warning "RVMODEL_SET_MSW_INT not defined. Executing this will end test. Define an empty macro to suppress this warning" #define RVMODEL_SET_MSW_INT RVTEST_DFLT_INT_HNDLR #endif #ifndef RVMODEL_CLR_MSW_INT //.warning "RVMODEL_CLR_MSW_INT not defined. Executing this will end test. Define an empty macro to suppress this warning" #define RVMODEL_CLR_MSW_INT RVTEST_DFLT_INT_HNDLR #endif #ifndef RVMODEL_CLR_MTIMER_INT //.warning "RVMODEL_CLR_MTIMER_INT not defined. Executing this will end test. Define an empty macro to suppress this warning" #define RVMODEL_CLR_MTIMER_INT RVTEST_DFLT_INT_HNDLR #endif #ifndef RVMODEL_CLR_MEXT_INT //.warning "RVMODEL_CLR_MEXT_INT not defined. Executing this will end test. Define an empty macro to suppress this warning" #define RVMODEL_CLR_MEXT_INT RVTEST_DFLT_INT_HNDLR #endif //Smode interrupts #ifndef RVMODEL_SET_SSW_INT //.warning "RVMODEL_SET_SSW_INT not defined. Executing this will end test. Define an empty macro to suppress this warning" #define RVMODEL_SET_SSW_INT RVTEST_DFLT_INT_HNDLR #endif #ifndef RVMODEL_CLR_SSW_INT //.warning "RVMODEL_CLR_SSW_INT not defined. Executing this will end test. Define an empty macro to suppress this warning" #define RVMODEL_CLR_SSW_INT RVTEST_DFLT_INT_HNDLR #endif #ifndef RVMODEL_CLR_STIMER_INT //.warning "RVMODEL_CLR_STIMER_INT not defined. Executing this will end test. Define an empty macro to suppress this warning" #define RVMODEL_CLR_STIMER_INT RVTEST_DFLT_INT_HNDLR #endif #ifndef RVMODEL_CLR_SEXT_INT //.warning "RVMODEL_CLR_SEXT_INT not defined. Executing this will end test. Define an empty macro to suppress this warning" #define RVMODEL_CLR_SEXT_INT RVTEST_DFLT_INT_HNDLR #endif //Vmode interrupts #ifndef RVMODEL_SET_VSW_INT //.warning "RVMODEL_SET_VSW_INT not defined. Executing this will end test. Define an empty macro to suppress this warning" #define RVMODEL_SET_VSW_INT RVTEST_DFLT_INT_HNDLR #endif #ifndef RVMODEL_CLR_VSW_INT //.warning "RVMODEL_CLR_VSW_INT not defined. Executing this will end test. Define an empty macro to suppress this warning" #define RVMODEL_CLR_VSW_INT RVTEST_DFLT_INT_HNDLR #endif #ifndef RVMODEL_CLR_VTIMER_INT //.warning "RVMODEL_CLR_VTIMER_INT not defined. Executing this will end test. Define an empty macro to suppress this warning" #define RVMODEL_CLR_VTIMER_INT RVTEST_DFLT_INT_HNDLR #endif #ifndef RVMODEL_CLR_VEXT_INT //.warning "RVMODEL_CLR_VEXT_INT not defined. Executing this will end test. Define an empty macro to suppress this warning" #define RVMODEL_CLR_VEXT_INT RVTEST_DFLT_INT_HNDLR #endif //============================================================================== // This section defines macros used by these required macros: // RVTEST_TRAP_PROLOG, RVTEST_TRAP_HANDLER, RVTEST_TRAP_EPILOG // These are macros instead of inline because they need to be replicated per mode // These are passed the privmode as an argument to properly rename labels // The helper INSTANTIATE_MODE_MACRO actually handles the replication //============================================================================== .macro RVTEST_TRAP_PROLOG __MODE__ .option push .option norvc /******************************************************************************/ /**** this is a mode-configured version of the prolog, which either saves and */ /**** replaces xtvec, or saves and replaces the code located at xtvec if it */ /**** it xtvec isn't arbitrarily writable. If not writable, restore & exit */ /******************************************************************************/ /******************************************************************************/ /**** 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. ****/ /******************************************************************************/ // RVTEST_TRAP_PROLOG trap_handler_prolog; enter with T1..T6 available; define specific handler // sp will immediately point to the current mode's save area and must not be touched //NOTE: this is run in M-mode, so can't use aliased S,V CSR names .global \__MODE__\()trampoline //.global mtrap_sigptr XCSR_VRENAME \__MODE__ //retarget XCSR names to this modes CSRs, separate V/S copies LA( T1, \__MODE__\()tramptbl_sv) // get ptr to save area (will be stored in xSCRATCH) //---------------------------------------------------------------------- init_\__MODE__\()scratch: csrrw T3, CSR_XSCRATCH, T1 // swap xscratch with save area ptr (will be used by handler) SREG T3, xscr_save_off(T1) // save old mscratch in xscratch_save //---------------------------------------------------------------------- init_\__MODE__\()edeleg: li T2, 0 // save and clear edeleg so we can exit to Mmode .ifc \__MODE__ , V csrrw T2, CSR_VEDELEG, T2 // special case: VS EDELEG available from Vmode .else .ifc \__MODE__ , M #ifdef rvtest_strap_routine csrrw T2, CSR_XEDELEG, T2 // this handles M mode save, but only if Smode exists #endif .else //FIXME: if N-extension or anything like it is implemented, uncomment the following // csrrw T2, CSR_XEDELEG, T2 // this handles S mode .endif .endif SREG T2, xedeleg_sv_off(T1) // now do the save //---------------------------------------------------------------------- init_\__MODE__\()satp: .ifnc \__MODE__ , M // if S or VS mode **FIXME: fixed offset frm trapreg_sv? LA( T4, rvtest_\__MODE__\()root_pg_tbl) // rplc xsatp w/ identity-mapped pg table srli T4, T4, 12 #if (XLEN==32) LI(T3, SATP32_MODE) #else LI(T3, (SATP64_MODE) & (SATP_MODE_SV39 << 60)) #endif or T4, T4, T3 csrrw T4, CSR_XSATP, T4 SREG T4, xsatp_sv_off(T1) .endif //---------------------------------------------------------------------- init_\__MODE__\()tvec: // LA( T4, \__MODE__\()trampoline) //this is a code-relative pointer // ADDI( T3, T4, actual_tramp_sz) // SREG T3, tentry_addr(T1) // initialize to original common entry point csrr T3, CSR_XTVEC SREG T3, xtvec_sav_off(T1) // save orig mtvec+mode in tvec_save andi T2, T3, WDBYTMSK // extract mode bits LREG T4, tentry_addr(T1) addi T4, T4, -actual_tramp_sz// load trampoline addr (common entry pt) avoiding an LA() or T2, T4, T2 // merge .mode & tramp ptr and store to both XTVEC, tvec_new SREG T2, xtvec_new_off(T1) csrw CSR_XTVEC, T2 // write xtvec with trap_trampoline+mode, so trap will go to the trampoline csrr T5, CSR_XTVEC // now read new_mtval back & make sure we could write it #ifndef HANDLER_TESTCODE_ONLY beq T5, T2, rvtest_\__MODE__\()prolog_done // if mtvec==trap_trampoline, mtvec is writable, continue #endif csrw CSR_XTVEC, T3 // xTVEC not completely writable, restore old value & exit if uninitialized beqz T3, abort\__MODE__\()test SREG T3, xtvec_new_off(T1) // else update tvect_new with orig mtvec /*****************************************************************/ /**** fixed mtvec, can't move it so move trampoline instead ****/ /**** T1=tramp sv, T2=orig tvec, T3=sv end, T4=tramp ****/ /*****************************************************************/ init_\__MODE__\()tramp: /**** copy trampoline at mtvec tgt; T4->T2->T1 T3=end of save ****/ andi T2, T3, ~WDBYTMSK // calc bgn of orig tramp area by clring mode bits addi T3, T2, actual_tramp_sz // calc end of orig tramp area (+4 maybe so bldwd aligned) // addi T1, T1, tramp_sv_off // calc bgn of tramp save area <--buggy!! //---------------------------------------------------------------------- overwt_tt_\__MODE__\()loop: // now build new tramp table w/ local offsets lw T6, 0(T2) // move original mtvec target to save area sw T6, 0(T1) lw T5, 0(T4) // move traphandler trampoline into orig mtvec target sw T5, 0(T2) lw T6, 0(T2) // rd it back to make sure it was written bne T6, T5, endcopy_\__MODE__\()tramp // table isn't fully writable, restore and give up #ifdef HANDLER_TESTCODE_ONLY csrr T5, CSR_XSCRATCH // load trapreg_sv from scratch addi T5, T5,256 // calculate some offset into the save area bgt T5, T1, endcopy_\__MODE__\()tramp // and pretend if couldnt be written #endif addi T2, T2, WDBYTSZ // next tvec inst. index addi T1, T1, WDBYTSZ // next save inst. index addi T4, T4, WDBYTSZ // next tramp inst. index bne T3, T2, overwt_tt_\__MODE__\()loop // haven't reached end of save area, loop //---------------------------------------------------------------------- endcopy_\__MODE__\()tramp: // vector table not writeable, restore RVMODEL_FENCEI // By default it is defined as nop. See the definition above csrr T1, CSR_XSCRATCH // reload trapreg_sv from scratch SREG T2, trampend_off(T1) // save copy progress; used to restore orig tramp SREG T4, tentry_addr(T1) // this is common entry point address, end of orig trampoline beq T3,T2, rvtest_\__MODE__\()prolog_done //full loop, don't exit abort\__MODE__\()test: LA( T6, exit_\__MODE__\()cleanup) // trampoline rplc failure **FIXME: precalc& put into savearea? jalr x0, T6 // this branch may be too far away, so longjmp rvtest_\__MODE__\()prolog_done: .option pop .endm //end of PROLOG /*******************************************************************************/ /*************** end of prolog macro ************/ /*******************************************************************************/ .macro RVTEST_TRAP_HANDLER __MODE__ .option push .option rvc // temporarily allow compress to allow c.nop alignment .align MTVEC_ALIGN // ensure that a trampoline is on a model defined or reasonable boundary .option pop /**********************************************************************/ /**** This is the entry point for all x-modetraps, vectored or not.****/ /**** xtvec should either point here, or trampoline code does and ****/ /**** trampoline code was copied to whereever xtvec pointed to. ****/ /**** At entry, xscratch will contain a pointer to a scratch area. ****/ /**** This is an array of branches at 4B intevals that spreads out ****/ /**** to an array of 12B xhandler stubs for specd int causes, and ****/ /**** to a return for anything above that (which causes a mismatch)****/ /**********************************************************************/ XCSR_RENAME \__MODE__ //retarget XCSR names to this modes CSRs .global \__MODE__\()trampoline // define the label and make it available .global common_\__MODE__\()entry .option push .option norvc \__MODE__\()trampoline: //****GLOBAL:***** .set value, 0 .rept NUM_SPECD_INTCAUSES // located at each possible int vectors j trap_\__MODE__\()handler+ value // offset < +/- 1MB .set value, value + 12 // length of xhandler trampoline spreader code .endr .rept XLEN-NUM_SPECD_INTCAUSES // fill at each impossible entry j rvtest_\__MODE__\()endtest // end test if this happens .endr /*********************************************************************/ /**** this is spreader stub array; it saves enough info (sp & ****/ /**** vec-offset) to enable branch to common routine to save rest ****/ /*********************************************************************/ /**** !!CSR_xSCRATCH is preloaded w/ xtrapreg_sv in init_xscratch:****/ trap_\__MODE__\()handler: // on exit sp swapped w/ save ptr, T6 is vector addr .rept NUM_SPECD_INTCAUSES csrrw sp, CSR_XSCRATCH, sp // save sp, replace w/trapreg_sv regtmp save ptr SREG T6, trap_sv_off+6*REGWIDTH(sp) // save T6 in temp save area offset 6 jal T6, common_\__MODE__\()handler // jmp to common code, saving vector in T6 .endr /*********************************************************************/ /**** common code for all ints & exceptions, will fork to handle ****/ /**** each separately. The common handler first stores trap mode+ ****/ /**** vector, & mcause signatures. Most traps have 4wd sigs, but ****/ /**** sw and timer ints only store 3 of the 4, & some hypervisor ****/ /**** traps will set store 6 ops ****/ /**** sig offset Exception ExtInt SWInt TimerInt ****/ /**** 0: <--------------------- Vect+mode ----------> ****/ /**** 4: <---------------------- xcause -------------> ****/ /**** 8: xepc <------------- xip --------------> ****/ /**** 12: tval IntID <---- x ----------------> ****/ /**** 16: tval2/x * <-------------- x ----------------> ****/ /**** 20: tinst/x * <-------------- x ----------------> ****/ /**** * only loaded for Mmode traps when hypervisor implemented ****/ /*********************************************************************/ /* in general, CSRs loaded in T2, addresses into T3 */ //If we can distinguish between HS and S mode, we can share S and V code. //except for prolog code which needs to initialize CSRs, and the save area //To do this, we need to read one of the CSRs (e.g. xSCRATCH) and compare //it to either Strapreg_sv or Vtrapreg_sv to determine which it is. common_\__MODE__\()handler: // enter with vector addr in T6 (orig T6 is at offset 6*REGWIDTH) SREG T5, trap_sv_off+5*REGWIDTH(sp) // x30 save remaining regs, starting with T5 csrrw T5, CSR_XSCRATCH, sp // restore ptr to reg sv area, and get old sp SREG T5, trap_sv_off+7*REGWIDTH(sp) // save old sp LREG T5, tentry_addr(sp) // get the address of the common entry point jr T5 // needed if trampoline gets moved elsewhere, else it's effectively a noop common_\__MODE__\()entry: SREG T4, trap_sv_off+4*REGWIDTH(sp) //x29 SREG T3, trap_sv_off+3*REGWIDTH(sp) //x28 SREG T2, trap_sv_off+2*REGWIDTH(sp) //x7 SREG T1, trap_sv_off+1*REGWIDTH(sp) //x6 save other temporaries //spcl case handling for ECALL in GOTO_MMODE mode,) ****tests can't use ECALL T2=0**** spcl_\__MODE__\()2mmode_test: csrr T5, CSR_XCAUSE addi T4, T5, -8 // is cause 8..11? Mmode should avoid ECALL 0 andi T4, T4, -4 // NOTE: cause 10 is RSVD. Sail will diverge, but buggy anyway bnez T4, \__MODE__\()trapsig_ptr_upd // no, not in special mode, just continue LREG T2, trap_sv_off+7*REGWIDTH(sp) // get test x2 (which is sp, which has been saved in the trap_sv area beqz T2, rtn2mmode // spcl code 0 in T2 means spcl ECALL goto_mmode, just rtn after ECALL //------pre-update trap_sig pointer so handlers can themselves trap----- \__MODE__\()trapsig_ptr_upd: // calculate entry size based on int vs. excpt, int type, and h mode li T2, 4*REGWIDTH // standard entry length bgez T5, \__MODE__\()xcpt_sig_sv // Keep std length if cause is an exception for now (MSB==0) \__MODE__\()int_sig_sv: slli T3, T5, 1 // remove MSB, cause<<1 addi T3, T3, -(IRQ_M_TIMER)<<1 // is cause (w/o MSB) an extint or larger? ( (cause<<1) > (8<<1) )? bgez T3, \__MODE__\()trap_sig_sv // yes, keep std length li T2, 3*REGWIDTH // no, its a timer or swint, overrride preinc to 3*regsz j \__MODE__\()trap_sig_sv /**********************************************************************/ /**** FIXME: could this simply instantiate RVMODEL_HALT instead of ****/ /**** branching to it? might need to instantiate GOTO_MMODE here ****/ /**** to take care of VM issues that RVMODEL_HALT can't deal with ****/ /**********************************************************************/ rvtest_\__MODE__\()endtest: // target may be too far away, so longjmp LA( T1, rvtest_\__MODE__\()end) // FIXME: must be identity mapped if its a VA jalr x0, T1 \__MODE__\()xcpt_sig_sv: .ifc \__MODE__ , M // exception case, don't adjust if hypervisor mode disabled csrr T1, CSR_MISA slli T1, T1, XLEN-8 // shift H bit into msb bgez T1, \__MODE__\()trap_sig_sv // no hypervisor mode, keep std width li T2, 6*REGWIDTH // Hmode implemented & Mmode trap, override preinc to be 6*regsz .endif \__MODE__\()trap_sig_sv: // This replaces an LA(rvtest_trap_sig) calculating initial_Xtrap_sigptr + // + (Mtrap_sigptr-initial_Mtrap-sigptr) // The delta between Mmode_sigptr and Xmode_sigptr are constants // Xtrap_sigptr (current priv mode) are in the save area ponted to by sp // ****FIXME - this breaks if the signature area cross a page boundary and the mapping isn't contiguous .set sv_area_off, (-0*sv_area_sz) // get trapsig ptr val offset for Mmode, (M) .ifc \__MODE__ , S .set sv_area_off, (-1*sv_area_sz) // get trapsig_ptr val up 1 save areas (M<-S) .else .ifc \__MODE__ , V .set sv_area_off, (-2*sv_area_sz) // get trapsig ptr val up 2 save areas, (M<-S<-V)) .endif .endif //------this should be atomic------------------------------------- LREG T1, trapsig_ptr_off+sv_area_off(sp) add T4, T1, T2 SREG T4, trapsig_ptr_off+sv_area_off(sp) //------end atomic------------------------------------------------ // convert mtrap_sigptr to curr_mode trap_sigptr LREG T3, sig_bgn_off+sv_area_off(sp) // load Mmode sig begin addr sub T1, T1, T3 // cvt to offset from sig begin LREG T3, sig_bgn_off+ 0(sp) // load sig begin addr add T1, T1, T3 // add offset from sig_begin to curr sig_begin addr LREG T3, xtvec_new_off(sp) // get pointer to actual tramp table //---------------------------------------------------------------- /*************************************************************************/ /**** This first entry has this format. ****/ /**** The #entries is useful for parsing and is really #bytes/entry ****/ /**** +---------------+-----------+----------+------+ ****/ /**** | XLEN-1 16 | 15 6 | 5 2 | 1 0 | ****/ /**** +---------------+-----------+----------+------+ ****/ /**** | zeroes | vector | #entries | mode | ****/ /**** +---------------+-----------+----------+------+ ****/ /*************************************************************************/ sv_\__MODE__\()vect: // **FIXME?: breaks if tramp crosses pg && MMU enabled sub T6, T6, T3 // cvt spreader-addr to vector offset fm top of tramptable slli T6, T6, 4 // make room for 4 bits; vector is 10b max **FIXME: broken for SV64!) or T6, T6, T2 // insert entry size into bits 5:2 addi T6, T6, \__MODE__\()MODE_SIG // insert mode# into 1:0 SREG T6, 0*REGWIDTH(T1) // save 1st sig value, (vec-offset, entrysz, trapmode) //---------------------------------------------------------------- sv_\__MODE__\()cause: SREG T5, 1*REGWIDTH(T1) // save 2nd sig value, (mcause) //---------------------------------------------------------------- bltz T5, common_\__MODE__\()int_handler // split off if this is an interrupt /*******************************************************************************/ /**** This is exception specific code, storing relative mepc & tval sigs ****/ /**** The mepc sig is relocated by data or code start, depending on whether ****/ /**** on whether it's in the data area or not, & restored bumped by 2..6B ****/ /**** depending op alignment so trapped op isn't re-executed ****/ /*******************************************************************************/ common_\__MODE__\()excpt_handler: //******************************************************************************** // calculate the delta between trap mode and handler mode sv areas & add to sp // This code calculates this table: (H-ext is determined by Vtrap_routine variable // +-------+-------+-------+-------+---------+ // | Hndlr | vMPP | M.GVA | H-ext | sv area | // | Mode | =3 | | | delta | // +-------+------+-------+-------+---------+ // | M | 0 | 1 | 1 | 2 | // | M | 0 | 0 | x | 1 | // | M | 1 | 0 | x | 0 | // | M | x | 1 | 0 | illegal | // | M | 1 | 1 | x | illegal | // +-------+------+-------+-------+---------+ // | | | H.GVA | H-ext | sv area | // +-------+------+-------+-------+---------+ // | S/HS | 0* | 1 | 1 | 1 | // | S/HS | 0* | 0 | 1 | 0 | // | S/HS | 0* | * | 0 | 0 | // +-------+------+-------+-------+---------+ // | | | noGVA | H-ext | sv area | | // +-------+------+-------+-------+---------+ // | VS | 0* | - | 1* | 0 | // +-------+------+-------+-------+---------+ // where vMPP is // +-------+-------+-------+-------+------+ // | Hndlr | | | sved | | // | Mode | MPRV | MPP=3 | MPP=3 | vMPP | // +-------+-------+-------+-------+------+ // | M | 0 | 1 | x | 1 | // | M | 0 | 0 | x | 0 | // | M | 1 | 1 | 0 | 1 | // | M | 1 | 1 | 1 | 0 | // | M | 1 | 0 | x |illegl| // +-------+-------+-------+-------+------+ // |S/HS/VS| 0* | 1* | x | 1 | // +-------+-------+-------+-------+------+ // * means can't be read, but must or would have value indicated // all other values are illegal // lvs result in T4 to be used during relocation, (so doesn't touch sp) // can use T3, T6 because relocation will overwrite them //******************************************************************************** // create an index from these values: vMPP, x.GVA , H-ext // where vMPP = m.PRV ? svedMPP : m.MPP & svedMPP .ifc \__MODE__ , M csrr T6, CSR_MSTATUS LREG T4, mpp_sv_off(sp) /* saved MPP, overwritten if MPRV=1 */ // extract MPRV into bit0. Note that only Mmode cares; all other modes can have garbage slli T3, T6, XLEN-MPRV_LSB-1 /* put MPRV into sign bit & test */ bge T3, x0, 1f and T4, T4, T6 /* MPP=11 if MPRV=0, so AND w/ prevMPP */ 1: // FIXME: add code here to end test if MPRV=1 & MPP<3 // e.g. rt justify, extract, add mprv, end if <4 // now convert 2 bit xMPP field into a single bit 2 srli T4, T4, MPP_LSB /* now cvt MPP (in its natural position)*/ andi T4, T4, 3 /* to a single bit in bit2 iff ==3 */ addi T4, T4, 1 andi T4, T4, 4 // extract GVA into bit 1 #if (rvtest_vtrap_routine) #if (XLEN==32) csrr T3, CSR_MSTATUSH /* get CSR with GVA bit, but only H-ext */ srli T3, T3, GVA_LSB-1 /* reposition RV32 mstatush into bit1 */ #else srli T3, T6, GVA_LSB-1+32 /* reposition RV32 mstatus into bit1 */ #endif andi T3, T3, 1<<1 or T4, T4, T3 /* extract GVA in bit1, insert into msk */ // put H-extension implemented into bit 0 ori T4, T4, 1 /* set LSB if H-ext present */ //****FIXME: this doesn't work if misa.H is RW but set to zero ****/ #endif // chk for illegal combination LI( T6, 0x3B) /*lgl msk(vMPP,GVA,H)= 011,00x,10x=0x3B */ srl T6, T6, T4 andi T6, T6, 1 beq T6, x0, rvtest_\__MODE__\()endtest /* illegal combination */ //determine sv offset multiplier LI( T6, sv_area_sz) andi T3, T4, 2 srli T3, T3, 1 /* extract GVA & move to bito cases */ srl T6, T6, T3 /* mul by 2 if GVAelse mul by 1 */ slli T3, T4, XLEN-3 srai T3, T3, XLEN-1 /* sg ext vMPP, user it to clr delta */ and T6, T6, T3 .else // do it again, but from VS or HS mode .ifc \__MODE__ , S // vMPP cannot be 11 because you it cannot handle at a lower mode than trap mode // MPRV cannot be 1 because that only applies to Mmode // GVA can only exist if there is H-ext #if rvtest_vtrap_routine LI( T6, sv_area_sz) csrr T3, CSR_HSTATUS /* get CSR with GVA bit, but only H-ext */ slli T3, T3, XLEN-1-GVA_LSB /* sign extend rt justified GVA bit */ slri T3, T3, XLEN-1 and T4, T3, T6 /* clr delta if GVA=0 */ #else li T4,0 /* clr delta if no H-ext */ #endif .else // handler is in VS mode, vtrap_routine must be defined, offset must be 0 li T4,0 .endif .endif //******************************************************************************** vmem_adj_\__MODE__\()epc: add T4, T4, sp /* calc address of correct sv_area */ csrr T2, CSR_XEPC /* T4 now pts to trapping sv_area mode */ LREG T3, vmem_bgn_off(T4) // see if epc is in the vmem area LREG T6, vmem_seg_siz(T4) add T6, T6, T3 // construct vmem seg end bgeu T2, T6, code_adj_\__MODE__\()epc// epc > rvtest_vmem_end, try data adj bgeu T2, T3, adj_\__MODE__\()epc// epc >=rvtest_vmem_begin, adj and save code_adj_\__MODE__\()epc: LREG T3, code_bgn_off(T4) // see if epc is in the code area LREG T6, code_seg_siz(T4) add T6, T6, T3 // construct code seg end bgeu T2, T6, data_adj_\__MODE__\()epc// epc > rvtest_code_end, try data adj bgeu T2, T3, adj_\__MODE__\()epc// epc >=rvtest_code_begin, adj and save data_adj_\__MODE__\()epc: LREG T3, data_bgn_off(T4) // see if epc is in the data area LREG T6, data_seg_siz(T4) add T6, T6, T3 // construct data seg end bgeu T2, T6, cleanup_epilogs // mepc > rvtest_code_end, (outside data seg), abort bltu T2, T3, cleanup_epilogs // mepc < rvtest_code_begin (outside data seg), abort adj_\__MODE__\()epc: sub T3, T2, T3 // Offset adjustment sv_\__MODE__\()epc: SREG T3, 2*REGWIDTH(T1) // save 3rd sig value, (rel mepc) into trap sig area adj_\__MODE__\()epc_rtn: // adj mepc so there is at least 4B of padding after op andi T6, T2, ~WDBYTMSK // adjust mepc to prev 4B alignment (if 2B aligned) addi T6, T6, 2*WDBYTSZ // adjust mepc so it skips past op, has padding & 4B aligned csrw CSR_XEPC, T6 // restore adjusted value, w/ 2,4 or 6B of padding /****WARNING needs updating when insts>32b are ratified, only 4 or 6B of padding; for 64b insts, 2B or 4B of padding ****/ /******************************************************************************/ /* Relocate mtval if it’s an addr (by sig, data or code regions) else by zero */ /* error if exception address isn't inside code, data or signature segments */ /* Enter with rvtest_code_begin (which is start of actual test) in T3 */ /* FUTURE FIXME: this may need to be updated to handle 48 or 64b opcodes */ /* This uses offset sp in T4 from epc relocation */ /******************************************************************************/ /**** FIXME: if in Mmode and mode!=bare & MPRV=1, then T4 be altered to point to the mode of the mstatus.mpp that is stored in Xtrampend_sv ****/ csrr T2, CSR_XTVAL chk_\__MODE__\()tval: andi T5, T5, EXCPT_CAUSE_MSK // ensures shift amt will be within range LI( T3, SET_REL_TVAL_MSK) // now check if code or data (or sig) region adjustment srl T3, T3, T5 // put mcause bit# into LSB slli T3, T3, XLEN-1 // put mcause bit# into MSB bge T3, x0, sv_\__MODE__\()tval // if MSB=0, no adj, sv to ensure tval was cleared vmem_adj_\__MODE__\()tval: /* T4 still points to sv area of trapping mode */ LREG T3, vmem_bgn_off(T4) // fetch sig_begin addr LREG T6, vmem_seg_siz(T4) add T6, T6, T3 // construct vmem seg end bgeu T2, T6, sig_adj_\__MODE__\()tval// tval > rvtest_sig_end, chk code seg bgeu T2, T3, adj_\__MODE__\()tval// tval >=rvtest_sig_begin, adj & save sig_adj_\__MODE__\()tval: LREG T3, sig_bgn_off(T4) // fetch sig_begin addr LREG T6, sig_seg_siz(T4) add T6, T6, T3 // construct sig seg end bgeu T2, T6, code_adj_\__MODE__\()tval// tval > rvtest_sig_end, chk code seg bgeu T2, T3, adj_\__MODE__\()tval// tval >=rvtest_sig_begin, adj & save code_adj_\__MODE__\()tval: LREG T3, code_bgn_off(T4) // fetch code_begin addr LREG T6, code_seg_siz(T4) add T6, T6, T3 // construct code seg end bgeu T2, T6, data_adj_\__MODE__\()tval// tval > rvtest_code_end, chk data seg bgeu T2, T3, adj_\__MODE__\()tval// tval >=rvtest_code_begin, adj & save data_adj_\__MODE__\()tval: LREG T3, data_bgn_off(T4) // fetch data_begin addr LREG T6, data_seg_siz(T4) add T6, T6, T3 // construct data seg end bgeu T2, T6, cleanup_epilogs // tval > rvtest_data_end, (outside data seg), abort bltu T2, T3, cleanup_epilogs // tval < rvtest_data_begin (outside data seg), abort adj_\__MODE__\()tval: sub T3, T2, T3 // perform mtval adjust by either code, data, or sig position in T3 sv_\__MODE__\()tval: SREG T3, 3*REGWIDTH(T1) // save 4th sig value, (rel tval) skp_\__MODE__\()tval: .ifc \__MODE__ , M .ifdef __H_EXT__ csrr T2, CSR_MTVAL2 // **** FIXME: does this need reloc also? Its a guest phys addr SREG T2, 4*REGWIDTH(T1) // store 5th sig value, only if mmode handler and VS mode exists csrr T2, CSR_MTINST SREG T2, 5*REGWIDTH(T1) // store 6th sig value, only if mmode handler and VS mode exists .endif .endif chk_\__MODE__\()trapsig_overrun: // sv_area_off is defined above at Xtrap_sig_sv: //This is the same code used at xtrap_sig_sv to get the shared copy of trap signature pointer LREG T4, sv_area_off+trapsig_ptr_off(sp) LREG T2, sv_area_off+sig_bgn_off(sp) LREG T1, sv_area_off+sig_seg_siz(sp) // now see if the pointer has overrun sig_end add T1, T1, T2 // construct segment end address bgtu T4, T1, cleanup_epilogs // abort test if pre-incremented value overruns /**** vector to exception special handling routines ****/ li T2, int_hndlr_tblsz // offset of exception dispatch table base j spcl_\__MODE__\()handler // jump to shared int/excpt spcl handling dispatcher /**** common return code for both interrupts and exceptions ****/ resto_\__MODE__\()rtn: // restore and return LREG T1, trap_sv_off+1*REGWIDTH(sp) LREG T2, trap_sv_off+2*REGWIDTH(sp) LREG T3, trap_sv_off+3*REGWIDTH(sp) LREG T4, trap_sv_off+4*REGWIDTH(sp) LREG T5, trap_sv_off+5*REGWIDTH(sp) LREG T6, trap_sv_off+6*REGWIDTH(sp) LREG sp, trap_sv_off+7*REGWIDTH(sp) // restore temporaries \__MODE__\()RET // return to test, after padding adjustment (macro to handle case) /***************************************************/ /**** This is the interrupt specific code. It ****/ /**** clears the int and saves int-specific CSRS****/ /***************************************************/ common_\__MODE__\()int_handler: // T1 has sig ptr, T5 has mcause, sp has save area li T3, 1 //**FIXME** - make sure this is kept up-to-date with fast int extension and others andi T2, T5, INT_CAUSE_MSK // clr INT & unarched arched bits (**NOTE expand if future extns use them) sll T3, T3, T2 // create mask 1<0, it is the handler address ****/ /**** There is an optional check that cause==mcause ****/ /**************************************************************/ spcl_\__MODE__\()handler: // case table branch to special handler code, depending on mcause auipc T3, 0 // shortcut for LA(clrint_\__MODE__\()tbl) (might be 4 too large) addi T3, T3, 15*4 // shortcut to avoid LA clrint_xtbl - this is might be 4 too large add T3, T3, T2 // offset into the correct int/excpt dispatch table slli T2, T5, 3 // index into 8b aligned dispatch entry and jump through it add T3, T3, T2 andi T3, T3, -8 // make sure this is dblwd aligned, correct if it is 4 too large LREG T3, 0(T3) spcl_\__MODE__\()dispatch_hndling: beqz T3, abort_tests // if address is 0, this is an error, exit test slli T2, T3, XLEN-1 // look at LSB and dispatch if even bge T2, x0, spcl_\__MODE__\()dispatch srli T3, T3,1 //odd entry>0, remove LSB, normalizing to cause range beq T5, T3, resto_\__MODE__\()rtn // case range matches, not an error, just noop j abort_tests //FIXME: this needs to report an error somehow spcl_\__MODE__\()dispatch: jr T3 // not a default, jump to handler /**** this is the table of interrupt clearing routine pointers ****/ /**** They could include special handlers ****/ /**** They default to model supplied RVMODEL macros above, ****/ /**** Note that the external interrupt routines are expected to ****/ /**** return with an interrupt ID in T3 ****/ .align 3 //make sure this is a dblwd boundary clrint_\__MODE__\()tbl: //this code should only touch T2..T6 #ifdef rvtest_vtrap_routine // M/S/V/U .dword 0 // int cause 0 is reserved, error .dword \__MODE__\()clr_Ssw_int // int cause 1 Smode SW int .dword \__MODE__\()clr_Vsw_int // int cause 2 Vmode SW int .dword \__MODE__\()clr_Msw_int // int cause 3 Mmode SW int //**************************************************************** .dword 0 // int cause 4 is reserved, error .dword \__MODE__\()clr_Stmr_int // int cause 5 Smode Tmr int .dword \__MODE__\()clr_Vtmr_int // int cause 6 Vmode Tmr int .dword \__MODE__\()clr_Mtmr_int // int cause 7 Mmode Tmr int //**************************************************************** .dword 0 // int cause 8 is reserved, error .dword \__MODE__\()clr_Sext_int // int cause 9 Smode Ext int .dword \__MODE__\()clr_Vext_int // int cause A Vmode Ext int .dword \__MODE__\()clr_Mext_int // int cause B Mmode Ext int //**************************************************************** #elseif rvtest_dtrap_routine // M/S/U only .dword 0 // int cause 0 is reserved, error .dword \__MODE__\()clr_Ssw_int // int cause 1 Smode SW int .dword 1 // int cause 2 no Vmode .dword \__MODE__\()clr_Msw_int // int cause 3 Mmode SW int //**************************************************************** .dword 0 // int cause 4 is reserved, error .dword \__MODE__\()clr_Stmr_int // int cause 5 Smode Tmr int .dword 1 // int cause 6 no vmode .dword \__MODE__\()clr_Mtmr_int // int cause 7 Mmode Tmr int //**************************************************************** .dword 0 // int cause 8 is reserved, error .dword \__MODE__\()clr_Sext_int // int cause 9 Smode Ext int .dword 1 // int cause A no vmode .dword \__MODE__\()clr_Mext_int // int cause B Mmode Ext int //**************************************************************** #else // M(/U)mode only .dword 0 // int cause 0 is reserved, error .dword 1 // int cause 1 no Smode .dword 1 // int cause 2 no Vmode .dword \__MODE__\()clr_Msw_int // int cause 3 Mmode SW int //**************************************************************** .dword 0 // int cause 4 is reserved, error .dword 1 // int cause 5 no Smode .dword 1 // int cause 6 no vmode .dword \__MODE__\()clr_Mtmr_int // int cause 7 Mmode Tmr int //**************************************************************** .dword 0 // int cause 8 is reserved, error .dword 1 // int cause 9 no Smode .dword 1 // int cause A no vmode .dword \__MODE__\()clr_Mext_int // int cause B Mmode Ext int //**************************************************************** #endif .rept NUM_SPECD_INTCAUSES-0xC .dword 1 // int cause c..NUM_SPECD_INTCAUSES is reserved, just return .endr .rept XLEN-NUM_SPECD_INTCAUSES .dword 0 // impossible, quit test by jumping to epilogs .endr //**************************************************************** /**** this is the table of exception handling routine pointers, which ****/ /**** could include special handlers. They default to the rtn code ****/ excpt_\__MODE__\()hndlr_tbl: // handler code should only touch T2..T6 ****<<--must be speced!**** .set causeidx, 0 .rept NUM_SPECD_EXCPTCAUSES .dword causeidx*2+1 // default, marked by @*cause+2just return .set causeidx, causeidx+1 .endr .rept XLEN-NUM_SPECD_EXCPTCAUSES .dword 0 // impossible, quit test by jumping to epilogs .endr /**** These are invocations of the model supplied interrupt clearing macros ****/ /**** Note there is a copy per mode, though they could all be the same code ****/ /**** !!! Note: These macros should only touch T2..T6, unless test is aware ****/ /**** of other modified registers and knows they are dead- ****/ /**** but T1 must not be modified under any circumstances ****/ /**** !!! Note: the ext interrupt clearing macros must leave intID in T3 !!!****/ // **FIXME** : the spec needs to be updated with the per/mode versions, not just one // **FIXME**: move these outside the handler so it can copied per mode using INSTANTIATE_MODE_MACRO //------------- MMode---------------- \__MODE__\()clr_Msw_int: // int 3 default to just return if not defined RVMODEL_CLR_MSW_INT j resto_\__MODE__\()rtn \__MODE__\()clr_Mtmr_int: // int 7 default to just return RVMODEL_CLR_MTIMER_INT j resto_\__MODE__\()rtn \__MODE__\()clr_Mext_int: // inT11 default to just return after saving IntID in T3 RVMODEL_CLR_MEXT_INT SREG T3, 3*REGWIDTH(T1) // save 4rd sig value, (intID) j resto_\__MODE__\()rtn //------------- SMode---------------- \__MODE__\()clr_Ssw_int: // int 1 default to just return if not defined RVMODEL_CLR_SSW_INT j resto_\__MODE__\()rtn \__MODE__\()clr_Stmr_int: // int 5 default to just return RVMODEL_CLR_STIMER_INT j resto_\__MODE__\()rtn \__MODE__\()clr_Sext_int: // int 9 default to just return after saving IntID in T3 RVMODEL_CLR_SEXT_INT SREG T3, 3*REGWIDTH(T1) // save 4rd sig value, (intID) j resto_\__MODE__\()rtn //------------- VSmode---------------- \__MODE__\()clr_Vsw_int: // int 2 default to just return if not defined RVMODEL_CLR_VSW_INT j resto_\__MODE__\()rtn \__MODE__\()clr_Vtmr_int: // int 6 default to just return RVMODEL_CLR_VTIMER_INT j resto_\__MODE__\()rtn \__MODE__\()clr_Vext_int: // int 8 default to just return after saving IntID in T3 RVMODEL_CLR_VEXT_INT SREG T3, 3*REGWIDTH(T1) // save 4rd sig value, (intID) j resto_\__MODE__\()rtn .ifc \__MODE__ , M /*************** Spcl handler for returning from GOTO_MMODE. ********/ /*************** Only gets executed if GOTO_MMODE not called from Mmode ********/ /*************** Executed in M-mode. Enter w/ T1=ptr to Mregsave, T2=0 ********/ /*************** NOTE: Ecall must NOT delegate when T2=0 or this fails ********/ rtn2mmode: addi T4,T5, -CAUSE_MACHINE_ECALL beqz T4, rtn_fm_mmode /* shortcut if called from Mmode */ #if (rvtest_vtrap_routine) #if (XLEN==32) csrr T2, CSR_MSTATUSH /* find out originating mode if RV32 */ #else csrr T2, CSR_MSTATUS /* find out originating mode if RV64/128*/ #endif slli T2, T2, WDSZ-MPV_LSB-1 /* but V into MSB ****FIXME if RV128 */ #endif LREG T6, code_bgn_off+1*sv_area_sz(sp) /* get U/S mode code begin */ bgez T2, from_u_s /* V==0, not virtualized, *1 offset */ from_v: LREG T6, code_bgn_off+2*sv_area_sz(sp)/* get VU/VS mode code begin */ from_u_s: /* get u/s modes CODE_BEGIN */ LREG T4, code_bgn_off+0*sv_area_sz(sp) /* get M mode code begin */ sub T4, T4, T6 /* calc relocation amount */ rtn_fm_mmode: csrr T2, CSR_MEPC /* get return address in orig mode's VM */ add T2, T2, T4 /* calc rtn_addr in Mmode VM */ LREG T1, trap_sv_off+1*REGWIDTH(sp) // LREG T2, trap_sv_off+2*REGWIDTH(sp) /*this holds the return address */ LREG T3, trap_sv_off+3*REGWIDTH(sp) LREG T4, trap_sv_off+4*REGWIDTH(sp) LREG T5, trap_sv_off+5*REGWIDTH(sp) LREG T6, trap_sv_off+6*REGWIDTH(sp) LREG sp, trap_sv_off+7*REGWIDTH(sp) // restore temporaries jr 4(T2) /* return after GOTO_MMODE in M-mode */ .endif .option pop .endm // end of HANDLER /*******************************************************************************/ /*************** end of handler macro ************/ /*******************************************************************************/ /*******************************************************************************/ /**************** cleanup code; restore xtvec or where it points to ************/ /********* Assumption: in M-mode, because GOTO_MMODE always ends tests *********/ /********* Assumption: XSCRATCH pnts to save area for appropriate mode *********/ /*******************************************************************************/ .macro RVTEST_TRAP_EPILOG __MODE__ .option push .option norvc XCSR_VRENAME \__MODE__ // retarget XCSR names to this modes CSRs, no V/S aiasing exit_\__MODE__\()cleanup: csrr T1, mscratch // pointer to save area .ifc \__MODE__ , S addi T1, T1, 1*sv_area_sz .else .ifc \__MODE__ , V addi T1, T1, 2*sv_area_sz .endif .endif resto_\__MODE__\()edeleg: LREG T2, xedeleg_sv_off(T1) // get saved xedeleg at offset -32 .ifc \__MODE__ , V csrw CSR_VEDELEG, T2 //special case: VS EDELEG available from Vmode .else .ifc \__MODE__ , M #ifdef rvtest_strap_routine csrw CSR_XEDELEG, T2 //this handles M mode restore, but only if Smode exists #endif .else //FIXME: if Umode-int-extension or anything like it is implemented, uncomment the following // csrw CSR_XEDELEG, T2 //this handles S mode restore .endif .endif .ifnc \__MODE__ , M resto_\__MODE__\()satp: LREG T2, xsatp_sv_off(T1) // restore saved xsatp csrw CSR_XSATP, T2 .endif resto_\__MODE__\()scratch: LREG T5, xscr_save_off(T1) // restore saved xscratch csrw CSR_XSCRATCH, T5 resto_\__MODE__\()xtvec: LREG T4, xtvec_sav_off(T1) // restore orig xtvec addr & load current one csrrw T2, CSR_XTVEC, T4 andi T4, T4, ~WDBYTMSK // remove mode, so both word aligned andi T2, T2, ~WDBYTMSK bne T4, T2, 1f // if saved!=curr mtvec, done, else need to restore tramp resto_\__MODE__\()tramp: // T2 now contains where to restore to addi T4, T1, tramp_sv_off // T4 now contains where to restore from LREG T3, trampend_off(T1) // T3 tracks how much to restore resto_\__MODE__\()loop: lw T6, 0(T4) // read saved tramp entry sw T6, 0(T2) // restore original tramp entry addi T2, T2, WDBYTSZ // next tgt index addi T4, T4, WDBYTSZ // next save index blt T2, T3, resto_\__MODE__\()loop // didn't get to end, continue 1: .global rvtest_\__MODE__\()end rvtest_\__MODE__\()end: #ifdef HANDLER_TESTCODE_ONLY //**FIXME**: add conditional code to compare original trampoline with // restored trampoline and store the deltas in the trap signature region // as an added check? must work for each mode #endif .option pop .endm //end of EPILOG /*******************************************************************************/ /**** end epilog cleanup code; should fall from V->S->M into RVMODEL_HALT ******/ /*******************************************************************************/ /*******************************************************************************/ /**** This macro defines per/mode save areas for mmode for each mode ****/ /**** note that it is the code area, not the data area, and ****/ /**** must be mulitple of 8B, so multiple instantiations stay aligned ****/ /**** This is preceded by the current signature pointer, (@Mtrpreg_sv -64? ****/ /*******************************************************************************/ .macro RVTEST_TRAP_SAVEAREA __MODE__ .option push .option norvc .global \__MODE__\()tramptbl_sv //****ASSERT: this should be a 64B boundary******// \__MODE__\()tramptbl_sv: // save area of existing trampoline table, // also stored in XSCRATCH!!! .rept (tramp_sz>>2) // size in words (technically, length of j op) padded to be 8B aligned j .+0 // prototype jump instruction, offset to be filled in .endr \__MODE__\()code_bgn_ptr: .dword rvtest_code_begin // ptr to code bgn area using this mode's mapping trampsvend+0*8 \__MODE__\()code_seg_sz: .dword rvtest_code_end-rvtest_code_begin // code seg size in any mode trampsvend+1*8 \__MODE__\()data_bgn_ptr: .dword rvtest_data_begin // ptr to data bgn area using this mode's mapping trampsvend+2*8 \__MODE__\()data_seg_sz: .dword rvtest_data_end-rvtest_data_begin // code seg size in any mode trampsvend+3*8 \__MODE__\()sig_bgn_ptr: .dword rvtest_sig_begin // ptr to sig bgn area using this mode's mapping trampsvend+4*8 \__MODE__\()sig_seg_sz: .dword rvtest_sig_end-rvtest_sig_begin // code seg size in any mode trampsvend+5*8 \__MODE__\()vmem_bgn_ptr: .dword rvtest_code_begin // default to code bgn area w/ this mode's mapping trampsvend+6*8 \__MODE__\()vmem_seg_sz: .dword rvtest_code_end-rvtest_code_begin // vmem seg size in any mode trampsvend+7*8 \__MODE__\()mpp_sv: // save mpp=3<<1 during test for mprv spcl case,***only Smode vers \__MODE__\()trap_sig: .dword mtrap_sigptr // ptr to next trapsig ***GLBL(only Mmode ver. used) trampsvend+8*8 \__MODE__\()satp_sv: .dword 0 // save area for incoming xsatp trampsvend+9*8 \__MODE__\()trampend_sv: .dword 0 // save loc of end of sved trampoline prolog/epilog trampsvend+10*8 \__MODE__\()tentry_sv: .dword \__MODE__\()trampoline + actual_tramp_sz // save comm entry loc pt trampsvend+11*8 \__MODE__\()edeleg_sv: .dword 0 // save loc for edeleg CSR trampsvend+12*8: \__MODE__\()tvec_new: .dword 0 // points to in-use tvec, actual tramp table used trampsvend+13*8 \__MODE__\()tvec_save: .dword 0 // save area for incoming mtvec trampsvend+14*8 \__MODE__\()scratch_save: .dword 0 // save area for incoming mscratch trampsvend+15*8 //****GLOBAL:***** onlyMMode version used \__MODE__\()trapreg_sv: // hndler regsave area, T1..T6,sp+spare keep dbl algn trampsvend+16*8 .fill 8, REGWIDTH, 0xdeadbeef \__MODE__\()sv_area_end: // used to calc size, which is used to avoid CSR read trampsvend+24/32+8 .option pop .endm // end of TRAP_SAVEAREA //============================================================================== // This section defines the required test format spec macros: // RVTEST_[CODE/DATA/SIG]_[BEGIN/END] //============================================================================== /**************************** CODE BEGIN w/ TRAP HANDLER START *********************/ /**** instantiate prologs using RVTEST_TRAP_PROLOG() if rvtests_xtrap_routine is ****/ /**** is defined, then initializes regs & defines rvtest_code_begin global label ****/ /************************************************************************************/ .macro RVTEST_CODE_BEGIN .option push .option rvc .align UNROLLSZ .option norvc .section .text.init .globl rvtest_init .global rvtest_code_begin //define the label and make it available rvtest_init: //instantiate prologs here INSTANTIATE_MODE_MACRO RVTEST_TRAP_PROLOG RVTEST_INIT_GPRS // 0xF0E1D2C3B4A59687 rvtest_code_begin: .option pop .endm //end of RVTEST_CODE_BEGIN /*********************** end of RVTEST_CODE_BEGIN ***********************************/ /************************************************************************************/ /**** The above is instantiated at the start of the actual test ****/ /**** So the test is here ****/ /**** the below is instantiated at the end of the actual test ****/ /************************************************************************************/ /**************************************************************************************/ /**** RVTEST_CODE_END macro defines end of test code: saves regs, transitions to ****/ /**** Mmode, & instantiates epilog using RVTEST_TRAP_EPILOG() macros. Test code ****/ /**** falls through to this else must branch to label rvtest_code_end. This must ****/ /**** branch to a RVMODEL_HALT macro at the end. The actual trap handlers for each ****/ /**** mode are instantiated immediately following with RVTEST_TRAP_HANDLER() macro ****/ /**************************************************************************************/ .macro RVTEST_CODE_END // test is ended, but in no particular mode .option push .option norvc .global rvtest_code_end // define the label and make it available .global cleanup_epilogs // ****ALERT: tests must populate x1 with a point to the end of regular sig area /**** MPRV must be clear here !!! ****/ rvtest_code_end: // RVMODEL_HALT should get here #ifdef rvtest_gpr_save // gpr_save area is instantiated at end of signature RVTEST_SAVE_GPRS x1 gpr_save #endif RVTEST_GOTO_MMODE // if only Mmode used by tests, this has no effect cleanup_epilogs: // jump here to quit, will restore state for each mode //restore xTVEC, trampoline, regs for each mode in opposite order that they were saved #ifdef rvtest_mtrap_routine #ifdef rvtest_strap_routine #ifdef rvtest_vtrap_routine RVTEST_TRAP_EPILOG V // actual v-mode prolog/epilog/handler code #endif RVTEST_TRAP_EPILOG S // actual s-mode prolog/epilog/handler code #endif RVTEST_TRAP_EPILOG M // actual m-mode prolog/epilog/handler code #endif /************* test done, epilog has restored everying, jump to halt ****************/ j exit_cleanup //skip around handlers, go to RVMODEL_HALT abort_tests: LREG T4, sig_bgn_off(sp) // calculate Mmode sig_end addr in handler's mode LREG T1, sig_seg_siz(sp) add T1, T1, T4 // construct sig seg end LI( T1, 0xBAD0DAD0) // early abort signature value at sig_end, independent of mtrap_sigptr SREG T1, -4(T4) // save into last signature canary j exit_cleanup // skip around handlers, go to RVMODEL_HALT /********************** trap handlers inserted here ***********************************/ INSTANTIATE_MODE_MACRO RVTEST_TRAP_HANDLER exit_cleanup: // *** RVMODEL_HALT MUST follow this***, then data .option pop .endm // end of RVTEST_CODE_END /************************************************************************************/ /**** RVTEST_CODE_END macros must fall thru or jump to an RVMODEL_HALT macro here ***/ /************************************************************************************/ /*===================================data section starts here========================*/ /************************************************************************************/ /**** RVTEST_DATA_BEGIN macro defines end of input data & rvtest_data_end label ****/ /**** this is a data area, so we instantiate trap save areas for each mode here ****/ /************************************************************************************/ .macro RVTEST_DATA_BEGIN .data .align 4 //ensure dbl alignment /**************************************************************************************/ /**** this is the pointer to the current trap signature part of the signature area ****/ /**** it is shared by all trap modes, but shouldn't be instantiated unless at least****/ /**** 1 trap mode is defined (which is covered if m-mode trap handlers are defined ****/ /**************************************************************************************/ /**** now instantiate separate save areas for each modes state ****/ /**** strictly speaking, should only be needed for reentrant traps ****/ INSTANTIATE_MODE_MACRO RVTEST_TRAP_SAVEAREA /************************************************************************************/ /**************** end of RVTEST_DATA_BEGIN; input data should follow ****************/ /************************************************************************************/ .global rvtest_data_begin rvtest_data_begin: .endm /************************************************************************************/ /**************** RVTEST_DATA_END macro; defines global label rvtest_data_end ****/ /************************************************************************************/ .macro RVTEST_DATA_END .global rvtest_data_end #ifndef rvtest_mtrap_routine mtrap_sigptr: .fill 2,4,0xdeadbeef #endif /**** create identity mapped page tables here if mmu is present ****/ .align 12 #ifndef RVTEST_NO_IDENTY_MAP #ifdef rvtest_strap_routine rvtest_Sroot_pg_tbl: RVTEST_PTE_IDENT_MAP #ifdef rvtest_vtrap_routine rvtest_Vroot_pg_tbl: RVTEST_PTE_IDENT_MAP #endif #endif #endif rvtest_data_end: .endm