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
//! 共享 RISC-V 内部函数
mod p;

pub use p::*;

use crate::arch::asm;

/// 生成 `PAUSE` 指令
///
/// PAUSE 指令是一个提示,指示当前 hart 的指令退出率应该暂时降低或暂停。
/// 其影响的持续时间必须有界,并且可以为零。
#[inline]
pub fn pause() {
    unsafe { asm!(".insn i 0x0F, 0, x0, x0, 0x010", options(nomem, nostack)) }
}

/// 生成 `NOP` 指令
///
/// 除了推进 `pc` 和增加任何适用的性能计数器外,NOP 指令不会改变任何架构可见的状态。
///
#[inline]
pub fn nop() {
    unsafe { asm!("nop", options(nomem, nostack)) }
}

/// 生成 `WFI` 指令
///
/// WFI 指令为实现提供了一个提示,即当前的 hart 可以暂停,直到可能需要服务中断。
///
/// 该指令是一个提示,合法的实现是简单地将 WFI 实现为 NOP。
#[inline]
pub unsafe fn wfi() {
    asm!("wfi", options(nomem, nostack))
}

/// 生成 `FENCE.I` 指令
///
/// FENCE.I 指令可确保 RISC-V hart 上的后续指令提取将看到任何先前对同一 RISC-V hart 可见的数据存储。
///
///
/// FENCE.I 不确保其他 RISC-V hart 的指令提取会观察多处理器系统中本地 hart 的存储。
///
#[inline]
pub unsafe fn fence_i() {
    asm!("fence.i", options(nostack))
}

/// 给定虚拟地址和地址空间的内存管理栅栏
///
/// 对于由整数参数 `asid` 标识的地址空间,栅栏命令仅对与参数 `vaddr` 中的虚拟地址相对应的叶页表条目进行读取和写入。对全局映射的访问没有排序。
/// 除了包含全局映射的条目外,该栅栏还使所有包含与参数 `vaddr` 中的虚拟地址相对应的叶页表条目并且匹配由整数参数 `asid` 标识的地址空间的所有地址转换缓存条目无效。
///
///
///
///
#[inline]
pub unsafe fn sfence_vma(vaddr: usize, asid: usize) {
    asm!("sfence.vma {}, {}", in(reg) vaddr, in(reg) asid, options(nostack))
}

/// 给定虚拟地址的主管内存管理栅栏
///
/// 对于所有地址空间,栅栏命令仅对与参数 `vaddr` 中的虚拟地址相对应的叶页表条目进行读取和写入。
/// 对于所有地址空间,栅栏还使包含与参数 `vaddr` 中的虚拟地址相对应的叶页表条目的所有地址转换缓存条目无效。
///
///
#[inline]
pub unsafe fn sfence_vma_vaddr(vaddr: usize) {
    asm!("sfence.vma {}, x0", in(reg) vaddr, options(nostack))
}

/// 给定地址空间的主管内存管理栅栏
///
/// 栅栏命令对任何级别的页表进行的所有读取和写入,但仅限于由整数参数 `asid` 标识的地址空间。
///
/// 对全局映射的访问没有排序。
/// 栅栏还使所有与整数参数 `asid` 标识的地址空间匹配的地址转换缓存条目无效,但包含外部映射的条目除外。
///
///
#[inline]
pub unsafe fn sfence_vma_asid(asid: usize) {
    asm!("sfence.vma x0, {}", in(reg) asid, options(nostack))
}

/// 所有地址空间和虚拟地址的主管内存管理栅栏
///
/// 栅栏对所有地址空间的页表的任何级别进行的所有读取和写入排序。
///
/// 栅栏还使所有地址空间的所有地址转换缓存条目无效。
#[inline]
pub unsafe fn sfence_vma_all() {
    asm!("sfence.vma", options(nostack))
}

/// 使给定虚拟地址和地址空间的主管转换缓存无效
///
/// 该指令使具有相同 `vaddr` 和 `asid` 值的 `SFENCE.VMA` 指令无效的任何地址转换缓存条目无效。
///
#[inline]
pub unsafe fn sinval_vma(vaddr: usize, asid: usize) {
    // asm!("sinval.vma {}, {}", in(reg) vaddr, in(reg) asid, options(nostack))
    asm!(".insn r 0x73, 0, 0x0B, x0, {}, {}", in(reg) vaddr, in(reg) asid, options(nostack))
}

