-
Notifications
You must be signed in to change notification settings - Fork 215
/
Copy patharch_test.h
1466 lines (1306 loc) · 64.5 KB
/
arch_test.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#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
//-----------------------------------------------------------------------
// 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 LREGWU lwu
#define REGWIDTH 8
#define MASK 0xFFFFFFFFFFFFFFFF
#else
#if XLEN==32
#define SREG sw
#define LREG lw
#define LREGWU lw
#define REGWIDTH 4
#define MASK 0xFFFFFFFF
#endif
#endif
#if FLEN==64
#define FLREG fld
#define FSREG fsd
#define FREGWIDTH 8
#define SIGALIGN 8
#else
#if FLEN==32
#define FLREG flw
#define FSREG fsw
#define FREGWIDTH 4
#if XLEN==64
#define SIGALIGN 8
#else
#define SIGALIGN 4
#endif
#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
#define NAN_BOXED(__val__,__width__,__max__) \
.if __width__ == 32 ;\
.word __val__ ;\
.else ;\
.dword __val__ ;\
.endif ;\
.if __max__ > __width__ ;\
.set pref_bytes,(__max__-__width__)/32 ;\
.else ;\
.set pref_bytes, 0 ;\
.endif ;\
.rept pref_bytes ;\
.word 0xffffffff ;\
.endr ;
#define ZERO_EXTEND(__val__,__width__,__max__) \
.if __max__ > __width__ ;\
.set pref_bytes,(__max__-__width__)/32 ;\
.else ;\
.set pref_bytes, 0 ;\
.endif ;\
.rept pref_bytes ;\
.word 0 ;\
.endr ;\
.if __width__ == 32 ;\
.word __val__ ;\
.else ;\
.dword __val__ ;\
.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
.set value, 0
.rept NUM_SPECD_INTCAUSES // located at each possible int vectors
j mtrap_handler + 12*(value) //offset < +/- 1MB
.set 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 a0, MSTATUS_FS & (MSTATUS_FS >> 1); \
csrs mstatus, a0; \
csrwi fcsr, 0
#ifdef pext_check_vxsat_ov
#define RVTEST_VXSAT_ENABLE()\
li a0, MSTATUS_VS & (MSTATUS_VS >> 1); \
csrs mstatus, a0; \
clrov
#else
#define RVTEST_VXSAT_ENABLE()
#endif
#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 LOAD_MEM_VAL(_LINST, _AREG, _RD, _OFF, _TREG) \
.if _OFF >= 2048 ;\
.set _off, _OFF%2048 ;\
LI(_TREG, _OFF-_off) ;\
add _AREG,_AREG,_TREG ;\
.else ;\
.set _off, _OFF ;\
.endif ;\
_LINST _RD, _off(_AREG) ;\
.if _OFF >= 2048 ;\
sub _AREG,_AREG,_TREG ;\
.endif
/* use this function to ensure individual signature stores don't exceed offset limits */
/* if they would, then update the base by offset & reduce offset by -2048 */
/* there is an option to pre-increment offset if there was a previous signture store */
#define CHK_OFFSET(_BREG, _SZ, _PRE_INC) \
.if (_PRE_INC!=0) ;\
.set offset, offset+_SZ ;\
.endif ;\
.if offset>=2048 ;\
addi _BREG, _BREG, (2048 - _SZ) ;\
.set offset, offset -(2048 - _SZ) ;\
.endif
/* automatically adjust base and offset if offset gets too big */
/* RVTEST_SIGUPD(basereg, sigreg) stores sigreg at offset(basereg) and updates offset by regwidth */
/* RVTEST_SIGUPD(basereg, sigreg,newoff) stores sigreg at newoff(basereg) and updates offset to regwidth+newoff */
#define RVTEST_SIGUPD(_BR,_R,...) \
.if NARG(__VA_ARGS__) == 1 ;\
.set offset,_ARG1(__VA_OPT__(__VA_ARGS__,0)) ;\
.endif ;\
CHK_OFFSET(_BR,REGWIDTH,0);\
SREG _R,offset(_BR) ;\
.set offset,offset+REGWIDTH
#define RVTEST_SIGUPD_F(_BR,_R,_F,...) \
.if NARG(__VA_ARGS__) == 1 ;\
.set offset,_ARG1(__VA_OPT__(__VA_ARGS__,0)) ;\
.endif ;\
.if (offset & (SIGALIGN-1)) != 0 ;\
.warning "Incorrect Offset Alignment for Signature.";\
.err ;\
.endif ;\
CHK_OFFSET(_BR,SIGALIGN,0);\
FSREG _R,offset(_BR) ;\
CHK_OFFSET(_BR,SIGALIGN,1);\
SREG _F,offset(_BR) ;\
.set offset,offset+(SIGALIGN)
#define RVTEST_SIGUPD_FID(_BR,_R,_F,...) \
.if NARG(__VA_ARGS__) == 1 ;\
.set offset,_ARG1(__VA_OPT__(__VA_ARGS__,0)) ;\
.endif ;\
.if (offset & (SIGALIGN-1)) != 0 ;\
.warning "Incorrect Offset Alignment for Signature.";\
.err ;\
.endif ;\
CHK_OFFSET(_BR,SIGALIGN,0);\
SREG _R,offset(_BR) ;\
CHK_OFFSET(_BR,SIGALIGN,1);\
SREG _F,offset(_BR) ;\
.set offset,offset+(SIGALIGN)
// for updating signatures when 'rd' is a paired register (64-bit) in Zpsfoperand extension in RV32.
#define RVTEST_SIGUPD_P64(_BR,_R,_R_HI,...) \
.if NARG(__VA_ARGS__) == 0 ;\
RVTEST_SIGUPD_FID(_BR,_R,_R_HI) ;\
.else ;\
RVTEST_SIGUPD_FID(_BR,_R,_R_HI,_ARG1(__VA_OPT__(__VA_ARGS__,0)));\
.endif
// for reading vxsat.OV flag in P-ext; and only reads the flag when Zicsr extension is present
#ifdef pext_check_vxsat_ov
#define RDOV(_F)\
rdov _F
#else
#define RDOV(_F)\
nop
#endif
// for updating signatures that include flagreg when 'rd' is a paired register (64-bit) in Zpsfoperand extension in RV32.
#define RVTEST_SIGUPD_PK64(_BR,_R,_R_HI,_F,...)\
.if NARG(__VA_ARGS__) == 1 ;\
.set offset,_ARG1(__VA_OPT__(__VA_ARGS__,0)) ;\
.endif ;\
CHK_OFFSET(_BR,REGWIDTH,0);\
SREG _R,offset(_BR) ;\
CHK_OFFSET(_BR,REGWIDTH,1);\
SREG _R_HI,offset+REGWIDTH(_BR) ;\
RDOV(_F) ;\
CHK_OFFSET(_BR,REGWIDTH,1);\
SREG _F,offset+2*REGWIDTH(_BR) ;\
.set offset,offset+(3*REGWIDTH)
// for updating signatures that include flagreg for P-ext saturation instructions (RV32/RV64).
#define RVTEST_SIGUPD_PK(_BR,_R,_F,OFFSET)\
RVTEST_SIGUPD_FID(_BR,_R,_F,OFFSET)
#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) && (label == 1b) ;\
.fill 2,1,0x00 ;\
.endif ;\
xori rd,rd, 0x1 ;\
beq x0,x0,6b ;\
.if (adj & 2 == 2) && (label == 1b) ;\
.fill 2,1,0x00 ;\
.endif ;\
.if (imm/2) - 2 >= 0 ;\
.set num,(imm/2)-2 ;\
.else ;\
.set num,0 ;\
.endif ;\
.ifc 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 ;\
.ifc label, 1b ;\
.set num,0 ;\
.endif ;\
.rept num ;\
nop ;\
.endr ;\
3: .if (adj & 2 == 2) && (label == 3f) ;\
.fill 2,1,0x00 ;\
.endif ;\
xori rd,rd, 0x3 ;\
LA(tempreg, 4f ) ;\
jalr x0,0(tempreg) ;\
.if (adj&2 == 2) && (label == 3f) ;\
.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 ;\
.ifc 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 ;\
.ifc 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,fcsr_val,rs1,rs2,imm_val,offset,inst,adj,flagreg,valaddr_reg, val_offset);\
LOAD_MEM_VAL(FLREG, valaddr_reg, rs2, val_offset, testreg); \
addi rs1,swreg,offset+adj ;\
LI(testreg,imm_val) ;\
sub rs1,rs1,testreg ;\
inst rs2, imm_val(rs1) ;\
nop ;\
nop ;\
csrr flagreg, fcsr ;\
RVTEST_SIGUPD(swreg,flagreg,offset+SIGALIGN)
#define TEST_LOAD_F(swreg,testreg,fcsr_val,rs1,destreg,imm_val,inst,adj,flagreg) ;\
LA(rs1,rvtest_data+adj-imm_val) ;\
LI(testreg, fcsr_val) ;\
csrw fcsr, testreg ;\
inst destreg, imm_val(rs1) ;\
nop ;\
nop ;\
csrr flagreg, fcsr ;\
RVTEST_SIGUPD_F(swreg,destreg,flagreg)
#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, code... ) \
code; \
RVTEST_SIGUPD_F(swreg,destreg,flagreg); \
RVMODEL_IO_ASSERT_GPR_EQ(testreg, destreg, correctval)
#define TEST_CASE_FID(testreg, destreg, correctval, swreg, flagreg, code... ) \
code; \
RVTEST_SIGUPD_FID(swreg,destreg,flagreg); \
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 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, fcsr_val, correctval, valaddr_reg, val_offset, flagreg, swreg, testreg) \
TEST_CASE_F(testreg, destreg, correctval, swreg, flagreg, \
LOAD_MEM_VAL(FLREG, valaddr_reg, freg, val_offset, testreg); \
li testreg, fcsr_val; csrw fcsr, testreg; \
inst destreg, freg, rm; \
csrr flagreg, fcsr ; \
)
//Tests for floating-point instructions with a single register operand
//This variant does not take the rm field and set it while writing the instruction
#define TEST_FPSR_OP_NRM( inst, destreg, freg, fcsr_val, correctval, valaddr_reg, val_offset, flagreg, swreg, testreg) \
TEST_CASE_F(testreg, destreg, correctval, swreg, flagreg, \
LOAD_MEM_VAL(FLREG, valaddr_reg, freg, val_offset, testreg); \
li testreg, fcsr_val; csrw fcsr, testreg; \
inst destreg, freg; \
csrr flagreg, fcsr ; \
)
//Tests for floating-point instructions with a single register operand and integer destination register
#define TEST_FPID_OP( inst, destreg, freg, rm, fcsr_val, correctval, valaddr_reg, val_offset, flagreg, swreg, testreg,load_instr) \
TEST_CASE_FID(testreg, destreg, correctval, swreg, flagreg, \
LOAD_MEM_VAL(load_instr, valaddr_reg, freg, val_offset, testreg); \
li testreg, fcsr_val; csrw fcsr, testreg; \
inst destreg, freg, rm; \
csrr flagreg, fcsr ; \
)
//Tests for floating-point instructions with a single register operand and integer operand register
#define TEST_FPIO_OP( inst, destreg, freg, rm, fcsr_val, correctval, valaddr_reg, val_offset, flagreg, swreg, testreg, load_instr) \
TEST_CASE_F(testreg, destreg, correctval, swreg, flagreg, \
LOAD_MEM_VAL(load_instr, valaddr_reg, freg, val_offset, testreg); \
li testreg, fcsr_val; csrw fcsr, testreg; \
inst destreg, freg, rm; \