-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathnanorv.c
4736 lines (4287 loc) · 141 KB
/
nanorv.c
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 "nanorv.h"
//
// User-tunable compile-time options.
//
//
// Allow usage of MSVC-specific extensions/intrinsics.
//
#ifdef RV_OPT_BUILD_MSVC
#include <intrin.h>
#endif
//
// Allow usage of CRT/LibC for certain (math) functions.
//
#ifdef RV_OPT_BUILD_LIBC
#include <math.h>
#include <float.h>
#endif
//
// Allow usage of x86 SSE intrinsics.
//
#ifdef RV_OPT_BUILD_SSE
#include <intrin.h>
#include <xmmintrin.h>
#endif
//
// Set up builtin int128 types if supported.
//
#ifdef RV_OPT_BUILD_INT128_TYPES
#define int128_t __int128
#define uint128_t unsigned __int128
#endif
//
// Allow usage of C11 std atomic functions.
//
#if defined(RV_OPT_BUILD_STD_ATOMIC)
#include <stdatomic.h>
#endif
//
// Relaxed memory-order atomic aligned store.
//
#if defined(RV_OPT_HOST_ATOMIC_ALIGNED_ACCESS)
#define RV_RELAXED_ATOMIC_STORE8(Destination, Value) \
( *( volatile RV_UINT8* )(Destination) = (Value) )
#define RV_RELAXED_ATOMIC_STORE16(Destination, Value) \
( *( volatile RV_UINT16* )(Destination) = (Value) )
#define RV_RELAXED_ATOMIC_STORE32(Destination, Value) \
( *( volatile RV_UINT32* )(Destination) = (Value) )
#define RV_RELAXED_ATOMIC_STORE64(Destination, Value) \
( *( volatile RV_UINT64* )(Destination) = (Value) )
#elif defined(RV_OPT_BUILD_STD_ATOMIC)
#define RV_RELAXED_ATOMIC_STORE8(Destination, Value) \
atomic_exchange_explicit( ( volatile _Atomic(RV_UINT8)* )(Destination), (Value), memory_order_relaxed )
#define RV_RELAXED_ATOMIC_STORE16(Destination, Value) \
atomic_exchange_explicit( ( volatile _Atomic(RV_UINT16)* )(Destination), (Value), memory_order_relaxed )
#define RV_RELAXED_ATOMIC_STORE32(Destination, Value) \
atomic_exchange_explicit( ( volatile _Atomic(RV_UINT32)* )(Destination), (Value), memory_order_relaxed )
#define RV_RELAXED_ATOMIC_STORE64(Destination, Value) \
atomic_exchange_explicit( ( volatile _Atomic(RV_UINT64)* )(Destination), (Value), memory_order_relaxed )
#elif defined(RV_OPT_BUILD_MSVC)
_Static_assert( sizeof( RV_UINT8 ) == sizeof( char ), "Invalid RV_UINT8 size." );
_Static_assert( sizeof( RV_UINT16 ) == sizeof( short ), "Invalid RV_UINT16 size." );
_Static_assert( sizeof( RV_UINT32 ) == sizeof( long ), "Invalid RV_UINT32 size." );
_Static_assert( sizeof( RV_UINT64 ) == sizeof( long long ), "Invalid RV_UINT64 size." );
#define RV_RELAXED_ATOMIC_STORE8(Destination, Value) \
_InterlockedExchange8( ( volatile char* )(Destination), (Value) )
#define RV_RELAXED_ATOMIC_STORE16(Destination, Value) \
_InterlockedExchange16( ( volatile short* )(Destination), (Value) )
#define RV_RELAXED_ATOMIC_STORE32(Destination, Value) \
_InterlockedExchange( ( volatile long* )(Destination), (Value) );
#define RV_RELAXED_ATOMIC_STORE64(Destination, Value) \
_InterlockedExchange64( ( volatile long long* )(Destination), (Value) );
#else
#error "Unsupported."
#endif
//
// Relaxed memory-order atomic aligned load.
//
#if defined(RV_OPT_HOST_ATOMIC_ALIGNED_ACCESS)
#define RV_RELAXED_ATOMIC_LOAD8(Source) \
( *( volatile RV_UINT8* )(Source) )
#define RV_RELAXED_ATOMIC_LOAD16(Source) \
( *( volatile RV_UINT16* )(Source) )
#define RV_RELAXED_ATOMIC_LOAD32(Source) \
( *( volatile RV_UINT32* )(Source) )
#define RV_RELAXED_ATOMIC_LOAD64(Source) \
( *( volatile RV_UINT64* )(Source) )
#elif defined(RV_OPT_BUILD_STD_ATOMIC)
#define RV_RELAXED_ATOMIC_LOAD8(Source) \
atomic_fetch_add_explicit( ( volatile _Atomic(RV_UINT8)* )(Source), 0, memory_order_relaxed )
#define RV_RELAXED_ATOMIC_LOAD16(Source) \
atomic_fetch_add_explicit( ( volatile _Atomic(RV_UINT16)* )(Source), 0, memory_order_relaxed )
#define RV_RELAXED_ATOMIC_LOAD32(Source) \
atomic_fetch_add_explicit( ( volatile _Atomic(RV_UINT32)* )(Source), 0, memory_order_relaxed )
#define RV_RELAXED_ATOMIC_LOAD64(Source) \
atomic_fetch_add_explicit( ( volatile _Atomic(RV_UINT64)* )(Source), 0, memory_order_relaxed )
#elif defined(RV_OPT_BUILD_MSVC)
_Static_assert( sizeof( RV_UINT8 ) == sizeof( char ), "Invalid RV_UINT8 size." );
_Static_assert( sizeof( RV_UINT16 ) == sizeof( short ), "Invalid RV_UINT16 size." );
_Static_assert( sizeof( RV_UINT32 ) == sizeof( long ), "Invalid RV_UINT32 size." );
_Static_assert( sizeof( RV_UINT64 ) == sizeof( long long ), "Invalid RV_UINT64 size." );
#else
#error "Unsupported."
#endif
//
// Internal MMU types/definitions.
//
#define RV_MMU_ACCESS_TYPE_LOAD 0
#define RV_MMU_ACCESS_TYPE_STORE 1
#define RV_MMU_ACCESS_TYPE_EXECUTE 2
typedef enum _RV_MMU_ACCESS_SIZE {
RV_MMU_ACCESS_SIZE_BYTE = 1,
RV_MMU_ACCESS_SIZE_HALF_WORD = 2,
RV_MMU_ACCESS_SIZE_WORD = 4,
RV_MMU_ACCESS_SIZE_DOUBLE_WORD = 8
} RV_MMU_ACCESS_SIZE;
typedef union _RV_MEM_VALUE {
RV_UINT8 AsU8;
RV_UINT16 AsU16;
RV_UINT32 AsU32;
RV_UINT64 AsU64;
#if defined(RV_OPT_RV32F) || defined(RV_OPT_RV32D)
RV_FLOAT AsFloat;
RV_DOUBLE AsDouble;
#endif
} RV_MEM_VALUE;
typedef struct _RV_MMU_ACCESS_CHUNK {
VOID* Data;
RV_SIZE_T Size;
} RV_MMU_ACCESS_CHUNK;
#define RV_MMU_MIN_PAGESIZE 0x1000
//
// Instruction formats/instruction encoding helpers.
//
//
// RV32I instruction format R bit positions/masks.
//
#define RV_INST_R_FUNCT7_SHIFT (25ul)
#define RV_INST_R_FUNCT7_MASK ((1ul << (31 - 25 + 1)) - 1)
#define RV_INST_R_RS2_SHIFT (20ul)
#define RV_INST_R_RS2_MASK ((1ul << (24 - 20 + 1)) - 1)
#define RV_INST_R_RS1_SHIFT (15ul)
#define RV_INST_R_RS1_MASK ((1ul << (19 - 15 + 1)) - 1)
#define RV_INST_R_FUNCT3_SHIFT (12ul)
#define RV_INST_R_FUNCT3_MASK ((1ul << (14 - 12 + 1)) - 1)
#define RV_INST_R_RD_SHIFT (7ul)
#define RV_INST_R_RD_MASK ((1ul << (11 - 7 + 1)) - 1)
#define RV_INST_R_OPCODE_SHIFT (0ul)
#define RV_INST_R_OPCODE_MASK ((1ul << (6 - 0 + 1)) - 1)
//
// RV32I instruction format I bit positions/masks.
//
#define RV_INST_I_IMM_11_0_SHIFT (20ul)
#define RV_INST_I_IMM_11_0_MASK ((1ul << (31 - 20 + 1)) - 1)
#define RV_INST_I_RS1_SHIFT (15ul)
#define RV_INST_I_RS1_MASK ((1ul << (19 - 15 + 1)) - 1)
#define RV_INST_I_FUNCT3_SHIFT (12ul)
#define RV_INST_I_FUNCT3_MASK ((1ul << (14 - 12 + 1)) - 1)
#define RV_INST_I_RD_SHIFT (7ul)
#define RV_INST_I_RD_MASK ((1ul << (11 - 7 + 1)) - 1)
#define RV_INST_I_OPCODE_SHIFT (0ul)
#define RV_INST_I_OPCODE_MASK ((1ul << (6 - 0 + 1)) - 1)
//
// RV32I instruction format S bit positions/masks.
//
#define RV_INST_S_IMM_11_5_SHIFT (25ul)
#define RV_INST_S_IMM_11_5_MASK ((1ul << (31 - 25 + 1)) - 1)
#define RV_INST_S_RS2_SHIFT (20ul)
#define RV_INST_S_RS2_MASK ((1ul << (24 - 20 + 1)) - 1)
#define RV_INST_S_RS1_SHIFT (15ul)
#define RV_INST_S_RS1_MASK ((1ul << (19 - 15 + 1)) - 1)
#define RV_INST_S_FUNCT3_SHIFT (12ul)
#define RV_INST_S_FUNCT3_MASK ((1ul << (14 - 12 + 1)) - 1)
#define RV_INST_S_IMM_4_0_SHIFT (7ul)
#define RV_INST_S_IMM_4_0_MASK ((1ul << (11 - 7 + 1)) - 1)
#define RV_INST_S_OPCODE_SHIFT (0ul)
#define RV_INST_S_OPCODE_MASK ((1ul << (6 - 0 + 1)) - 1)
//
// RV32I instruction format U bit positions/masks.
//
#define RV_INST_U_IMM_31_12_SHIFT (12ul)
#define RV_INST_U_IMM_31_12_MASK ((1ul << (31 - 12 + 1)) - 1)
#define RV_INST_U_RD_SHIFT (7ul)
#define RV_INST_U_RD_MASK ((1ul << (11 - 7 + 1)) - 1)
#define RV_INST_U_OPCODE_SHIFT (0ul)
#define RV_INST_U_OPCODE_MASK ((1ul << (6 - 0 + 1)) - 1)
//
// RV32I instruction format B bit positions/masks.
//
#define RV_INST_B_IMM_12_SHIFT (31ul)
#define RV_INST_B_IMM_12_MASK (1ul)
#define RV_INST_B_IMM_10_5_SHIFT (25ul)
#define RV_INST_B_IMM_10_5_MASK ((1ul << (30 - 25 + 1)) - 1)
#define RV_INST_B_RS2_SHIFT (20ul)
#define RV_INST_B_RS2_MASK ((1ul << (24 - 20 + 1)) - 1)
#define RV_INST_B_RS1_SHIFT (15ul)
#define RV_INST_B_RS1_MASK ((1ul << (19 - 15 + 1)) - 1)
#define RV_INST_B_FUNCT3_SHIFT (12ul)
#define RV_INST_B_FUNCT3_MASK ((1ul << (14 - 12 + 1)) - 1)
#define RV_INST_B_IMM_4_1_SHIFT (8ul)
#define RV_INST_B_IMM_4_1_MASK ((1ul << (11 - 8 + 1)) - 1)
#define RV_INST_B_IMM_11_SHIFT (7ul)
#define RV_INST_B_IMM_11_MASK 1ul
#define RV_INST_B_OPCODE_SHIFT (0ul)
#define RV_INST_B_OPCODE_MASK ((1ul << (6 - 0 + 1)) - 1)
//
// RV32I instruction format J bit positions/masks.
//
#define RV_INST_J_IMM_20_SHIFT (31ul)
#define RV_INST_J_IMM_20_MASK (1ul)
#define RV_INST_J_IMM_10_1_SHIFT (21ul)
#define RV_INST_J_IMM_10_1_MASK ((1ul << (30 - 21 + 1)) - 1)
#define RV_INST_J_IMM_11_SHIFT (20ul)
#define RV_INST_J_IMM_11_MASK (1ul)
#define RV_INST_J_IMM_19_12_SHIFT (12ul)
#define RV_INST_J_IMM_19_12_MASK ((1ul << (19 - 12 + 1)) - 1)
#define RV_INST_J_RD_SHIFT (7ul)
#define RV_INST_J_RD_MASK ((1ul << (11 - 7 + 1)) - 1)
#define RV_INST_J_OPCODE_SHIFT (0ul)
#define RV_INST_J_OPCODE_MASK ((1ul << (6 - 0 + 1)) - 1)
//
// RISC-V primary opcode map.
//
#define RV_OPCODE_LOAD (3) /* (0b00'000'11) */
#define RV_OPCODE_LOAD_FP (7) /* (0b00'001'11) */
#define RV_OPCODE_CUSTOM0 (11) /* (0b00'010'11) */
#define RV_OPCODE_MISC_MEM (15) /* (0b00'011'11) */
#define RV_OPCODE_OP_IMM (19) /* (0b00'100'11) */
#define RV_OPCODE_AUIPC (23) /* (0b00'101'11) */
#define RV_OPCODE_OP_IMM32 (27) /* (0b00'110'11) */
#define RV_OPCODE_STORE (35) /* (0b01'000'11) */
#define RV_OPCODE_STORE_FP (39) /* (0b01'001'11) */
#define RV_OPCODE_CUSTOM1 (43) /* (0b01'010'11) */
#define RV_OPCODE_AMO (47) /* (0b01'011'11) */
#define RV_OPCODE_OP (51) /* (0b01'100'11) */
#define RV_OPCODE_LUI (55) /* (0b01'101'11) */
#define RV_OPCODE_OP_32 (59) /* (0b01'110'11) */
#define RV_OPCODE_MADD (67) /* (0b10'000'11) */
#define RV_OPCODE_MSUB (71) /* (0b10'001'11) */
#define RV_OPCODE_NMSUB (75) /* (0b10'010'11) */
#define RV_OPCODE_NMADD (79) /* (0b10'011'11) */
#define RV_OPCODE_OP_FP (83) /* (0b10'100'11) */
#define RV_OPCODE_RESERVED0 (87) /* (0b10'101'11) */
#define RV_OPCODE_CUSTOM2 (91) /* (0b10'110'11) */
#define RV_OPCODE_BRANCH (99) /* (0b11'000'11) */
#define RV_OPCODE_JALR (103) /* (0b11'001'11) */
#define RV_OPCODE_RESERVED1 (107) /* (0b11'010'11) */
#define RV_OPCODE_JAL (111) /* (0b11'011'11) */
#define RV_OPCODE_SYSTEM (115) /* (0b11'100'11) */
#define RV_OPCODE_RESERVED2 (119) /* (0b11'101'11) */
#define RV_OPCODE_CUSTOM3 (123) /* (0b11'110'11) */
//
// Instruction funct3 values.
//
//
// Base opcode RV_OPCODE_JALR funct3 values (I-type).
// imm[11:0] rs1 000 rd 1100111 JALR
//
#define RV_JALR_FUNCT3_BASE (0)
//
// Base opcode RV_OPCODE_BRANCH funct3 values (B-type).
//
#define RV_BRANCH_FUNCT3_BEQ (0)
#define RV_BRANCH_FUNCT3_BNE (1)
#define RV_BRANCH_FUNCT3_BLT (4)
#define RV_BRANCH_FUNCT3_BGE (5)
#define RV_BRANCH_FUNCT3_BLTU (6)
#define RV_BRANCH_FUNCT3_BGEU (7)
//
// Base opcode RV_OPCODE_LOAD funct3 values (I-type).
//
#define RV_LOAD_FUNCT3_LB (0)
#define RV_LOAD_FUNCT3_LH (1)
#define RV_LOAD_FUNCT3_LW (2)
#define RV_LOAD_FUNCT3_LBU (4)
#define RV_LOAD_FUNCT3_LHU (5)
#define RV_LOAD_FUNCT3_LD (3) /* RV64I */
#define RV_LOAD_FUNCT3_LWU (6) /* RV64I */
//
// Base opcode RV_OPCODE_STORE funct3 values (S-type).
//
#define RV_STORE_FUNCT3_SB (0)
#define RV_STORE_FUNCT3_SH (1)
#define RV_STORE_FUNCT3_SW (2)
#define RV_STORE_FUNCT3_SD (3) /* RV64I */
//
// Base opcode RV_OPCODE_OP_IMM funct3 values (I-type).
//
#define RV_OP_IMM_FUNCT3_ADDI (0)
#define RV_OP_IMM_FUNCT3_SLTI (2)
#define RV_OP_IMM_FUNCT3_SLTIU (3)
#define RV_OP_IMM_FUNCT3_XORI (4)
#define RV_OP_IMM_FUNCT3_ORI (6)
#define RV_OP_IMM_FUNCT3_ANDI (7)
//
// Base opcode RV_OPCODE_OP_IMM funct3 values (R-type).
//
#define RV_OP_IMM_FUNCT3_SLLI (1)
#define RV_OP_IMM_FUNCT3_SRLI_SRAI (5)
//
// Base opcode RV_OPCODE_OP funct3 values (R-type).
//
#define RV_OP_FUNCT3_ADD_SUB (0)
#define RV_OP_FUNCT3_SLL (1)
#define RV_OP_FUNCT3_SLT (2)
#define RV_OP_FUNCT3_SLTU (3)
#define RV_OP_FUNCT3_XOR (4)
#define RV_OP_FUNCT3_SRL_SRA (5)
#define RV_OP_FUNCT3_OR (6)
#define RV_OP_FUNCT3_AND (7)
//
// Base opcode RV_OPCODE_MISC_MEM funct3 values (I-type?)
//
#define RV_MISC_MEM_FUNCT3_FENCE (0)
//
// Base opcode RV_OPCODE_SYSTEM funct3 values.
//
#define RV_SYSTEM_FUNCT3_ECALL_EBREAK (0)
//
// RV32/RV64 Zicsr Standard Extension RV_OPCODE_SYSTEM funct3 values.
//
#define RV_SYSTEM_FUNCT3_CSRRW (1)
#define RV_SYSTEM_FUNCT3_CSRRS (2)
#define RV_SYSTEM_FUNCT3_CSRRC (3)
#define RV_SYSTEM_FUNCT3_CSRRWI (5)
#define RV_SYSTEM_FUNCT3_CSRRSI (6)
#define RV_SYSTEM_FUNCT3_CSRRCI (7)
//
// RV32M RV_OPCODE_OP funct3 values.
//
#define RV_OP_FUNCT3_RV32M_MUL (0)
#define RV_OP_FUNCT3_RV32M_MULH (1)
#define RV_OP_FUNCT3_RV32M_MULHSU (2)
#define RV_OP_FUNCT3_RV32M_MULHU (3)
#define RV_OP_FUNCT3_RV32M_DIV (4)
#define RV_OP_FUNCT3_RV32M_DIVU (5)
#define RV_OP_FUNCT3_RV32M_REM (6)
#define RV_OP_FUNCT3_RV32M_REMU (7)
//
// RV32F RV_OPCODE_OP_FP funct3 values.
//
#define RV_OP_FP_FUNCT3_FSGNJ_S (0)
#define RV_OP_FP_FUNCT3_FSGNJN_S (1)
#define RV_OP_FP_FUNCT3_FSGNJX_S (2)
#define RV_OP_FP_FUNCT3_FMIN_S (0)
#define RV_OP_FP_FUNCT3_FMAX_S (1)
#define RV_OP_FP_FUNCT3_FMV_X_W (0)
#define RV_OP_FP_FUNCT3_FEQ_S (2)
#define RV_OP_FP_FUNCT3_FLT_S (1)
#define RV_OP_FP_FUNCT3_FLE_S (0)
#define RV_OP_FP_FUNCT3_FCLASS_S (1)
#define RV_OP_FP_FUNCT3_FMV_W_X (0)
//
// RV64I RV_OPCODE_OP_IMM_32 funct3 values.
//
#define RV_OP_IMM_32_FUNCT3_ADDIW (0)
#define RV_OP_IMM_32_FUNCT3_SLLIW (1)
#define RV_OP_IMM_32_FUNCT3_SRLIW_SRAIW (5)
//
// RV64I RV_OPCODE_OP_32 funct3 values.
//
#define RVP_OP_32_FUNCT3_ADDW (0)
#define RVP_OP_32_FUNCT3_SUBW (0)
#define RVP_OP_32_FUNCT3_SLLW (1)
#define RVP_OP_32_FUNCT3_SRLW (5)
#define RVP_OP_32_FUNCT3_SRAW (5)
//
// RV64M RV_OPCODE_OP_32 funct3 values.
//
#define RV_OP_32_FUNCT3_RV64M_MULW (0)
#define RV_OP_32_FUNCT3_RV64M_DIVW (4)
#define RV_OP_32_FUNCT3_RV64M_DIVUW (5)
#define RV_OP_32_FUNCT3_RV64M_REMW (6)
#define RV_OP_32_FUNCT3_RV64M_REMUW (7)
//
// Instruction funct7 values.
//
//
// Base opcode RV_OPCODE_OP_IMM funct7 values (R-type).
//
#define RV_OP_IMM_FUNCT7_SLLI (0)
#define RV_OP_IMM_FUNCT7_SRLI (0)
#define RV_OP_IMM_FUNCT7_SRAI (32)
//
// Base opcode RV_OPCODE_OP funct7 values (R-type).
//
#define RV_OP_FUNCT7_ADD (0)
#define RV_OP_FUNCT7_SUB (32)
#define RV_OP_FUNCT7_SLL (0)
#define RV_OP_FUNCT7_SLT (0)
#define RV_OP_FUNCT7_SLTU (0)
#define RV_OP_FUNCT7_XOR (0)
#define RV_OP_FUNCT7_SRL (0)
#define RV_OP_FUNCT7_SRA (32)
#define RV_OP_FUNCT7_OR (0)
#define RV_OP_FUNCT7_AND (0)
#define RV_OP_FUNCT7_RV32M (1)
//
// RV_OPCODE_OP_IMM_32 funct7 values.
//
#define RV_OP_IMM_32_FUNCT7_SLLIW (0)
#define RV_OP_IMM_32_FUNCT7_SRLIW (0)
#define RV_OP_IMM_32_FUNCT7_SRAIW (32)
//
// RV_OPCODE_OP_32 funct7 values.
//
#define RV_OP_32_FUNCT7_ADDW (0)
#define RV_OP_32_FUNCT7_SUBW (32)
#define RV_OP_32_FUNCT7_SLLW (0)
#define RV_OP_32_FUNCT7_SRLW (0)
#define RV_OP_32_FUNCT7_SRAW (32)
#define RV_OP_32_FUNCT7_RV64M (1)
//
// RV32F RV_OPCODE_OP_FP funct7 values.
//
#define RV_OP_FP_FUNCT7_FADD_S (0)
#define RV_OP_FP_FUNCT7_FSUB_S (4)
#define RV_OP_FP_FUNCT7_FMUL_S (8)
#define RV_OP_FP_FUNCT7_FDIV_S (12)
#define RV_OP_FP_FUNCT7_FSQRT_S (44)
#define RV_OP_FP_FUNCT7_FSGNJ_S (16)
#define RV_OP_FP_FUNCT7_FSGNJN_S (16)
#define RV_OP_FP_FUNCT7_FSGNJX_S (16)
#define RV_OP_FP_FUNCT7_FMIN_FMAX_S (20)
#define RV_OP_FP_FUNCT7_FCVT_W_S_WU_S (96)
#define RV_OP_FP_FUNCT7_FMV_X_W_FCLASS_S (112)
#define RV_OP_FP_FUNCT7_FEQ_S_FLT_S_FLE_S (80)
#define RV_OP_FP_FUNCT7_FCVT_S_W_S_WU (104)
#define RV_OP_FP_FUNCT7_FMV_W_X (120)
//
// Special RV32F rs2 values.
//
#define RV_OP_FP_RS2_FSQRT_S (0)
#define RV_OP_FP_RS2_FCVT_W_S (0)
#define RV_OP_FP_RS2_FCVT_WU_S (1)
#define RV_OP_FP_RS2_FMV_X_W (0)
#define RV_OP_FP_RS2_FCLASS_S (0)
#define RV_OP_FP_RS2_FCVT_S_W (0)
#define RV_OP_FP_RS2_FCVT_S_WU (1)
#define RV_OP_FP_RS2_FMV_W_X (0)
#define RV_OP_FP_RS2_FCVT_L_S (2)
#define RV_OP_FP_RS2_FCVT_LU_S (3)
#define RV_OP_FP_RS2_FCVT_S_L (2)
#define RV_OP_FP_RS2_FCVT_S_LU (3)
//
// Instruction funct12 values.
//
//
// Base opcode RV_OPCODE_SYSTEM funct12 values.
//
#define RV_SYSTEM_FUNCT12_ECALL (0)
#define RV_SYSTEM_FUNCT12_EBREAK (1)
//
// Floating-point-specific values.
//
//
// RV32F 2-bit Floating-point format field fmt values.
//
#define RV_FP_FMT_S (0) /* 32-bit single-precision. */
#define RV_FP_FMT_D (1) /* 64-bit double-precision. */
#define RV_FP_FMT_H (2) /* 16-bit half-precision. */
#define RV_FP_FMT_Q (3) /* 128-bit quad-precision. */
//
// RV32F fcsr bitfield information.
//
#define RV_FCSR_FFLAGS_SHIFT (0ul)
#define RV_FCSR_FFLAGS_MASK ((1ul << (4 - 0 + 1)) - 1)
#define RV_FCSR_NX_SHIFT (0ul) /* Inexact. */
#define RV_FCSR_NX_MASK (1ul)
#define RV_FCSR_NX_FLAG (RV_FCSR_NX_MASK << RV_FCSR_NX_SHIFT)
#define RV_FCSR_UF_SHIFT (1ul) /* Underflow. */
#define RV_FCSR_UF_MASK (1ul)
#define RV_FCSR_UF_FLAG (RV_FCSR_UF_MASK << RV_FCSR_UF_SHIFT)
#define RV_FCSR_OF_SHIFT (2ul) /* Overflow. */
#define RV_FCSR_OF_MASK (1ul)
#define RV_FCSR_OF_FLAG (RV_FCSR_OF_MASK << RV_FCSR_OF_SHIFT)
#define RV_FCSR_DZ_SHIFT (3ul) /* Divide by Zero. */
#define RV_FCSR_DZ_MASK (1ul)
#define RV_FCSR_DZ_FLAG (RV_FCSR_DZ_MASK << RV_FCSR_DZ_SHIFT)
#define RV_FCSR_NV_SHIFT (4ul) /* Invalid operation / Divide by Zero. */
#define RV_FCSR_NV_MASK (1ul)
#define RV_FCSR_NV_FLAG (RV_FCSR_NV_MASK << RV_FCSR_NV_SHIFT)
#define RV_FCSR_FRM_SHIFT (5ul) /* Rounding Mode. */
#define RV_FCSR_FRM_MASK ((1ul << (7 - 5 + 1)) - 1)
#define RV_FCSR_RESERVED0_SHIFT (8ul) /* Reserved. */
#define RV_FCSR_RESERVED0_MASK ((1ul << (31 - 8 + 1)) - 1)
//
// RV32F rounding modes.
//
#define RV_ROUNDING_MODE_RNE (0) /* Round to Nearest, ties to Even */
#define RV_ROUNDING_MODE_RTZ (1) /* Round towards Zero */
#define RV_ROUNDING_MODE_RDN (2) /* Round Down( towards -inf ) */
#define RV_ROUNDING_MODE_RUP (3) /* Round Up( towards +inf ) */
#define RV_ROUNDING_MODE_RMM (4) /* Round to Nearest, ties to Max Magnitude */
#define RV_ROUNDING_MODE_RESERVED0 (5) /* Reserved for future use. */
#define RV_ROUNDING_MODE_RESERVED1 (6) /* Reserved for future use. */
#define RV_ROUNDING_MODE_DYN (7) /* Only valid if specified in an instruction's rm field. */
//
// RV32F classification values.
//
#define RV_FCLASS_RD_NEGATIVE_INF (1ul << 0)
#define RV_FCLASS_RD_NEGATIVE_NORMAL (1ul << 1)
#define RV_FCLASS_RD_NEGATIVE_SUBNORMAL (1ul << 2)
#define RV_FCLASS_RD_NEGATIVE_ZERO (1ul << 3)
#define RV_FCLASS_RD_POSITIVE_ZERO (1ul << 4)
#define RV_FCLASS_RD_POSITIVE_SUBNORMAL (1ul << 5)
#define RV_FCLASS_RD_POSITIVE_NORMAL (1ul << 6)
#define RV_FCLASS_RD_POSITIVE_INF (1ul << 7)
#define RV_FCLASS_RD_SIGNALING_NAN (1ul << 8)
#define RV_FCLASS_RD_QUIET_NAN (1ul << 9)
//
// RV interrupt 0 base exception indices.
//
#define RV_EXCEPTION_INSTRUCTION_ADDRESS_MISALIGNED 0
#define RV_EXCEPTION_INSTRUCTION_ACCESS_FAULT 1
#define RV_EXCEPTION_ILLEGAL_INSTRUCTION 2
#define RV_EXCEPTION_BREAKPOINT 3
#define RV_EXCEPTION_LOAD_ADDRESS_MISALIGNED 4
#define RV_EXCEPTION_LOAD_ACCESS_FAULT 5
#define RV_EXCEPTION_STORE_AMO_ADDRESS_MISALIGNED 6
#define RV_EXCEPTION_STORE_AMO_ACCESS_FAULT 7
#define RV_EXCEPTION_ENV_CALL_FROM_U_MODE 8
#define RV_EXCEPTION_ENV_CALL_FROM_S_MODE 9
#define RV_EXCEPTION_RESERVED0 10
#define RV_EXCEPTION_ENV_CALL_FROM_M_MODE 11
#define RV_EXCEPTION_INSTRUCTION_PAGE_FAULT 12
#define RV_EXCEPTION_LOAD_PAGE_FAULT 13
#define RV_EXCEPTION_RESERVED1 14
#define RV_EXCEPTION_STORE_AMO_PAGE_FAULT 15
//
// CSR numbers/fields.
//
#define RV_CSR_ACCESS_READ (1 << 0)
#define RV_CSR_ACCESS_WRITE (1 << 1)
//
// Floating-Point Control and Status Registers
// 0x001 Read/write fflags Floating-Point Accrued Exceptions.
// 0x002 Read/write frm Floating-Point Dynamic Rounding Mode.
// 0x003 Read/write fcsr Floating-Point Control and Status Register (frm + fflags).
//
#define RV_CSR_VALUE_FFLAGS (0x001)
#define RV_CSR_PERMISSION_FFLAGS (RV_CSR_ACCESS_READ | RV_CSR_ACCESS_WRITE)
#define RV_CSR_VALUE_FRM (0x002)
#define RV_CSR_PERMISSION_FRM (RV_CSR_ACCESS_READ | RV_CSR_ACCESS_WRITE)
#define RV_CSR_VALUE_FCSR (0x003)
#define RV_CSR_PERMISSION_FCSR (RV_CSR_ACCESS_READ | RV_CSR_ACCESS_WRITE)
//
// Counters and Timers
// 0xC00 Read-only cycle Cycle counter for RDCYCLE instruction.
// 0xC01 Read-only time Timer for RDTIME instruction.
// 0xC02 Read-only instret Instructions-retired counter for RDINSTRET instruction.
// 0xC80 Read-only cycleh Upper 32 bits of cycle, RV32I only.
// 0xC81 Read-only timeh Upper 32 bits of time, RV32I only.
// 0xC82 Read-only instreth Upper 32 bits of instret, RV32I only.
//
#define RV_CSR_VALUE_CYCLE (0xC00)
#define RV_CSR_PERMISSION_CYCLE (RV_CSR_ACCESS_READ)
#define RV_CSR_VALUE_TIME (0xC01)
#define RV_CSR_PERMISSION_TIME (RV_CSR_ACCESS_READ)
#define RV_CSR_VALUE_INSTRET (0xC02)
#define RV_CSR_PERMISSION_INSTRET (RV_CSR_ACCESS_READ)
#define RV_CSR_VALUE_CYCLEH (0xC80)
#define RV_CSR_PERMISSION_CYCLEH (RV_CSR_ACCESS_READ)
#define RV_CSR_VALUE_TIMEH (0xC81)
#define RV_CSR_PERMISSION_TIMEH (RV_CSR_ACCESS_READ)
#define RV_CSR_VALUE_INSTRETH (0xC82)
#define RV_CSR_PERMISSION_INSTRETH (RV_CSR_ACCESS_READ)
//
// Instruction decoder helpers.
//
//
// Build an instruction classification value from opcode + funct3 + funct7 parts.
//
#define RV_INST_CLASSIFY_F3F7(Opcode, Funct3, Funct7) \
(((Opcode) & RV_INST_R_OPCODE_MASK) \
| (((Funct3) & RV_INST_R_FUNCT3_MASK) << 7ul) \
| (((Funct7) & RV_INST_R_FUNCT7_MASK) << 10ul))
//
// Exception/interrupt functions.
//
//
// Push exception interrupt.
//
static
VOID
RvpExceptionPush(
_Inout_ RV_PROCESSOR* Vp,
_In_ RV_UINT32 ExceptionIndex
)
{
//
// Mark the given exception as pending.
// Currently only a single exception may be queued per instruction.
//
Vp->ExceptionIndex = ExceptionIndex;
Vp->ExceptionPending = 1;
}
//
// Helper functions.
//
//
// Sign extends a 32-bit value with a variable sign bit index.
//
static
RV_UINT32
RvpSignExtend32(
_Inout_ RV_PROCESSOR* Vp,
_In_ RV_UINT32 Value,
_In_ RV_UINT32 SignBitIndex
)
{
RV_UINT32 SxValueBitSize;
RV_UINT32 SignBitIsSet;
RV_UINT32 ExtensionMask;
RV_UINT32 ValueMask;
RV_UINT32 SxValue;
//
// Get sign bit boolean value, and calculate a mask of all bits below the sign bit.
//
SignBitIsSet = ( ( Value & ( 1ul << SignBitIndex ) ) >> SignBitIndex );
SxValueBitSize = ( sizeof( SxValueBitSize ) * CHAR_BIT );
ValueMask = ( ( ( RV_UINT32 )1ul << SignBitIndex ) - 1 );
//
// Calculate a mask with all word bits set to SignBitIsSet.
//
ExtensionMask = ( ( ( RV_UINT32 )SignBitIsSet << ( SxValueBitSize - 1 ) ) - SignBitIsSet );
ExtensionMask |= ( ( RV_UINT32 )SignBitIsSet << ( SxValueBitSize - 1 ) );
//
// Set all bits that aren't below the sign bit to the value of SignBitIsSet.
//
SxValue = Value;
SxValue |= ( ExtensionMask & ~ValueMask );
return SxValue;
}
//
// MMU functions.
//
#if defined(RV_OPT_MMU_GTH_PAGING)
//
// Convert a guest physical-page-number to host virtual address.
// Used to convert the PPNs contained by page-tables to host-accessible addresses.
// Note: this function is currently only used for guest-to-host mapping.
//
_Success_( return )
static
RV_BOOLEAN
RvpMmuPtGuestPpnToHostVa(
_Inout_ RV_PROCESSOR* Vp,
_In_ RV_UINT64 GuestPpn,
_Out_ VOID** ppHostAddress
)
{
UNREFERENCED_PARAMETER( Vp );
if( GuestPpn > ( UINT64_MAX / RV_SV48_PAGESIZE ) ) {
return RV_FALSE;
}
*ppHostAddress = ( VOID* )( GuestPpn * RV_SV48_PAGESIZE );
return RV_TRUE;
}
//
// Convert a guest physical address to host virtual address.
// Note: this function is currently only used for guest-to-host mapping.
//
_Success_( return )
static
RV_BOOLEAN
RvpMmuPtGuestPaToHostVa(
_Inout_ RV_PROCESSOR* Vp,
_In_ RV_UINT64 GuestPa,
_Out_ VOID** ppHostAddress
)
{
RV_UINT64 GuestPpn;
VOID* PageHostAddress;
//
// PPN of the PA.
//
GuestPpn = ( GuestPa / RV_SV48_PAGESIZE );
//
// Translate PPN of the given PA.
//
if( RvpMmuPtGuestPpnToHostVa( Vp, GuestPpn, &PageHostAddress ) == RV_FALSE ) {
return RV_FALSE;
}
//
// Add on the page offset to translated HVA of the PPN.
//
*ppHostAddress = ( ( RV_UCHAR* )PageHostAddress + ( GuestPa & ( RV_SV48_PAGESIZE - 1 ) ) );
return RV_TRUE;
}
//
// Perform SV48 page table lookup.
// Note: this function is currently only used for guest-to-host mapping.
//
RV_MMU_TREE_WALK_RESULT
RvpMmuPtSv48TreeWalk(
_Inout_ RV_PROCESSOR* Vp,
_In_ RV_UINT64 TableRootPpn,
_In_ RV_UINT64 LookupVa,
_In_ RV_UINT32 AccessFlags
)
{
RV_MMU_TREE_WALK_RESULT Result;
RV_UINT64 RootPpn;
RV_UINT64 RootPa;
RV_UINT64 PageSize;
RV_UINT i;
RV_UINT64 PtePa;
VOID* PteHva;
RV_UINT64 Pte;
RV_UINT64 VpnShift;
RV_UINT64 Vpn;
RV_UINT64 PpnFull;
RV_SIZE_T j;
RV_UINT64 Pa;
RV_UINT64 PpnShift;
RV_UINT64 PpnMask;
//
// Physical page number (PPN) of the root page table.
//
RootPpn = TableRootPpn;
//
// Page size.
//
PageSize = RV_SV48_PAGESIZE;
//
// Physical address of the root page table (a).
// 1. Let a be satp.ppn * PAGESIZE, and let i = (LEVELS - 1). (For Sv48, PAGESIZE=4096 and
// LEVELS=4.) The satp register must be active, i.e., the effective privilege mode must be
// S-mode or U-mode.
//
RootPa = ( RootPpn * PageSize );
i = ( RV_SV48_LEVELS - 1 );
//
// Set up empty initial results
//
Result = ( RV_MMU_TREE_WALK_RESULT ){ 0 };
//
// Search all levels for a leaf node.
//
while( RV_TRUE ) {
Result.Level = i;
//
// 2. Let pte be the value of the PTE at address a+va.vpn[i]*PTESIZE. (For Sv48, PTESIZE=8.)
// If accessing pte violates a PMA or PMP check, raise an access-fault exception corresponding
// to the original access type.
//
VpnShift = ( RV_SV48_VA_VPN0_SHIFT + ( i * RV_SV48_VA_VPN_BIT_COUNT ) );
Vpn = ( ( LookupVa & ( RV_SV48_VA_VPN0_MASK << VpnShift ) ) >> VpnShift );
PtePa = ( RootPa + ( Vpn * RV_SV48_PTESIZE ) );
//
// Translate the PTE's PA to a host virtual address.
//
if( RvpMmuPtGuestPaToHostVa( Vp, PtePa, &PteHva ) == RV_FALSE ) {
Result.IsPresent = 0;
break;
}
//
// Read the value of the PTE.
//
Pte = *( volatile RV_UINT64* )PteHva;
//
// 3. If pte.v = 0, or if pte.r = 0 and pte.w = 1, or if any bits or encodings that are reserved for
// future standard use are set within pte, stop and raise a page-fault exception corresponding
// to the original access type.
//
if( ( Pte & RV_SV48_PTE_V_FLAG ) == 0
|| ( ( Pte & ( RV_SV48_PTE_R_FLAG | RV_SV48_PTE_W_FLAG ) ) == RV_SV48_PTE_W_FLAG )
|| ( ( Pte & ( RV_SV48_PTE_R_FLAG | RV_SV48_PTE_W_FLAG | RV_SV48_PTE_X_FLAG ) )
== ( RV_SV48_PTE_W_FLAG | RV_SV48_PTE_X_FLAG ) ) )
{
Result.IsPresent = 0;
break;
}
//
// Read PPN field of the PTE.
// If this is a leaf node, then this is the PPN of the memory controlled by the PTE.
// If this isn't a leaf node, then this is the PPN of another page table level.
//
PpnFull = RV_SV48_PTE_FULL_PPN( Pte );
//
// 4. Otherwise, the PTE is valid. If pte.r = 1 or pte.x = 1, go to step 5. Otherwise, this PTE is a
// pointer to the next level of the page table. Let i = i-1. If i < 0, stop and raise a page-fault
// exception corresponding to the original access type. Otherwise, let a = pte.ppn*PAGESIZE
// and go to step 2.
//
if( ( Pte & ( RV_SV48_PTE_R_FLAG | RV_SV48_PTE_X_FLAG ) ) == 0 ) {
//
// This PTE is a pointer to the next level of the page table.
//
if( i == 0 ) {
//
// If this was the last level, and still wasn't a leaf node, this PTE is invalid,
// stop and raise a page-fault exception corresponding to the original access type.
//
Result.IsPresent = 0;
break;
}
//
// Move down to the next level of the page table.
//
i -= 1;
//
// let a = pte.ppn*PAGESIZE and go to step 2.
//
RootPa = ( PpnFull * RV_SV48_PAGESIZE );
continue;
}
//
// 5. A leaf PTE has been found. Determine if the requested memory access is allowed by the
// pte.r, pte.w, pte.x, and pte.u bits, given the current privilege mode and the value of the
// SUM and MXR fields of the mstatus register. If not, stop and raise a page-fault exception
// corresponding to the original access type.
//
if( ( Pte & AccessFlags ) != AccessFlags ) {
Result.IsAccessFault = 1;
break;
}
//
// 6. If i > 0 and pte.ppn[i - 1 : 0] != 0, this is a misaligned superpage;
// stop and raise a page-fault exception corresponding to the original access type.
//
if( i > 0 ) {
for( j = 0; j < i; j++ ) {
PpnShift = ( RV_SV48_PTE_PPN0_SHIFT + ( 9 * j ) );
PpnMask = ( ( i == 3 ) ? RV_SV48_PTE_PPN3_MASK : RV_SV48_PTE_PPN0_MASK );
if( ( Pte & ( PpnMask << PpnShift ) ) != 0 ) {
Result.IsPresent = 0;
break;
}
}
}
//
// 7. If pte.a = 0, or if the original memory access is a store and pte.d = 0,
// either raise a page-fault exception corresponding to the original access type, or:
// * If a store to pte would violate a PMA or PMP check, raise an access-fault exception
// corresponding to the original access type.
//
// * Perform the following steps atomically:
// - Compare pte to the value of the PTE at address a + va.vpn[i] * PTESIZE.
// - If the values match, set pte.a to 1 and, if the original memory access is a store, also
// set pte.d to 1.
// - If the comparison fails, return to step 2
//
if( ( Pte & RV_SV48_PTE_A_FLAG )
|| ( ( AccessFlags & RV_SV48_PTE_W_FLAG ) && ( Pte & RV_SV48_PTE_D_FLAG ) == 0 ) )
{
/* TODO. */
}
//
// pa.pgoff = va.pgoff.
//
Pa = ( ( ( LookupVa & RV_SV48_VA_PGOFF_MASK ) >> RV_SV48_VA_PGOFF_SHIFT ) << RV_SV48_PA_PGOFF_SHIFT );
//
// If i > 0, then this is a superpage translation and pa.ppn[i - 1 : 0] = va.vpn[i - 1 : 0].
//
if( i > 0 ) {