/// 使给定虚拟地址的主管转换缓存无效
///
/// 该指令使具有相同 `vaddr` 和 `asid` 值的 `SFENCE.VMA` 指令无效的任何地址转换缓存条目无效。
///
#[inline]
pub unsafe fn sinval_vma_vaddr(vaddr: usize) {
    asm!(".insn r 0x73, 0, 0x0B, x0, {}, x0", in(reg) vaddr, options(nostack))
}

/// 使给定地址空间的主管转换缓存无效
///
/// 该指令使具有相同 `vaddr` 和 `asid` 值的 `SFENCE.VMA` 指令无效的任何地址转换缓存条目无效。
///
#[inline]
pub unsafe fn sinval_vma_asid(asid: usize) {
    asm!(".insn r 0x73, 0, 0x0B, x0, x0, {}", in(reg) asid, options(nostack))
}

/// 使所有地址空间和虚拟地址的主管转换缓存无效
///
/// 该指令使具有相同 `vaddr` 和 `asid` 值的 `SFENCE.VMA` 指令无效的任何地址转换缓存条目无效。
///
#[inline]
pub unsafe fn sinval_vma_all() {
    asm!(".insn r 0x73, 0, 0x0B, x0, x0, x0", options(nostack))
}

/// 生成 `SFENCE.W.INVAL` 指令
///
/// 该指令保证对当前 RISC-V hart 已经可见的任何先前存储在同一 hart 执行的后续 `SINVAL.VMA` 指令之前排序。
///
#[inline]
pub unsafe fn sfence_w_inval() {
    // asm!("sfence.w.inval", options(nostack))
    asm!(".insn i 0x73, 0, x0, x0, 0x180", options(nostack))
}

/// 生成 `SFENCE.INVAL.IR` 指令
///
/// 该指令保证当前 hart 执行的任何先前的 SINVAL.VMA 指令在该 hart 对内存管理数据结构的后续隐式引用之前被排序。
///
#[inline]
pub unsafe fn sfence_inval_ir() {
    // asm!("sfence.inval.ir", options(nostack))
    asm!(".insn i 0x73, 0, x0, x0, 0x181", options(nostack))
}

/// 按有符号字节整数加载虚拟机内存
///
/// 该指令执行显式内存访问,就像 `V=1` 一样;
/// 即,具有地址转换和保护以及字节序,适用于 VS 模式或 VU 模式下的内存访问。
///
/// 这个函数是不安全的,因为它通过 `HLV.B` 指令访问虚拟 supervisor 或用户,这实际上是对任何内存地址的解引用。
///
///
#[inline]
pub unsafe fn hlv_b(src: *const i8) -> i8 {
    let value: i8;
    asm!(".insn i 0x73, 0x4, {}, {}, 0x600", out(reg) value, in(reg) src, options(readonly, nostack));
    value
}

/// 按无符号字节整数加载虚拟机内存
///
/// 该指令执行显式内存访问,就像 `V=1` 一样;
/// 即,具有地址转换和保护以及字节序,适用于 VS 模式或 VU 模式下的内存访问。
///
/// 这个函数是不安全的,因为它通过 `HLV.BU` 指令访问虚拟 supervisor 或用户,这实际上是对任何内存地址的解引用。
///
///
#[inline]
pub unsafe fn hlv_bu(src: *const u8) -> u8 {
    let value: u8;
    asm!(".insn i 0x73, 0x4, {}, {}, 0x601", out(reg) value, in(reg) src, options(readonly, nostack));
    value
}

/// 通过有符号的半整数加载虚拟机内存
///
/// 该指令执行显式内存访问,就像 `V=1` 一样;
/// 即,具有地址转换和保护以及字节序,适用于 VS 模式或 VU 模式下的内存访问。
///
/// 这个函数是不安全的,因为它通过 `HLV.H` 指令访问虚拟 supervisor 或用户,这实际上是对任何内存地址的解引用。
///
///
#[inline]
pub unsafe fn hlv_h(src: *const i16) -> i16 {
    let value: i16;
    asm!(".insn i 0x73, 0x4, {}, {}, 0x640", out(reg) value, in(reg) src, options(readonly, nostack));
    value
}

/// 按无符号半整数加载虚拟机内存
///
/// 该指令执行显式内存访问,就像 `V=1` 一样;
/// 即,具有地址转换和保护以及字节序,适用于 VS 模式或 VU 模式下的内存访问。
///
/// 这个函数是不安全的,因为它通过 `HLV.HU` 指令访问虚拟 supervisor 或用户,这实际上是对任何内存地址的解引用。
///
///
#[inline]
pub unsafe fn hlv_hu(src: *const u16) -> u16 {
    let value: u16;
    asm!(".insn i 0x73, 0x4, {}, {}, 0x641", out(reg) value, in(reg) src, options(readonly, nostack));
    value
}

