cvw/tests/wally-riscv-arch-test/riscv-test-suite/env/arch_test.h

1997 lines
104 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

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

// -----------
// 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 <<LIMMSZ)-1)
#define SEXT_LIMM(x) ((x &LIMMMSK) | (-BIT((x),LIMMSGN)<<LIMMSZ))
#define WDBYTSZ (WDSZ >> 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<<CAUSE_MISALIGNED_FETCH | 1<<CAUSE_FETCH_ACCESS | 1<<CAUSE_BREAKPOINT | \
1<<CAUSE_MISALIGNED_LOAD | 1<<CAUSE_LOAD_ACCESS | 1<<CAUSE_MISALIGNED_STORE | 1<<CAUSE_STORE_ACCESS | \
1<<CAUSE_FETCH_PAGE_FAULT | 1<<CAUSE_LOAD_PAGE_FAULT | 1<<CAUSE_STORE_PAGE_FAULT) \
& 0xFFFFFFFF)
#endif
#ifndef SET_ABS_TVAL_MSK
#define SET_ABS_TVAL_MSK ((1<<CAUSE_ILLEGAL_INSTRUCTION) & 0xFFFFFFFF)
#endif
#ifndef GOTO_M_OP
#define GOTO_M_OP ecall
#endif
//this is a valid global pte entry with all permissions. IF at the root entry, it forms an identity map.
#define RVTEST_PTE_IDENT_MAP .fill 4096/REGWIDTH, REGWIDTH, (PTE_G | PTE_U | PTE_X | PTE_W | PTE_R | PTE_V)
#define RVTEST_PTE_NOACC_MAP .fill 4096/REGWIDTH, REGWIDTH, (PTE_G | PTE_U )
//_ADDR_SZ_ is a global variable extracted from YAML; set a default if it isn't defined
// This should be the MAX(phy_addr_size, VADDR_SZ) from YAML, where VADDR_SZ is derived from SATP.mode at reset
#ifndef _ADDR_SZ_
#if XLEN==64
#define _ADDR_SZ_ 57
#else
#define _ADDR_SZ_ 32
#endif
#endif
// define a bunch of XLEN dependent constants
#if XLEN==32
#define SREG sw
#define LREG lw
#define XLEN_WIDTH 5
#define LREGWU lw
#elif XLEN==64
#define SREG sd
#define LREG ld
#define XLEN_WIDTH 6
#define LREGWU lwu
#else
#define SREG sq
#define LREG lq
#define XLEN_WIDTH 7
#endif
#if FLEN==32
#define FLREG flw
#define FSREG fsw
#define FREGWIDTH 4
#elif FLEN==64
#define FLREG fld
#define FSREG fsd
#define FREGWIDTH 8
#else
#define FLREG flq
#define FSREG fsq
#define FREGWIDTH 16
#endif
#if SIGALIGN==8
#define CANARY \
.dword 0x6F5CA309E7D4B281
#else
#define CANARY \
.word 0x6F5CA309
#endif
//---------------------------mode encoding definitions-----------------------------
.set MMODE_SIG, 3
.set SMODE_SIG, 1
.set VMODE_SIG, 2
/* these macros need to be defined because mode is uppercase in mode specific macros */
/* note that vs mode uses smode return */
#define GVA_LSB 6 //bit pos of LSB of the hstatus.GVA field
#define MPP_LSB 11 //bit pos of LSB of the mstatus.MPP field
#define MPRV_LSB 17 //bit pos of LSB of the mstatus.MPRV field
#define MPV_LSB 7 // bit pos of prev vmod mstatush.MPV in either mstatush or mstatus upper
#define MPP_SMODE (1<<MPP_LSB)
//define sizes
#define actual_tramp_sz ((XLEN + 3* NUM_SPECD_INTCAUSES + 5) * 4) // 5 is added ops before common entry pt
#define tramp_sz ((actual_tramp_sz+4) & -8) // round up to keep aligment for sv area alloc
#define ptr_sv_sz (16*8)
#define reg_sv_sz ( 8*REGWIDTH)
#define sv_area_sz (tramp_sz + ptr_sv_sz + reg_sv_sz) // force dblword alignment
#define int_hndlr_tblsz (XLEN*2*WDBYTSZ)
/*
//#define sv_area_sz (Msv_area_end-Mtramptbl_sv) //sv_area start with aligned tramp_tbl
//#define tramp_sz (((common_Mentry-Mtrampoline)+4)& -8) // #ops from Mend..Mentry, forced to dblword size
*/
//define a fixed offsets into the save area
#define tramp_sv_off ( 0*8) // (Mtramptbl_sv -Mtrapreg_sv) algned to dblwd
#define code_bgn_off (tramp_sz+ 0*8) // (Mcode_bgn_ptr -Mtrapreg_sv)
#define code_seg_siz (tramp_sz+ 1*8) // (Mcode_seg_siz -Mtrapreg_sv)
#define data_bgn_off (tramp_sz+ 2*8) // (Mdata_bgn_ptr -Mtrapreg_sv) <--update on mapping chg
#define data_seg_siz (tramp_sz+ 3*8) // (Mdata_seg_siz -Mtrapreg_sv)
#define sig_bgn_off (tramp_sz+ 4*8) // ( Msig_bgn_ptr -Mtrapreg_sv) <--update on mapping chg
#define sig_seg_siz (tramp_sz+ 5*8) // ( Msig_seg_siz -Mtrapreg_sv)
#define vmem_bgn_off (tramp_sz+ 6*8) // (Mvmem_bgn_ptr -Mtrapreg_sv) <--update on mapping chg
#define vmem_seg_siz (tramp_sz+ 7*8) // (Mvmem_seg_siz -Mtrapreg_sv)
#define mpp_sv_off (sv_area_sz+tramp_sz+8*8) // (Strap_sig -Mtrapreg_sv)
#define trapsig_ptr_off (tramp_sz+ 8*8) // (Mtrap_sig -Mtrapreg_sv)
#define xsatp_sv_off (tramp_sz+ 9*8) // (Msatp_sv -Mtrapreg_sv)
#define trampend_off (tramp_sz+10*8) // (Mtrampend_sv -Mtrapreg_sv)
#define tentry_addr (tramp_sz+11*8) // (Mtentry_sv -Mtrapreg_sv) <--update on mapping chg
#define xedeleg_sv_off (tramp_sz+12*8) // (Medeleg_sv -Mtrapreg_sv)
#define xtvec_new_off (tramp_sz+13*8) // (tvec_new -Mtrapreg_sv)
#define xtvec_sav_off (tramp_sz+14*8) // (tvec_save -Mtrapreg_sv)
#define xscr_save_off (tramp_sz+15*8) // (scratch_save -Mtrapreg_sv)
#define trap_sv_off (tramp_sz+16*8) // (trapreg_sv -Mtrapreg_sv) 8 registers long
//==============================================================================
// this section has general test helper macros, required, optional, or just useful
//==============================================================================
#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_CASE(_PNAME,_DSTR,...)
//-----------------------------------------------------------------------
//Fixed length la, li macros; # of ops is ADDR_SZ dependent, not data dependent
//-----------------------------------------------------------------------
// this generates a constants using the standard addi or lui/addi sequences
// but also handles cases that are contiguous bit masks in any position,
// and also constants handled with the addi/lui/addi but are shifted left
/**** fixed length LI macro ****/
#if (XLEN<64)
#define LI(reg, imm) ;\
.set immx, (imm & MASK) /* trim to XLEN (noeffect on RV64) */ ;\
.set absimm, ((immx^(-BIT(immx,XLEN-1)))&MASK) /* cvt to posnum to simplify code */ ;\
.set cry, (BIT(imm, IMMSGN)) ;\
.set imm12, (SEXT_IMM(immx)) ;\
.if ((absimm>>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, dont 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, dont 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<<edge1)) /* check for single bit case */ ;\
li reg, 1 ;\
slli reg, reg, edge1 /* make 0001000 sgl bit mask */ ;\
.if (!even) ;\
xori reg, reg, -1 /* orig odd, cvt to 1110111 mask */ ;\
.endif ;\
.elseif (imme == ((1<<edge2) - (1<<edge1))) /* chk for multibit case */ ;\
li reg, -1 ;\
srli reg, reg, XLEN-(edge2-edge1) /* make multibit 1s mask */ ;\
slli reg, reg, edge1 /* and put it into position */ ;\
.if (!even) ;\
xori reg, reg, -1 /* orig odd, cvt to 1110111 mask */ ;\
.endif ;\
/************** look for 12b or 32b imms with trailing zeroes ***********/ ;\
.elseif ((immx==imme)&&((absimmsh>>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 <<shft? */ ;\
lui reg, ((immxsh>>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[<GOTO_M_OP_cause>]==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 <currmode>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 its 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<<xcause **NOTE**: that MSB is ignored in shift amt
csrrc T4, CSR_XIE, T3 // read, then attempt to clear int enable bit??
csrrc T4, CSR_XIP, T3 // read, then attempt to clear int pend bit
sv_\__MODE__\()ip: // note: clear has no effect on MxIP
SREG T4, 2*REGWIDTH(T1) // save 3rd sig value, (xip)
li T2, 0 // index of interrupt dispatch table base
/**************************************************************/
/**** spcl int/excp dispatcher. T5 has mcause, T2 ****/
/**** holds int table (0) or excpt tbl (int_tbl_sz) offset ****/
/**** this loads an entry @ table_base+table_off+mcause<<8 ****/
/**** if entry=0, it should never be taken, error return ****/
/**** if entry is odd, it has cause<<1, skip disptaching ****/
/**** otherwise if even & >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