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