/// 通过无符号半整数访问虚拟机指令
///
/// 该指令执行显式内存访问,就像 `V=1` 一样;
/// 被读取的内存在地址转换的两个阶段都必须是可执行的,但不需要读取权限。
///
/// 这个函数是不安全的,因为它通过 `HLVX.HU` 指令访问虚拟 supervisor 或用户,这实际上是对任何内存地址的解引用。
///
///
#[inline]
pub unsafe fn hlvx_hu(src: *const u16) -> u16 {
    let insn: u16;
    asm!(".insn i 0x73, 0x4, {}, {}, 0x643", out(reg) insn, in(reg) src, options(readonly, nostack));
    insn
}

/// 按有符号字整数加载虚拟机内存
///
/// 该指令执行显式内存访问,就像 `V=1` 一样;
/// 即,具有地址转换和保护以及字节序,适用于 VS 模式或 VU 模式下的内存访问。
///
/// 这个函数是不安全的,因为它通过 `HLV.W` 指令访问虚拟 supervisor 或用户,这实际上是对任何内存地址的解引用。
///
///
#[inline]
pub unsafe fn hlv_w(src: *const i32) -> i32 {
    let value: i32;
    asm!(".insn i 0x73, 0x4, {}, {}, 0x680", out(reg) value, in(reg) src, options(readonly, nostack));
    value
}

/// 通过无符号字整数访问虚拟机指令
///
/// 该指令执行显式内存访问,就像 `V=1` 一样;
/// 被读取的内存在地址转换的两个阶段都必须是可执行的,但不需要读取权限。
///
/// 这个函数是不安全的,因为它通过 `HLVX.WU` 指令访问虚拟 supervisor 或用户,这实际上是对任何内存地址的解引用。
///
///
#[inline]
pub unsafe fn hlvx_wu(src: *const u32) -> u32 {
    let insn: u32;
    asm!(".insn i 0x73, 0x4, {}, {}, 0x683", out(reg) insn, in(reg) src, options(readonly, nostack));
    insn
}

/// 按字节整数存储虚拟机内存
///
/// 该指令执行显式内存访问,就像 `V=1` 一样;
/// 即,具有地址转换和保护以及字节序,适用于 VS 模式或 VU 模式下的内存访问。
///
/// 这个函数是不安全的,因为它通过 `HSV.B` 指令访问虚拟 supervisor 或用户,这实际上是对任何内存地址的解引用。
///
///
#[inline]
pub unsafe fn hsv_b(dst: *mut i8, src: i8) {
    asm!(".insn r 0x73, 0x4, 0x31, x0, {}, {}", in(reg) dst, in(reg) src, options(nostack));
}

/// 按半整数存储虚拟机内存
///
/// 该指令执行显式内存访问,就像 `V=1` 一样;
/// 即,具有地址转换和保护以及字节序,适用于 VS 模式或 VU 模式下的内存访问。
///
/// 这个函数是不安全的,因为它通过 `HSV.H` 指令访问虚拟 supervisor 或用户,这实际上是对任何内存地址的解引用。
///
///
#[inline]
pub unsafe fn hsv_h(dst: *mut i16, src: i16) {
    asm!(".insn r 0x73, 0x4, 0x33, x0, {}, {}", in(reg) dst, in(reg) src, options(nostack));
}

/// 按字整数存储虚拟机内存
///
/// 该指令执行显式内存访问,就像 `V=1` 一样;
/// 即,具有地址转换和保护以及字节序,适用于 VS 模式或 VU 模式下的内存访问。
///
/// 这个函数是不安全的,因为它通过 `HSV.W` 指令访问虚拟 supervisor 或用户,这实际上是对任何内存地址的解引用。
///
///
#[inline]
pub unsafe fn hsv_w(dst: *mut i32, src: i32) {
    asm!(".insn r 0x73, 0x4, 0x35, x0, {}, {}", in(reg) dst, in(reg) src, options(nostack));
}

/// 给定来宾虚拟地址和来宾地址空间的管理程序内存管理栅栏
///
/// 保证在该 hart 为 VS 阶段地址转换完成指令的所有隐式读取之前,对当前 hart 已经可见的任何先前存储进行排序:
///
/// - 在 `HFENCE.VVMA` 之后,并且
/// - 当 `hgatp.VMID` 具有与执行 `HFENCE.VVMA` 时相同的设置时执行。
///
/// 这个栅栏指定了一个单一的客户虚拟地址和一个单一的客户地址空间标识符。
#[inline]
pub unsafe fn hfence_vvma(vaddr: usize, asid: usize) {
    // asm!("hfence.vvma {}, {}", in(reg) vaddr, in(reg) asid)
    asm!(".insn r 0x73, 0, 0x11, x0, {}, {}", in(reg) vaddr, in(reg) asid, options(nostack))
}

/// 给定来宾虚拟地址的管理程序内存管理栅栏
///
/// 保证在该 hart 为 VS 阶段地址转换完成指令的所有隐式读取之前,对当前 hart 已经可见的任何先前存储进行排序:
///
/// - 在 `HFENCE.VVMA` 之后,并且
/// - 当 `hgatp.VMID` 具有与执行 `HFENCE.VVMA` 时相同的设置时执行。
///
/// 此栅栏指定单个访客虚拟地址。
#[inline]
pub unsafe fn hfence_vvma_vaddr(vaddr: usize) {
    asm!(".insn r 0x73, 0, 0x11, x0, {}, x0", in(reg) vaddr, options(nostack))
}

/// 给定来宾地址空间的管理程序内存管理栅栏
///
/// 保证在该 hart 为 VS 阶段地址转换完成指令的所有隐式读取之前,对当前 hart 已经可见的任何先前存储进行排序:
///
/// - 在 `HFENCE.VVMA` 之后,并且
/// - 当 `hgatp.VMID` 具有与执行 `HFENCE.VVMA` 时相同的设置时执行。
///
/// 这个栅栏指定了一个单一的客户地址空间标识符。
#[inline]
pub unsafe fn hfence_vvma_asid(asid: usize) {
    asm!(".insn r 0x73, 0, 0x11, x0, x0, {}", in(reg) asid, options(nostack))
}

/// 所有来宾地址空间和来宾虚拟地址的管理程序内存管理栅栏
///
/// 保证在该 hart 为 VS 阶段地址转换完成指令的所有隐式读取之前,对当前 hart 已经可见的任何先前存储进行排序:
///
/// - 在 `HFENCE.VVMA` 之后,并且
/// - 当 `hgatp.VMID` 具有与执行 `HFENCE.VVMA` 时相同的设置时执行。
///
/// 此栅栏适用于任何访客地址空间和访客虚拟地址。
#[inline]
pub unsafe fn hfence_vvma_all() {
    asm!(".insn r 0x73, 0, 0x11, x0, x0, x0", options(nostack))
}

/// 来宾物理地址和虚拟机的管理程序内存管理栅栏
///
/// 保证对当前 hart 已经可见的任何先前存储在该 hart 为跟在 HFENCE.GVMA 之后的指令的 G 级地址转换完成的所有隐式读取之前排序。
///
///
/// 这个栅栏指定了一个单一的来宾物理地址,**右移 2 位**,以及一个虚拟机标识符 (VMID) 的虚拟机。
///
#[inline]
pub unsafe fn hfence_gvma(gaddr: usize, vmid: usize) {
    // asm!("hfence.gvma {}, {}", in(reg) gaddr, in(reg) vmid, options(nostack))
    asm!(".insn r 0x73, 0, 0x31, x0, {}, {}", in(reg) gaddr, in(reg) vmid, options(nostack))
}

/// 来宾物理地址的虚拟机管理程序内存管理栅栏
///
/// 保证对当前 hart 已经可见的任何先前存储在该 hart 为跟在 HFENCE.GVMA 之后的指令的 G 级地址转换完成的所有隐式读取之前排序。
///
///
/// 这个栅栏指定了一个单一的访客物理地址; **物理地址应右移 2 位**。
#[inline]
pub unsafe fn hfence_gvma_gaddr(gaddr: usize) {
    asm!(".insn r 0x73, 0, 0x31, x0, {}, x0", in(reg) gaddr, options(nostack))
}

/// 给定虚拟机的管理程序内存管理栅栏
///
/// 保证对当前 hart 已经可见的任何先前存储在该 hart 为跟在 HFENCE.GVMA 之后的指令的 G 级地址转换完成的所有隐式读取之前排序。
///
///
/// 此栅栏通过虚拟机标识符 (VMID) 指定单个虚拟机。
#[inline]
pub unsafe fn hfence_gvma_vmid(vmid: usize) {
    asm!(".insn r 0x73, 0, 0x31, x0, x0, {}", in(reg) vmid, options(nostack))
}

/// 适用于所有虚拟机和来宾物理地址的管理程序内存管理栅栏
///
/// 保证对当前 hart 已经可见的任何先前存储在该 hart 为跟在 HFENCE.GVMA 之后的指令的 G 级地址转换完成的所有隐式读取之前排序。
///
///
/// 此栅栏指定所有来宾物理地址和所有虚拟机。
#[inline]
pub unsafe fn hfence_gvma_all() {
    asm!(".insn r 0x73, 0, 0x31, x0, x0, x0", options(nostack))
}

/// 使给定来宾虚拟地址和来宾地址空间的管理程序转换缓存无效
///
/// 该指令使具有相同 `vaddr` 和 `asid` 值的 `HFENCE.VVMA` 指令无效的任何地址转换缓存条目无效。
///
///
/// 这个栅栏指定了一个单一的客户虚拟地址和一个单一的客户地址空间标识符。
#[inline]
pub unsafe fn hinval_vvma(vaddr: usize, asid: usize) {
    // asm!("hinval.vvma {}, {}", in(reg) vaddr, in(reg) asid, options(nostack))
    asm!(".insn r 0x73, 0, 0x13, x0, {}, {}", in(reg) vaddr, in(reg) asid, options(nostack))
}

/// 使给定来宾虚拟地址的管理程序转换缓存无效
///
/// 该指令使具有相同 `vaddr` 和 `asid` 值的 `HFENCE.VVMA` 指令无效的任何地址转换缓存条目无效。
///
///
/// 此栅栏指定单个访客虚拟地址。
#[inline]
pub unsafe fn hinval_vvma_vaddr(vaddr: usize) {
    asm!(".insn r 0x73, 0, 0x13, x0, {}, x0", in(reg) vaddr, options(nostack))
}

/// 使给定来宾地址空间的管理程序转换缓存无效
///
/// 该指令使具有相同 `vaddr` 和 `asid` 值的 `HFENCE.VVMA` 指令无效的任何地址转换缓存条目无效。
///
///
/// 这个栅栏指定了一个单一的客户地址空间标识符。
#[inline]
pub unsafe fn hinval_vvma_asid(asid: usize) {
    asm!(".insn r 0x73, 0, 0x13, x0, x0, {}", in(reg) asid, options(nostack))
}

/// 使所有来宾地址空间和来宾虚拟地址的管理程序转换缓存无效
///
/// 该指令使具有相同 `vaddr` 和 `asid` 值的 `HFENCE.VVMA` 指令无效的任何地址转换缓存条目无效。
///
///
/// 此栅栏适用于任何访客地址空间和访客虚拟地址。
#[inline]
pub unsafe fn hinval_vvma_all() {
    asm!(".insn r 0x73, 0, 0x13, x0, x0, x0", options(nostack))
}

/// 使来宾物理地址和虚拟机的管理程序转换缓存无效
///
/// 该指令使具有相同 `gaddr` 和 `vmid` 值的 `HFENCE.GVMA` 指令无效的任何地址转换缓存条目无效。
///
///
/// 这个栅栏指定了一个单一的来宾物理地址,**右移 2 位**,以及一个虚拟机标识符 (VMID) 的虚拟机。
///
#[inline]
pub unsafe fn hinval_gvma(gaddr: usize, vmid: usize) {
    // asm!("hinval.gvma {}, {}", in(reg) gaddr, in(reg) vmid, options(nostack))
    asm!(".insn r 0x73, 0, 0x33, x0, {}, {}", in(reg) gaddr, in(reg) vmid, options(nostack))
}

/// 使来宾物理地址的管理程序转换缓存无效
///
/// 该指令使具有相同 `gaddr` 和 `vmid` 值的 `HFENCE.GVMA` 指令无效的任何地址转换缓存条目无效。
///
///
/// 这个栅栏指定了一个单一的访客物理地址; **物理地址应右移 2 位**。
#[inline]
pub unsafe fn hinval_gvma_gaddr(gaddr: usize) {
    asm!(".insn r 0x73, 0, 0x33, x0, {}, x0", in(reg) gaddr, options(nostack))
}

/// 使给定虚拟机的管理程序转换缓存无效
///
/// 该指令使具有相同 `gaddr` 和 `vmid` 值的 `HFENCE.GVMA` 指令无效的任何地址转换缓存条目无效。
///
///
/// 此栅栏通过虚拟机标识符 (VMID) 指定单个虚拟机。
#[inline]
pub unsafe fn hinval_gvma_vmid(vmid: usize) {
    asm!(".insn r 0x73, 0, 0x33, x0, x0, {}", in(reg) vmid, options(nostack))
}

/// 使所有虚拟机和来宾物理地址的管理程序转换缓存无效
///
/// 该指令使具有相同 `gaddr` 和 `vmid` 值的 `HFENCE.GVMA` 指令无效的任何地址转换缓存条目无效。
///
///
/// 此栅栏指定所有来宾物理地址和所有虚拟机。
#[inline]
pub unsafe fn hinval_gvma_all() {
    asm!(".insn r 0x73, 0, 0x33, x0, x0, x0", options(nostack))
}

/// 读取浮点控制和状态寄存器 `fcsr`
///
/// 寄存器 `fcsr` 是一个 32 位的读写寄存器,它为浮点算术运算选择动态舍入模式并保存应计异常标志。
///
///
/// 根据 "F" Standard Extension for Single-Precision Floating-Point, Version 2.2,寄存器 `fcsr` 定义为:
///
/// | Bit index | Meaning |
/// |:----------|:--------|
/// | 0..=4 | Accrued Exceptions (`fflags`) |
/// | 5..=7 | Rounding Mode (`frm`) |
/// | 8..=31 | _Reserved_ |
///
/// 有关每个字段的定义,请访问 [`frrm`] 和 [`frflags`]。
///
/// [`frrm`]: fn.frrm.html
/// [`frflags`]: fn.frflags.html
///
#[inline]
pub fn frcsr() -> u32 {
    let value: u32;
    unsafe { asm!("frcsr {}", out(reg) value, options(nomem, nostack)) };
    value
}

/// 交换浮点控制和状态寄存器 `fcsr`
///
/// 该函数通过复制要返回的原始值来交换 `fcsr` 中的值,然后将从输入变量 `value` 获得的新值写入 `fcsr`。
///
#[inline]
pub fn fscsr(value: u32) -> u32 {
    let original: u32;
    unsafe { asm!("fscsr {}, {}", out(reg) original, in(reg) value, options(nomem, nostack)) }
    original
}

/// 读取浮点舍入模式的寄存器 `frm`
///
/// 根据 "F" 单精度浮点标准扩展,版本 2.2,舍入模式字段定义如下表所示:
///
///
/// | Rounding Mode | Mnemonic | Meaning |
/// |:-------------|:----------|:---------|
/// | 000 | RNE | Round to Nearest, ties to Even |
/// | 001 | RTZ | Round towards Zero |
/// | 010 | RDN | Round Down (towards −∞) |
/// | 011 | RUP | Round Up (towards +∞) |
/// | 100 | RMM | Round to Nearest, ties to Max Magnitude |
/// | 101 |     | _Reserved for future use._ |
/// | 110 |     | _Reserved for future use._ |
/// | 111 | DYN | In Rounding Mode register, _reserved_. |
#[inline]
pub fn frrm() -> u32 {
    let value: u32;
    unsafe { asm!("frrm {}", out(reg) value, options(nomem, nostack)) };
    value
}

/// 交换浮点舍入模式的寄存器 `frm`
///
/// 该函数通过复制要返回的原始值来交换 `frm` 中的值,然后将从输入变量 `value` 的三个最低有效位获得的新值写入 `frm`。
///
///
#[inline]
pub fn fsrm(value: u32) -> u32 {
    let original: u32;
    unsafe { asm!("fsrm {}, {}", out(reg) original, in(reg) value, options(nomem, nostack)) }
    original
}

/// 读取浮点应计异常标志寄存器 `fflags`
///
/// 累积的异常标志指示自上次由软件复位该字段以来在任何浮点算术指令上出现的异常情况。
///
///
/// 根据 "F" 单精度浮点标准扩展 2.2 版,应计异常标志定义为 5 位的位 vector。
/// 下表列出了每个二进制位的含义。
///
/// | Bit index | Mnemonic | Meaning |
/// |:--|:---|:-----------------|
/// | 4 | NV | Invalid Operation |
/// | 3 | DZ | Divide by Zero |
/// | 2 | OF | Overflow |
/// | 1 | UF | Underflow |
/// | 0 | NX | Inexact |
///
#[inline]
pub fn frflags() -> u32 {
    let value: u32;
    unsafe { asm!("frflags {}", out(reg) value, options(nomem, nostack)) };
    value
}

/// 交换浮点累积异常标志寄存器 `fflags`
///
/// 该函数通过复制要返回的原始值来交换 `fflags` 中的值,然后将从输入变量 `value` 的五个最低有效位获得的新值写入 `fflags`。
///
///
#[inline]
pub fn fsflags(value: u32) -> u32 {
    let original: u32;
    unsafe { asm!("fsflags {}, {}", out(reg) original, in(reg) value, options(nomem, nostack)) }
    original
}

/// SM3 哈希算法中使用的 `P0` 转换函数
///
/// 该函数包含在 `Zksh` 扩展中。它被定义为:
///
/// ```text
/// P0(X) = X ⊕ (X ≪ 9) ⊕ (X ≪ 17)
/// ```
///
/// 其中 `⊕` 表示 32 位异或,`≪ k` 表示左移 `k` 位。
///
/// 在 SM3 算法中,当压缩函数 `CF` 使用中间值 `TT2` 计算变量 `E` 一次迭代时,将 `P0` 转换作为 `E ← P0(TT2)` 用于后续处理。
///
///
/// 根据 RISC-V Cryptography Extensions, Volume I,该指令的执行延迟必须始终独立于它所操作的数据。
///
///
#[inline]
#[target_feature(enable = "zksh")]
pub fn sm3p0(x: u32) -> u32 {
    let ans: u32;
    unsafe { asm!("sm3p0 {}, {}", lateout(reg) ans, in(reg) x, options(pure, nomem, nostack)) };
    ans
}

/// SM3 哈希算法中使用的 `P1` 转换函数
///
/// 该函数包含在 `Zksh` 扩展中。它被定义为:
///
/// ```text
/// P1(X) = X ⊕ (X ≪ 15) ⊕ (X ≪ 23)
/// ```
///
/// 其中 `⊕` 表示 32 位异或,`≪ k` 表示左移 `k` 位。
///
/// 在 SM3 算法中,`P1` 转换用于扩展消息,其中扩展词 `Wj` 可以从前面的词生成。
/// 整个过程可以用下面的伪代码来描述:
///
/// ```text
/// FOR j=16 TO 67
///     Wj ← P1(Wj−16 ⊕ Wj−9 ⊕ (Wj−3 ≪ 15)) ⊕ (Wj−13 ≪ 7) ⊕ Wj−6
/// ENDFOR
/// ```
///
/// 根据 RISC-V Cryptography Extensions, Volume I,该指令的执行延迟必须始终独立于它所操作的数据。
///
///
#[inline]
#[target_feature(enable = "zksh")]
pub fn sm3p1(x: u32) -> u32 {
    let ans: u32;
    unsafe { asm!("sm3p1 {}, {}", lateout(reg) ans, in(reg) x, options(pure, nomem, nostack)) };
    ans
}

/// 加速 SM4 分组密码算法中的舍入函数 `F`
///
/// 该指令包含在扩展 `Zksed` 中。它被定义为:
///
/// ```text
/// SM4ED(x, a, BS) = x ⊕ T(ai)
/// ... where
/// ai = a.bytes[BS]
/// T(ai) = L(τ(ai))
/// bi = τ(ai) = SM4-S-Box(ai)
/// ci = L(bi) = bi ⊕ (bi ≪ 2) ⊕ (bi ≪ 10) ⊕ (bi ≪ 18) ⊕ (bi ≪ 24)
/// SM4ED = (ci ≪ (BS * 8)) ⊕ x
/// ```
///
/// 其中 `⊕` 表示 32 位异或,`≪ k` 表示左移 `k` 位。
/// 如上所述,`T` 是非线性 S-Box 转换 `τ` 和线性层转换 `L` 的组合转换。
///
/// 在 SM4 算法中,舍入函数 `F` 定义为:
///
/// ```text
/// F(x0, x1, x2, x3, rk) = x0 ⊕ T(x1 ⊕ x2 ⊕ x3 ⊕ rk)
/// ... where
/// T(A) = L(τ(A))
/// B = τ(A) = (SM4-S-Box(a0), SM4-S-Box(a1), SM4-S-Box(a2), SM4-S-Box(a3))
/// C = L(B) = B ⊕ (B ≪ 2) ⊕ (B ≪ 10) ⊕ (B ≪ 18) ⊕ (B ≪ 24)
/// ```
///
/// 它可以通过 `sm4ed` 指令来实现,例如:
///
/// ```no_run
/// # #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
/// # fn round_function(x0: u32, x1: u32, x2: u32, x3: u32, rk: u32) -> u32 {
/// # #[cfg(target_arch = "riscv32")] use core::arch::riscv32::sm4ed;
/// # #[cfg(target_arch = "riscv64")] use core::arch::riscv64::sm4ed;
/// let a = x1 ^ x2 ^ x3 ^ rk;
/// let c0 = sm4ed::<0>(x0, a);
/// let c1 = sm4ed::<1>(c0, a); // c1 代表 c[0..=1],等。
/// let c2 = sm4ed::<2>(c1, a);
/// let c3 = sm4ed::<3>(c2, a);
/// return c3; // c3 代表 c[0..=3]
/// # }
/// ```
///
/// 根据 RISC-V Cryptography Extensions, Volume I,该指令的执行延迟必须始终独立于它所操作的数据。
///
///
#[inline]
#[target_feature(enable = "zksed")]
pub fn sm4ed<const BS: u8>(x: u32, a: u32) -> u32 {
    static_assert!(BS <= 3);
    let ans: u32;
    unsafe {
        asm!("sm4ed {}, {}, {}, {}", lateout(reg) ans, in(reg) x, in(reg) a, const BS, options(pure, nomem, nostack))
    };
    ans
}

/// 加速 SM4 分组密码算法中的密钥调度操作
///
/// 该指令包含在扩展 `Zksed` 中。它被定义为:
///
/// ```text
/// SM4KS(x, k, BS) = x ⊕ T'(ki)
/// ... where
/// ki = k.bytes[BS]
/// T'(ki) = L'(τ(ki))
/// bi = τ(ki) = SM4-S-Box(ki)
/// ci = L'(bi) = bi ⊕ (bi ≪ 13) ⊕ (bi ≪ 23)
/// SM4KS = (ci ≪ (BS * 8)) ⊕ x
/// ```
///
/// 其中 `⊕` 表示 32 位异或,`≪ k` 表示左移 `k` 位。
/// 如上所述,`T'` 是非线性 S-Box 转换 `τ` 和替换线性层转换 `L'` 的组合转换。
///
/// 在 SM4 算法中,密钥调度定义为:
///
/// ```text
/// rk[i] = K[i+4] = K[i] ⊕ T'(K[i+1] ⊕ K[i+2] ⊕ K[i+3] ⊕ CK[i])
/// ... where
/// K[0..=3] = MK[0..=3] ⊕ FK[0..=3]
/// T'(K) = L'(τ(K))
/// B = τ(K) = (SM4-S-Box(k0), SM4-S-Box(k1), SM4-S-Box(k2), SM4-S-Box(k3))
/// C = L'(B) = B ⊕ (B ≪ 13) ⊕ (B ≪ 23)
/// ```
///
/// 其中 `MK` 表示 128 位加密密钥,常量 `FK` 和 `CK` 是由 SM4 算法定义的固定系统配置特性值。
///
/// 因此,按键调度操作可以通过 `sm4ks` 指令来实现,例如:
///
/// ```no_run
/// # #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
/// # fn key_schedule(k0: u32, k1: u32, k2: u32, k3: u32, ck_i: u32) -> u32 {
/// # #[cfg(target_arch = "riscv32")] use core::arch::riscv32::sm4ks;
/// # #[cfg(target_arch = "riscv64")] use core::arch::riscv64::sm4ks;
/// let k = k1 ^ k2 ^ k3 ^ ck_i;
/// let c0 = sm4ks::<0>(k0, k);
/// let c1 = sm4ks::<1>(c0, k); // c1 代表 c[0..=1],等。
/// let c2 = sm4ks::<2>(c1, k);
/// let c3 = sm4ks::<3>(c2, k);
/// return c3; // c3 代表 c[0..=3]
/// # }
/// ```
///
/// 根据 RISC-V Cryptography Extensions, Volume I,该指令的执行延迟必须始终独立于它所操作的数据。
///
///
#[inline]
#[target_feature(enable = "zksed")]
pub fn sm4ks<const BS: u8>(x: u32, k: u32) -> u32 {
    static_assert!(BS <= 3);
    let ans: u32;
    unsafe {
        asm!("sm4ks {}, {}, {}, {}", lateout(reg) ans, in(reg) x, in(reg) k, const BS, options(pure, nomem, nostack))
    };
    ans
}