1#![doc = include_str!("../README.md")]
2#![no_std]
3#![deny(missing_docs)]
4
5use core::fmt::{self, Debug, Display};
6use core::ops::RangeInclusive;
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
10pub enum Xlen {
11 Rv32,
13 Rv64,
15}
16
17impl Xlen {
18 pub fn is_32(self) -> bool {
20 matches!(self, Self::Rv32)
21 }
22
23 pub fn is_64(self) -> bool {
25 matches!(self, Self::Rv64)
26 }
27}
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
31pub struct Reg(pub u8);
32
33impl Reg {
34 pub const ZERO: Reg = Reg(0);
36
37 pub const RA: Reg = Reg(1);
39 pub const SP: Reg = Reg(2);
41 pub const GP: Reg = Reg(3);
43 pub const TP: Reg = Reg(4);
45
46 pub const S0: Reg = Reg(8);
48 pub const FP: Reg = Reg(8);
50 pub const S1: Reg = Reg(9);
52 pub const S2: Reg = Reg(18);
54 pub const S3: Reg = Reg(19);
56 pub const S4: Reg = Reg(20);
58 pub const S5: Reg = Reg(21);
60 pub const S6: Reg = Reg(22);
62 pub const S7: Reg = Reg(23);
64 pub const S8: Reg = Reg(24);
66 pub const S9: Reg = Reg(25);
68 pub const S10: Reg = Reg(26);
70 pub const S11: Reg = Reg(27);
72
73 pub const A0: Reg = Reg(10);
75 pub const A1: Reg = Reg(11);
77 pub const A2: Reg = Reg(12);
79 pub const A3: Reg = Reg(13);
81 pub const A4: Reg = Reg(14);
83 pub const A5: Reg = Reg(15);
85 pub const A6: Reg = Reg(16);
87 pub const A7: Reg = Reg(17);
89
90 pub const T0: Reg = Reg(5);
92 pub const T1: Reg = Reg(6);
94 pub const T2: Reg = Reg(7);
96 pub const T3: Reg = Reg(28);
98 pub const T4: Reg = Reg(29);
100 pub const T5: Reg = Reg(30);
102 pub const T6: Reg = Reg(31);
104}
105
106impl Display for Reg {
107 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108 let n = self.0;
109 match n {
110 0 => write!(f, "zero"),
111 1 => write!(f, "ra"),
112 2 => write!(f, "sp"),
113 3 => write!(f, "gp"),
114 4 => write!(f, "tp"),
115 5..=7 => write!(f, "t{}", n - 5),
116 8 => write!(f, "s0"),
117 9 => write!(f, "s1"),
118 10..=17 => write!(f, "a{}", n - 10),
119 18..=27 => write!(f, "s{}", n - 18 + 2),
120 28..=31 => write!(f, "t{}", n - 28 + 3),
121 _ => unreachable!("invalid register"),
122 }
123 }
124}
125
126#[derive(Copy, Clone, PartialEq, Eq, Hash)]
133pub struct Imm(u64);
134
135impl Imm {
136 pub const ZERO: Self = Self::new_u32(0);
139
140 pub const fn new_i32(value: i32) -> Self {
142 Self(value as i64 as u64)
143 }
144
145 pub const fn new_u32(value: u32) -> Self {
147 Self(value as u64)
148 }
149
150 pub const fn as_u32(self) -> u32 {
152 self.0 as u32
153 }
154
155 pub const fn as_i32(self) -> i32 {
157 self.0 as i32
158 }
159
160 pub const fn as_u64(self) -> u64 {
162 self.0 as u64
163 }
164
165 pub const fn as_i64(self) -> i64 {
167 self.0 as i64
168 }
169}
170
171impl From<i32> for Imm {
172 fn from(value: i32) -> Self {
173 Self::new_i32(value)
174 }
175}
176
177impl From<u32> for Imm {
178 fn from(value: u32) -> Self {
179 Self::new_u32(value)
180 }
181}
182
183impl From<Imm> for u32 {
184 fn from(value: Imm) -> Self {
185 value.as_u32()
186 }
187}
188
189impl From<Imm> for i32 {
190 fn from(value: Imm) -> Self {
191 value.as_i32()
192 }
193}
194
195#[derive(Clone, Copy, PartialEq, Eq, Hash)]
203#[rustfmt::skip]
204#[expect(missing_docs)] #[non_exhaustive]
206pub enum Inst {
207 Lui { uimm: Imm, dest: Reg },
209 Auipc { uimm: Imm, dest: Reg },
211
212 Jal { offset: Imm, dest: Reg },
214 Jalr { offset: Imm, base: Reg, dest: Reg },
216
217 Beq { offset: Imm, src1: Reg, src2: Reg },
219 Bne { offset: Imm, src1: Reg, src2: Reg },
221 Blt { offset: Imm, src1: Reg, src2: Reg },
223 Bge { offset: Imm, src1: Reg, src2: Reg },
225 Bltu { offset: Imm, src1: Reg, src2: Reg },
227 Bgeu { offset: Imm, src1: Reg, src2: Reg },
229
230 Lb { offset: Imm, dest: Reg, base: Reg },
232 Lbu { offset: Imm, dest: Reg, base: Reg },
234 Lh { offset: Imm, dest: Reg, base: Reg },
236 Lhu { offset: Imm, dest: Reg, base: Reg },
238 Lw { offset: Imm, dest: Reg, base: Reg },
240 Lwu { offset: Imm, dest: Reg, base: Reg },
242 Ld { offset: Imm, dest: Reg, base: Reg },
244
245
246 Sb { offset: Imm, src: Reg, base: Reg },
248 Sh { offset: Imm, src: Reg, base: Reg },
250 Sw { offset: Imm, src: Reg, base: Reg },
252 Sd { offset: Imm, src: Reg, base: Reg },
254
255 Addi { imm: Imm, dest: Reg, src1: Reg },
257 AddiW { imm: Imm, dest: Reg, src1: Reg },
259 Slti { imm: Imm, dest: Reg, src1: Reg },
261 Sltiu { imm: Imm, dest: Reg, src1: Reg },
263 Xori { imm: Imm, dest: Reg, src1: Reg },
265 Ori { imm: Imm, dest: Reg, src1: Reg },
267 Andi { imm: Imm, dest: Reg, src1: Reg },
269 Slli { imm: Imm, dest: Reg, src1: Reg },
271 SlliW { imm: Imm, dest: Reg, src1: Reg },
273 Srli { imm: Imm, dest: Reg, src1: Reg },
275 SrliW { imm: Imm, dest: Reg, src1: Reg },
277 Srai { imm: Imm, dest: Reg, src1: Reg },
279 SraiW { imm: Imm, dest: Reg, src1: Reg },
281
282 Add { dest: Reg, src1: Reg, src2: Reg },
284 AddW { dest: Reg, src1: Reg, src2: Reg },
286 Sub { dest: Reg, src1: Reg, src2: Reg },
288 SubW { dest: Reg, src1: Reg, src2: Reg },
290 Sll { dest: Reg, src1: Reg, src2: Reg },
292 SllW { dest: Reg, src1: Reg, src2: Reg },
294 Slt { dest: Reg, src1: Reg, src2: Reg },
296 Sltu { dest: Reg, src1: Reg, src2: Reg },
298 Xor { dest: Reg, src1: Reg, src2: Reg },
300 Srl { dest: Reg, src1: Reg, src2: Reg },
302 SrlW { dest: Reg, src1: Reg, src2: Reg },
304 Sra { dest: Reg, src1: Reg, src2: Reg },
306 SraW { dest: Reg, src1: Reg, src2: Reg },
308 Or { dest: Reg, src1: Reg, src2: Reg },
310 And { dest: Reg, src1: Reg, src2: Reg },
312 Fence { fence: Fence },
314
315 Ecall,
317 Ebreak,
319
320 Mul { dest: Reg, src1: Reg, src2: Reg },
323 MulW { dest: Reg, src1: Reg, src2: Reg },
325 Mulh { dest: Reg, src1: Reg, src2: Reg },
327 Mulhsu { dest: Reg, src1: Reg, src2: Reg },
329 Mulhu { dest: Reg, src1: Reg, src2: Reg },
331 Div { dest: Reg, src1: Reg, src2: Reg },
333 DivW { dest: Reg, src1: Reg, src2: Reg },
335 Divu { dest: Reg, src1: Reg, src2: Reg },
337 DivuW { dest: Reg, src1: Reg, src2: Reg },
339 Rem { dest: Reg, src1: Reg, src2: Reg },
341 RemW { dest: Reg, src1: Reg, src2: Reg },
343 Remu { dest: Reg, src1: Reg, src2: Reg },
345 RemuW { dest: Reg, src1: Reg, src2: Reg },
347
348 LrW {
351 order: AmoOrdering,
352 dest: Reg,
353 addr: Reg,
354 },
355 ScW {
357 order: AmoOrdering,
358 dest: Reg,
359 addr: Reg,
360 src: Reg,
361 },
362 AmoW {
364 order: AmoOrdering,
365 op: AmoOp,
366 dest: Reg,
367 addr: Reg,
368 src: Reg,
369 },
370}
371
372#[derive(Clone, Copy, PartialEq, Eq, Hash)]
374pub struct Fence {
375 pub fm: u8,
379 pub pred: FenceSet,
381 pub succ: FenceSet,
383 pub dest: Reg,
385 pub src: Reg,
387}
388
389#[derive(Clone, Copy, PartialEq, Eq, Hash)]
391#[expect(missing_docs)]
392pub struct FenceSet {
393 pub device_input: bool,
394 pub device_output: bool,
395 pub memory_read: bool,
396 pub memory_write: bool,
397}
398
399#[derive(Clone, Copy, PartialEq, Eq, Hash)]
401pub enum AmoOrdering {
402 Relaxed,
404 Acquire,
406 Release,
408 SeqCst,
410}
411
412#[derive(Clone, Copy, PartialEq, Eq, Hash)]
414pub enum AmoOp {
415 Swap,
417 Add,
419 Xor,
421 And,
423 Or,
425 Min,
427 Max,
429 Minu,
431 Maxu,
433}
434
435pub struct DecodeError {
439 pub instruction: u32,
441 pub unexpected_field: &'static str,
443}
444
445impl Fence {
446 pub fn is_tso(&self) -> bool {
449 matches!(
450 self,
451 Self {
452 fm: 0b1000,
453 pred: FenceSet {
454 device_input: _,
455 device_output: _,
456 memory_read: true,
457 memory_write: true
458 },
459 succ: FenceSet {
460 device_input: _,
461 device_output: _,
462 memory_read: true,
463 memory_write: true
464 },
465 ..
466 }
467 )
468 }
469 pub fn is_pause(&self) -> bool {
471 self.pred
472 == FenceSet {
473 device_input: false,
474 device_output: false,
475 memory_read: false,
476 memory_write: true,
477 }
478 && self.succ
479 == FenceSet {
480 device_input: false,
481 device_output: false,
482 memory_read: false,
483 memory_write: false,
484 }
485 && self.dest == Reg::ZERO
486 && self.src == Reg::ZERO
487 }
488}
489
490impl AmoOrdering {
491 pub fn from_aq_rl(aq: bool, rl: bool) -> Self {
493 match (aq, rl) {
494 (false, false) => Self::Relaxed,
495 (true, false) => Self::Acquire,
496 (false, true) => Self::Release,
497 (true, true) => Self::SeqCst,
498 }
499 }
500 pub fn aq_rl(&self) -> (bool, bool) {
502 match self {
503 AmoOrdering::Relaxed => (false, false),
504 AmoOrdering::Acquire => (true, false),
505 AmoOrdering::Release => (false, true),
506 AmoOrdering::SeqCst => (true, true),
507 }
508 }
509}
510
511impl Debug for Inst {
512 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
513 Display::fmt(&self, f)
514 }
515}
516
517impl Display for Inst {
521 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
522 match *self {
523 Inst::Lui { uimm, dest } => write!(f, "lui {dest}, {}", uimm.as_u32() >> 12),
524 Inst::Auipc { uimm, dest } => write!(f, "auipc {dest}, {}", uimm.as_u32() >> 12),
525 Inst::Jal { offset, dest } => {
526 if dest.0 == 0 {
527 write!(f, "j {}", offset.as_i32())
528 } else {
529 write!(f, "jal {dest}, {}", offset.as_i32())
530 }
531 }
532 Inst::Jalr { offset, base, dest } => {
533 if dest == Reg::ZERO && offset.as_u32() == 0 && base == Reg::RA {
534 write!(f, "ret")
535 } else {
536 write!(f, "jalr {dest}, {}({base})", offset.as_i32())
537 }
538 }
539 Inst::Beq { offset, src1, src2 } => {
540 write!(f, "beq {src1}, {src2}, {}", offset.as_i32())
541 }
542 Inst::Bne { offset, src1, src2 } => {
543 write!(f, "bne {src1}, {src2}, {}", offset.as_i32())
544 }
545 Inst::Blt { offset, src1, src2 } => {
546 write!(f, "blt {src1}, {src2}, {}", offset.as_i32())
547 }
548 Inst::Bge { offset, src1, src2 } => {
549 write!(f, "bge {src1}, {src2}, {}", offset.as_i32())
550 }
551 Inst::Bltu { offset, src1, src2 } => {
552 write!(f, "bltu {src1}, {src2}, {}", offset.as_i32())
553 }
554 Inst::Bgeu { offset, src1, src2 } => {
555 write!(f, "bgeu {src1}, {src2}, {}", offset.as_i32())
556 }
557 Inst::Lb { offset, dest, base } => write!(f, "lb {dest}, {}({base})", offset.as_i32()),
558 Inst::Lbu { offset, dest, base } => {
559 write!(f, "lbu {dest}, {}({base})", offset.as_i32())
560 }
561 Inst::Lh { offset, dest, base } => write!(f, "lh {dest}, {}({base})", offset.as_i32()),
562 Inst::Lhu { offset, dest, base } => {
563 write!(f, "lhu {dest}, {}({base})", offset.as_i32())
564 }
565 Inst::Lw { offset, dest, base } => write!(f, "lw {dest}, {}({base})", offset.as_i32()),
566 Inst::Lwu { offset, dest, base } => {
567 write!(f, "lwu {dest}, {}({base})", offset.as_i32())
568 }
569 Inst::Ld { offset, dest, base } => write!(f, "ld {dest}, {}({base})", offset.as_i32()),
570 Inst::Sb { offset, src, base } => write!(f, "sb {src}, {}({base})", offset.as_i32()),
571 Inst::Sh { offset, src, base } => write!(f, "sh {src}, {}({base})", offset.as_i32()),
572 Inst::Sw { offset, src, base } => write!(f, "sw {src}, {}({base})", offset.as_i32()),
573 Inst::Sd { offset, src, base } => write!(f, "sd {src}, {}({base})", offset.as_i32()),
574 Inst::Addi { imm, dest, src1 } => {
575 if dest.0 == 0 && src1.0 == 0 && imm.as_u32() == 0 {
576 write!(f, "nop")
577 } else if src1.0 == 0 {
578 write!(f, "li {dest}, {}", imm.as_i32())
579 } else if imm.as_u32() == 0 {
580 write!(f, "mv {dest}, {src1}")
581 } else {
582 write!(f, "addi {dest}, {src1}, {}", imm.as_i32())
583 }
584 }
585 Inst::AddiW { imm, dest, src1 } => {
586 if imm.as_u32() == 0 {
587 write!(f, "sext.w {dest}, {src1}")
588 } else {
589 write!(f, "addiw {dest}, {src1}, {}", imm.as_i32())
590 }
591 }
592 Inst::Slti {
593 imm,
594 dest,
595 src1: rs1,
596 } => write!(f, "slti {dest}, {rs1}, {}", imm.as_i32()),
597 Inst::Sltiu {
598 imm,
599 dest,
600 src1: rs1,
601 } => write!(f, "sltiu {dest}, {rs1}, {}", imm.as_i32()),
602 Inst::Andi {
603 imm,
604 dest,
605 src1: rs1,
606 } => write!(f, "andi {dest}, {rs1}, {}", imm.as_i32()),
607 Inst::Ori {
608 imm,
609 dest,
610 src1: rs1,
611 } => write!(f, "ori {dest}, {rs1}, {}", imm.as_i32()),
612 Inst::Xori {
613 imm,
614 dest,
615 src1: rs1,
616 } => write!(f, "xori {dest}, {rs1}, {}", imm.as_i32()),
617 Inst::Slli {
618 imm,
619 dest,
620 src1: rs1,
621 } => write!(f, "slli {dest}, {rs1}, {}", imm.as_i32()),
622 Inst::SlliW {
623 imm,
624 dest,
625 src1: rs1,
626 } => write!(f, "slliw {dest}, {rs1}, {}", imm.as_i32()),
627 Inst::Srli {
628 imm,
629 dest,
630 src1: rs1,
631 } => write!(f, "srli {dest}, {rs1}, {}", imm.as_i32()),
632 Inst::SrliW {
633 imm,
634 dest,
635 src1: rs1,
636 } => write!(f, "srliw {dest}, {rs1}, {}", imm.as_i32()),
637 Inst::Srai {
638 imm,
639 dest,
640 src1: rs1,
641 } => write!(f, "srai {dest}, {rs1}, {}", imm.as_i32()),
642 Inst::SraiW {
643 imm,
644 dest,
645 src1: rs1,
646 } => write!(f, "sraiw {dest}, {rs1}, {}", imm.as_i32()),
647 Inst::Add { dest, src1, src2 } => {
648 write!(f, "add {dest}, {src1}, {src2}")
649 }
650 Inst::AddW { dest, src1, src2 } => {
651 write!(f, "addw {dest}, {src1}, {src2}")
652 }
653 Inst::Sub { dest, src1, src2 } => write!(f, "sub {dest}, {src1}, {src2}"),
654 Inst::SubW { dest, src1, src2 } => write!(f, "subw {dest}, {src1}, {src2}"),
655 Inst::Sll { dest, src1, src2 } => write!(f, "sll {dest}, {src1}, {src2}"),
656 Inst::SllW { dest, src1, src2 } => write!(f, "sllw {dest}, {src1}, {src2}"),
657 Inst::Slt { dest, src1, src2 } => write!(f, "slt {dest}, {src1}, {src2}"),
658 Inst::Sltu { dest, src1, src2 } => write!(f, "sltu {dest}, {src1}, {src2}"),
659 Inst::Xor { dest, src1, src2 } => write!(f, "xor {dest}, {src1}, {src2}"),
660 Inst::Srl { dest, src1, src2 } => write!(f, "srl {dest}, {src1}, {src2}"),
661 Inst::SrlW { dest, src1, src2 } => write!(f, "srlw {dest}, {src1}, {src2}"),
662 Inst::Sra { dest, src1, src2 } => write!(f, "sra {dest}, {src1}, {src2}"),
663 Inst::SraW { dest, src1, src2 } => write!(f, "sraw {dest}, {src1}, {src2}"),
664 Inst::Or { dest, src1, src2 } => write!(f, "or {dest}, {src1}, {src2}"),
665 Inst::And { dest, src1, src2 } => write!(f, "and {dest}, {src1}, {src2}"),
666 Inst::Fence { fence } => match fence.fm {
667 _ if fence.is_tso() => write!(f, "fence.tso"),
668 0b0000 if fence.is_pause() => {
669 write!(f, "pause")
670 }
671 _ => write!(f, "fence {},{}", fence.pred, fence.succ),
672 },
673 Inst::Ecall => write!(f, "ecall"),
674 Inst::Ebreak => write!(f, "ebreak"),
675 Inst::Mul { dest, src1, src2 } => write!(f, "mul {dest}, {src1}, {src2}"),
676 Inst::MulW { dest, src1, src2 } => write!(f, "mulw {dest}, {src1}, {src2}"),
677 Inst::Mulh { dest, src1, src2 } => write!(f, "mulh {dest}, {src1}, {src2}"),
678 Inst::Mulhsu { dest, src1, src2 } => write!(f, "mulhsu {dest}, {src1}, {src2}"),
679 Inst::Mulhu { dest, src1, src2 } => write!(f, "mulhu {dest}, {src1}, {src2}"),
680 Inst::Div { dest, src1, src2 } => write!(f, "div {dest}, {src1}, {src2}"),
681 Inst::DivW { dest, src1, src2 } => write!(f, "divw {dest}, {src1}, {src2}"),
682 Inst::Divu { dest, src1, src2 } => write!(f, "divu {dest}, {src1}, {src2}"),
683 Inst::DivuW { dest, src1, src2 } => write!(f, "divuw {dest}, {src1}, {src2}"),
684 Inst::Rem { dest, src1, src2 } => write!(f, "rem {dest}, {src1}, {src2}"),
685 Inst::RemW { dest, src1, src2 } => write!(f, "remw {dest}, {src1}, {src2}"),
686 Inst::Remu { dest, src1, src2 } => write!(f, "remu {dest}, {src1}, {src2}"),
687 Inst::RemuW { dest, src1, src2 } => write!(f, "remuw {dest}, {src1}, {src2}"),
688 Inst::LrW { order, dest, addr } => write!(f, "lr.w{order} {dest}, ({addr})",),
689 Inst::ScW {
690 order,
691 dest,
692 addr,
693 src,
694 } => write!(f, "sc.w{order} {dest}, {src}, ({addr})"),
695 Inst::AmoW {
696 order,
697 op,
698 dest,
699 addr,
700 src,
701 } => write!(f, "amo{op}.w{order} {dest}, {src}, ({addr})",),
702 }
703 }
704}
705
706impl Display for FenceSet {
707 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
708 let mut has = false;
709 if self.device_input {
710 has = true;
711 write!(f, "i")?;
712 }
713 if self.device_output {
714 has = true;
715 write!(f, "o")?;
716 }
717 if self.memory_read {
718 has = true;
719 write!(f, "r")?;
720 }
721 if self.memory_write {
722 has = true;
723 write!(f, "w")?;
724 }
725 if !has {
726 write!(f, "0")?;
727 }
728 Ok(())
729 }
730}
731
732impl Display for AmoOrdering {
733 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
734 match self {
735 AmoOrdering::Relaxed => write!(f, ""),
736 AmoOrdering::Acquire => write!(f, ".aq"),
737 AmoOrdering::Release => write!(f, ".rl"),
738 AmoOrdering::SeqCst => write!(f, ".aqrl"),
739 }
740 }
741}
742
743impl Display for AmoOp {
744 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
745 match self {
746 AmoOp::Swap => write!(f, "swap"),
747 AmoOp::Add => write!(f, "add"),
748 AmoOp::Xor => write!(f, "xor"),
749 AmoOp::And => write!(f, "and"),
750 AmoOp::Or => write!(f, "or"),
751 AmoOp::Min => write!(f, "min"),
752 AmoOp::Max => write!(f, "max"),
753 AmoOp::Minu => write!(f, "minu"),
754 AmoOp::Maxu => write!(f, "maxu"),
755 }
756 }
757}
758
759impl Debug for DecodeError {
760 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
761 f.debug_struct("DecodeError")
762 .field("instruction", &format_args!("{:0>32b}", self.instruction))
763 .field("unexpected_field", &self.unexpected_field)
764 .finish()
765 }
766}
767
768impl Display for DecodeError {
769 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
770 write!(
771 f,
772 "failed to decode instruction '{:0>32b}' because of field '{}'",
773 self.instruction, self.unexpected_field
774 )
775 }
776}
777
778impl core::error::Error for DecodeError {}
779
780fn sign_extend(value: u32, size: u32) -> u32 {
781 let right = u32::BITS - size;
782 (((value << right) as i32) >> right) as u32
783}
784
785#[derive(Clone, Copy)]
786struct InstCode(u32);
787
788impl InstCode {
789 fn extract(self, range: RangeInclusive<u32>) -> u32 {
790 let end_span = 32 - (range.end() + 1);
791 (self.0 << (end_span)) >> (end_span + range.start())
792 }
793 fn insert(self, range: RangeInclusive<u32>, data: u32) -> Self {
794 let (start,end) = (*range.start(),*range.end());
795 let span_item = (1 << (end - start + 1)) - 1;
797 Self(self.0 & !(span_item << start) | ((data & span_item) << start))
798 }
799 fn immediate_s(self, mappings: &[(RangeInclusive<u32>, u32)]) -> Imm {
800 let mut imm = 0;
801 let mut size = 0;
802 for (from, to) in mappings {
803 let value = self.extract(from.clone());
804 imm |= value << to;
805 let this_size = from.end() - from.start() + 1;
806 size = size.max(*to + this_size);
807 }
808 Imm::new_i32(sign_extend(imm, size) as i32)
809 }
810 fn with_immediate_s(self, mappings: &[(RangeInclusive<u32>, u32)], data: Imm) -> Self {
811 let mut size = 0;
812 for (from, to) in mappings {
813 let this_size = from.end() - from.start() + 1;
814 size = size.max(*to + this_size);
815 }
816 mappings.iter().fold(self, |this, (from, to)| {
817 this.insert(
818 from.clone(),
819 data.as_u32() >> *to,
820 )
821 })
822 }
823
824 fn opcode(self) -> u32 {
825 self.0 & 0b1111111
826 }
827 fn with_opcode(self, opcode: u32) -> Self {
828 let mask = 0b1111111;
829 Self(self.0 & !mask | (opcode & mask))
830 }
831 fn funct3(self) -> u32 {
832 self.extract(12..=14)
833 }
834 fn funct7(self) -> u32 {
835 self.extract(25..=31)
836 }
837 fn with_funct3(self, data: u32) -> Self {
838 self.insert(12..=14, data)
839 }
840 fn with_funct7(self, data: u32) -> Self {
841 self.insert(25..=31, data)
842 }
843 fn rs1(self) -> Reg {
844 Reg(self.extract(15..=19) as u8)
845 }
846 fn rs2(self) -> Reg {
847 Reg(self.extract(20..=24) as u8)
848 }
849 fn with_rs1(self, data: Reg) -> Self {
850 self.insert(15..=19, data.0 as u32)
851 }
852 fn with_rs2(self, data: Reg) -> Self {
853 self.insert(20..=24, data.0 as u32)
854 }
855 fn rs2_imm(self) -> u32 {
856 self.extract(20..=24)
857 }
858 fn rs2_imm_plus(self) -> u32 {
860 self.extract(20..=25)
861 }
862 fn with_rs2_imm(self, data: u32) -> Self {
863 self.insert(20..=24, data)
864 }
865 fn with_rs2_imm_plus(self, data: u32) -> Self {
867 self.insert(20..=25, data)
868 }
869 fn rd(self) -> Reg {
870 Reg(self.extract(7..=11) as u8)
871 }
872 fn with_rd(self, data: Reg) -> Self {
873 self.insert(7..=11, data.0 as u32)
874 }
875 fn imm_i(self) -> Imm {
876 self.immediate_s(&[(20..=31, 0)])
877 }
878 fn imm_s(self) -> Imm {
879 self.immediate_s(&[(25..=31, 5), (7..=11, 0)])
880 }
881 fn imm_b(self) -> Imm {
882 self.immediate_s(&[(31..=31, 12), (7..=7, 11), (25..=30, 5), (8..=11, 1)])
883 }
884 fn imm_u(self) -> Imm {
885 self.immediate_s(&[(12..=31, 12)])
887 }
888 fn imm_j(self) -> Imm {
889 self.immediate_s(&[(31..=31, 20), (21..=30, 1), (20..=20, 11), (12..=19, 12)])
890 }
891 fn with_imm_i(self, data: Imm) -> Self {
892 self.with_immediate_s(&[(20..=31, 0)], data)
893 }
894 fn with_imm_s(self, data: Imm) -> Self {
895 self.with_immediate_s(&[(25..=31, 5), (7..=11, 0)], data)
896 }
897 fn with_imm_b(self, data: Imm) -> Self {
898 self.with_immediate_s(
899 &[(31..=31, 12), (7..=7, 11), (25..=30, 5), (8..=11, 1)],
900 data,
901 )
902 }
903 fn with_imm_u(self, data: Imm) -> Self {
904 self.with_immediate_s(&[(12..=31, 12)], data)
906 }
907 fn with_imm_j(self, data: Imm) -> Self {
908 self.with_immediate_s(
909 &[(31..=31, 20), (21..=30, 1), (20..=20, 11), (12..=19, 12)],
910 data,
911 )
912 }
913}
914
915#[derive(Clone, Copy)]
916struct InstCodeC(u16);
917
918impl InstCodeC {
919 fn extract(self, range: RangeInclusive<u32>) -> u32 {
920 let end_span = u16::BITS - (range.end() + 1);
921 ((self.0 << (end_span)) >> (end_span + range.start())) as u32
922 }
923 fn immediate_u(self, mappings: &[(RangeInclusive<u32>, u32)]) -> Imm {
924 let mut imm = 0;
925 for (from, to) in mappings {
926 let value = self.extract(from.clone());
927 imm |= value << to;
928 }
929 Imm::new_u32(imm)
930 }
931 fn immediate_s(self, mappings: &[(RangeInclusive<u32>, u32)]) -> Imm {
932 let mut imm = 0;
933 let mut size = 0;
934 for (from, to) in mappings {
935 assert!(from.start() <= from.end());
936 let value = self.extract(from.clone());
937 imm |= value << to;
938 let this_size = from.end() - from.start() + 1;
939 size = size.max(*to + this_size);
940 }
941 Imm::new_i32(sign_extend(imm, size) as i32)
942 }
943 fn quadrant(self) -> u16 {
944 self.0 & 0b11
945 }
946 fn funct3(self) -> u32 {
947 self.extract(13..=15)
948 }
949 fn funct2(self) -> u32 {
950 self.extract(10..=11)
951 }
952 fn rd(self) -> Reg {
954 Reg(self.extract(7..=11) as u8)
955 }
956 fn rs2(self) -> Reg {
958 Reg(self.extract(2..=6) as u8)
959 }
960 fn rs1_short(self) -> Reg {
962 let smol_reg = self.extract(7..=9);
963 Reg((smol_reg + 8) as u8)
965 }
966 fn rs2_short(self) -> Reg {
968 let smol_reg = self.extract(2..=4);
969 Reg((smol_reg + 8) as u8)
971 }
972}
973
974impl From<InstCodeC> for InstCode {
975 fn from(value: InstCodeC) -> Self {
976 Self(value.0 as u32)
977 }
978}
979
980#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
984pub enum IsCompressed {
985 No,
987 Yes,
989}
990
991fn decode_error(instruction: impl Into<InstCode>, unexpected_field: &'static str) -> DecodeError {
992 DecodeError {
993 instruction: instruction.into().0,
994 unexpected_field,
995 }
996}
997
998impl Inst {
999 pub fn first_byte_is_compressed(byte: u8) -> bool {
1017 (byte & 0b11) != 0b11
1018 }
1019
1020 pub fn decode(code: u32, xlen: Xlen) -> Result<(Inst, IsCompressed), DecodeError> {
1029 let is_compressed = (code & 0b11) != 0b11;
1030 if is_compressed {
1031 Ok((
1032 Self::decode_compressed(code as u16, xlen)?,
1033 IsCompressed::Yes,
1034 ))
1035 } else {
1036 Ok((Self::decode_normal(code, xlen)?, IsCompressed::No))
1037 }
1038 }
1039
1040 pub fn decode_compressed(code: u16, xlen: Xlen) -> Result<Inst, DecodeError> {
1052 let code = InstCodeC(code);
1053 if code.0 == 0 {
1054 return Err(decode_error(code, "null instruction"));
1055 }
1056 let inst = match code.quadrant() {
1057 0b00 => match code.funct3() {
1059 0b000 => {
1061 let imm =
1062 code.immediate_u(&[(5..=5, 3), (6..=6, 2), (7..=10, 6), (11..=12, 4)]);
1063 if imm.as_u32() == 0 {
1064 return Err(decode_error(code, "uimm=0 for C.ADDISPN is reserved"));
1065 }
1066 Inst::Addi {
1067 imm,
1068 dest: code.rs2_short(),
1069 src1: Reg::SP,
1070 }
1071 }
1072 0b010 => Inst::Lw {
1074 offset: code.immediate_u(&[(10..=12, 3), (5..=5, 6), (6..=6, 2)]),
1075 dest: code.rs2_short(),
1076 base: code.rs1_short(),
1077 },
1078 0b110 => Inst::Sw {
1080 offset: code.immediate_u(&[(10..=12, 3), (5..=5, 6), (6..=6, 2)]),
1081 src: code.rs2_short(),
1082 base: code.rs1_short(),
1083 },
1084 _ => return Err(decode_error(code, "C0 funct3")),
1085 },
1086 0b01 => match code.funct3() {
1088 0b000 => Inst::Addi {
1090 imm: code.immediate_s(&[(2..=6, 0), (12..=12, 5)]),
1091 dest: code.rd(),
1092 src1: code.rd(),
1093 },
1094 0b001 => Inst::Jal {
1096 offset: code.immediate_s(&[
1097 (2..=2, 5),
1098 (3..=5, 1),
1099 (6..=6, 7),
1100 (7..=7, 6),
1101 (8..=8, 10),
1102 (9..=10, 8),
1103 (11..=11, 4),
1104 (12..=12, 11),
1105 ]),
1106 dest: Reg::RA,
1107 },
1108 0b010 => Inst::Addi {
1110 imm: code.immediate_s(&[(2..=6, 0), (12..=12, 5)]),
1111 dest: code.rd(),
1112 src1: Reg::ZERO,
1113 },
1114 0b100 => {
1116 let bit12 = code.extract(12..=12);
1117 match code.funct2() {
1118 0b00 => {
1120 if bit12 != 0 {
1121 return Err(decode_error(code, "C.SRLI imm"));
1122 }
1123
1124 Inst::Srli {
1125 imm: code.immediate_u(&[(2..=6, 0), (12..=12, 5)]),
1126 dest: code.rs1_short(),
1127 src1: code.rs1_short(),
1128 }
1129 }
1130 0b01 => {
1132 if bit12 != 0 {
1133 return Err(decode_error(code, "C.SRLI imm"));
1134 }
1135
1136 Inst::Srai {
1137 imm: code.immediate_u(&[(2..=6, 0), (12..=12, 5)]),
1138 dest: code.rs1_short(),
1139 src1: code.rs1_short(),
1140 }
1141 }
1142 0b10 => Inst::Andi {
1144 imm: code.immediate_u(&[(2..=6, 0), (12..=12, 5)]),
1145 dest: code.rs1_short(),
1146 src1: code.rs1_short(),
1147 },
1148 0b11 => {
1149 if bit12 != 0 {
1150 return Err(decode_error(code, "C1 Arith bit 12"));
1151 }
1152 let funct2 = code.extract(5..=6);
1153 match funct2 {
1154 0b00 => Inst::Sub {
1156 dest: code.rs1_short(),
1157 src1: code.rs1_short(),
1158 src2: code.rs2_short(),
1159 },
1160 0b01 => Inst::Xor {
1162 dest: code.rs1_short(),
1163 src1: code.rs1_short(),
1164 src2: code.rs2_short(),
1165 },
1166 0b10 => Inst::Or {
1168 dest: code.rs1_short(),
1169 src1: code.rs1_short(),
1170 src2: code.rs2_short(),
1171 },
1172 0b11 => Inst::And {
1174 dest: code.rs1_short(),
1175 src1: code.rs1_short(),
1176 src2: code.rs2_short(),
1177 },
1178 _ => unreachable!("only two bits"),
1179 }
1180 }
1181 _ => unreachable!("only two bits"),
1182 }
1183 }
1184 0b101 => Inst::Jal {
1186 offset: code.immediate_s(&[
1187 (2..=2, 5),
1188 (3..=5, 1),
1189 (6..=6, 7),
1190 (7..=7, 6),
1191 (8..=8, 10),
1192 (9..=10, 8),
1193 (11..=11, 4),
1194 (12..=12, 11),
1195 ]),
1196 dest: Reg::ZERO,
1197 },
1198 0b011 => {
1199 match code.rd().0 {
1200 2 => Inst::Addi {
1202 imm: code.immediate_s(&[
1203 (2..=2, 5),
1204 (3..=4, 7),
1205 (5..=5, 6),
1206 (6..=6, 4),
1207 (12..=12, 9),
1208 ]),
1209 dest: Reg::SP,
1210 src1: Reg::SP,
1211 },
1212 _ => {
1214 let uimm = code.immediate_s(&[(2..=6, 12), (12..=12, 17)]);
1215 if uimm.as_u32() == 0 {
1216 return Err(decode_error(code, "C.LUI zero immediate"));
1217 }
1218 Inst::Lui {
1219 uimm,
1220 dest: code.rd(),
1221 }
1222 }
1223 }
1224 }
1225 0b110 => Inst::Beq {
1227 offset: code.immediate_s(&[
1228 (2..=2, 5),
1229 (3..=4, 1),
1230 (5..=6, 6),
1231 (10..=11, 3),
1232 (12..=12, 8),
1233 ]),
1234 src1: code.rs1_short(),
1235 src2: Reg::ZERO,
1236 },
1237 0b111 => Inst::Bne {
1239 offset: code.immediate_s(&[
1240 (2..=2, 5),
1241 (3..=4, 1),
1242 (5..=6, 6),
1243 (10..=11, 3),
1244 (12..=12, 8),
1245 ]),
1246 src1: code.rs1_short(),
1247 src2: Reg::ZERO,
1248 },
1249 _ => return Err(decode_error(code, "C1 funct3")),
1250 },
1251 0b10 => match code.funct3() {
1253 0b000 => {
1255 if code.extract(12..=12) != 0 {
1256 return Err(decode_error(code, "C.SLLI shift amount must be zero"));
1257 }
1258 Inst::Slli {
1259 imm: code.immediate_u(&[(2..=6, 0), (12..=12, 5)]),
1260 dest: code.rd(),
1261 src1: code.rd(),
1262 }
1263 }
1264 0b010 => {
1266 let dest = code.rd();
1267 if dest.0 == 0 {
1268 return Err(decode_error(code, "C.LWSP rd must not be zero"));
1269 }
1270
1271 Inst::Lw {
1272 offset: code.immediate_u(&[(12..=12, 5), (4..=6, 2), (2..=3, 6)]),
1273 dest,
1274 base: Reg::SP,
1275 }
1276 }
1277
1278 0b011 => {
1280 if xlen.is_32() {
1281 return Err(decode_error(code, "C.LDSP is not allowed on RV32"));
1282 }
1283 let dest = code.rd();
1284 if dest.0 == 0 {
1285 return Err(decode_error(code, "C.LWSP rd must not be zero"));
1286 }
1287
1288 Inst::Ld {
1289 offset: code.immediate_u(&[(12..=12, 5), (4..=6, 2), (2..=3, 6)]),
1290 dest,
1291 base: Reg::SP,
1292 }
1293 }
1294 0b100 => {
1295 let bit = code.extract(12..=12);
1296 let rs2 = code.rs2();
1297 let rd_rs1 = code.rd();
1298 match (bit, rd_rs1.0, rs2.0) {
1299 (0, _, 0) => {
1301 if rd_rs1.0 == 0 {
1302 return Err(decode_error(code, "C.JR rs1 must not be zero"));
1303 }
1304 Inst::Jalr {
1305 offset: Imm::ZERO,
1306 base: rd_rs1,
1307 dest: Reg::ZERO,
1308 }
1309 }
1310 (0, _, _) => Inst::Add {
1312 dest: code.rd(),
1313 src1: Reg::ZERO,
1314 src2: code.rs2(),
1315 },
1316 (1, 0, 0) => Inst::Ebreak,
1318 (1, _, 0) if rd_rs1.0 != 0 => Inst::Jalr {
1320 offset: Imm::ZERO,
1321 base: rd_rs1,
1322 dest: Reg::RA,
1323 },
1324 (1, _, _) => Inst::Add {
1326 dest: rd_rs1,
1327 src1: rd_rs1,
1328 src2: rs2,
1329 },
1330 _ => return Err(decode_error(code, "C2 funct=100 inst")),
1331 }
1332 }
1333 0b110 => Inst::Sw {
1335 offset: code.immediate_u(&[(7..=8, 6), (9..=12, 2)]),
1336 src: code.rs2(),
1337 base: Reg::SP,
1338 },
1339 0b111 => {
1341 if xlen.is_32() {
1342 return Err(decode_error(code, "C.SDSP is not allowed on RV32"));
1343 }
1344 Inst::Sd {
1345 offset: code.immediate_u(&[(7..=9, 6), (10..=12, 3)]),
1346 src: code.rs2(),
1347 base: Reg::SP,
1348 }
1349 }
1350 _ => return Err(decode_error(code, "C2 funct3")),
1351 },
1352 _ => return Err(decode_error(code, "instruction is not compressed")),
1353 };
1354 Ok(inst)
1355 }
1356
1357 pub fn decode_normal(code: u32, xlen: Xlen) -> Result<Inst, DecodeError> {
1359 let code = InstCode(code);
1360 let inst = match code.opcode() {
1361 0b0110111 => Inst::Lui {
1363 uimm: code.imm_u(),
1364 dest: code.rd(),
1365 },
1366 0b0010111 => Inst::Auipc {
1368 uimm: code.imm_u(),
1369 dest: code.rd(),
1370 },
1371 0b1101111 => Inst::Jal {
1373 offset: code.imm_j(),
1374 dest: code.rd(),
1375 },
1376 0b1100111 => match code.funct3() {
1378 0b000 => Inst::Jalr {
1379 offset: code.imm_i(),
1380 base: code.rs1(),
1381 dest: code.rd(),
1382 },
1383 _ => return Err(decode_error(code, "JALR funct3")),
1384 },
1385 0b1100011 => match code.funct3() {
1387 0b000 => Inst::Beq {
1388 offset: code.imm_b(),
1389 src1: code.rs1(),
1390 src2: code.rs2(),
1391 },
1392 0b001 => Inst::Bne {
1393 offset: code.imm_b(),
1394 src1: code.rs1(),
1395 src2: code.rs2(),
1396 },
1397 0b100 => Inst::Blt {
1398 offset: code.imm_b(),
1399 src1: code.rs1(),
1400 src2: code.rs2(),
1401 },
1402 0b101 => Inst::Bge {
1403 offset: code.imm_b(),
1404 src1: code.rs1(),
1405 src2: code.rs2(),
1406 },
1407 0b110 => Inst::Bltu {
1408 offset: code.imm_b(),
1409 src1: code.rs1(),
1410 src2: code.rs2(),
1411 },
1412 0b111 => Inst::Bgeu {
1413 offset: code.imm_b(),
1414 src1: code.rs1(),
1415 src2: code.rs2(),
1416 },
1417 _ => return Err(decode_error(code, "BRANCH funct3")),
1418 },
1419 0b0000011 => match code.funct3() {
1421 0b000 => Inst::Lb {
1422 offset: code.imm_i(),
1423 dest: code.rd(),
1424 base: code.rs1(),
1425 },
1426 0b001 => Inst::Lh {
1427 offset: code.imm_i(),
1428 dest: code.rd(),
1429 base: code.rs1(),
1430 },
1431 0b010 => Inst::Lw {
1432 offset: code.imm_i(),
1433 dest: code.rd(),
1434 base: code.rs1(),
1435 },
1436 0b011 => {
1437 if xlen.is_32() {
1438 return Err(decode_error(code, "LD is not supported on RV32"));
1439 }
1440 Inst::Ld {
1441 offset: code.imm_i(),
1442 dest: code.rd(),
1443 base: code.rs1(),
1444 }
1445 }
1446 0b100 => Inst::Lbu {
1447 offset: code.imm_i(),
1448 dest: code.rd(),
1449 base: code.rs1(),
1450 },
1451 0b101 => Inst::Lhu {
1452 offset: code.imm_i(),
1453 dest: code.rd(),
1454 base: code.rs1(),
1455 },
1456 0b110 => {
1457 if xlen.is_32() {
1458 return Err(decode_error(code, "LWU is not supported on RV32"));
1459 }
1460 Inst::Lwu {
1461 offset: code.imm_i(),
1462 dest: code.rd(),
1463 base: code.rs1(),
1464 }
1465 }
1466 _ => return Err(decode_error(code, "Invalid funct3 for LOAD instruction")),
1467 },
1468 0b0100011 => match code.funct3() {
1470 0b000 => Inst::Sb {
1471 offset: code.imm_s(),
1472 src: code.rs2(),
1473 base: code.rs1(),
1474 },
1475 0b001 => Inst::Sh {
1476 offset: code.imm_s(),
1477 src: code.rs2(),
1478 base: code.rs1(),
1479 },
1480 0b010 => Inst::Sw {
1481 offset: code.imm_s(),
1482 src: code.rs2(),
1483 base: code.rs1(),
1484 },
1485 0b011 => {
1486 if xlen.is_32() {
1487 return Err(decode_error(code, "SD is not supported on RV32"));
1488 }
1489 Inst::Sd {
1490 offset: code.imm_s(),
1491 src: code.rs2(),
1492 base: code.rs1(),
1493 }
1494 }
1495 _ => return Err(decode_error(code, "STORE funct3")),
1496 },
1497 0b0010011 => match code.funct3() {
1499 0b000 => Inst::Addi {
1500 imm: code.imm_i(),
1501 dest: code.rd(),
1502 src1: code.rs1(),
1503 },
1504 0b010 => Inst::Slti {
1505 imm: code.imm_i(),
1506 dest: code.rd(),
1507 src1: code.rs1(),
1508 },
1509 0b011 => Inst::Sltiu {
1510 imm: code.imm_i(),
1511 dest: code.rd(),
1512 src1: code.rs1(),
1513 },
1514 0b100 => Inst::Xori {
1515 imm: code.imm_i(),
1516 dest: code.rd(),
1517 src1: code.rs1(),
1518 },
1519 0b110 => Inst::Ori {
1520 imm: code.imm_i(),
1521 dest: code.rd(),
1522 src1: code.rs1(),
1523 },
1524 0b111 => Inst::Andi {
1525 imm: code.imm_i(),
1526 dest: code.rd(),
1527 src1: code.rs1(),
1528 },
1529 0b001 => {
1530 let left_zeroes = code.funct7()
1532 >> match xlen {
1533 Xlen::Rv32 => 0,
1534 Xlen::Rv64 => 1,
1535 };
1536 if left_zeroes != 0 {
1537 return Err(decode_error(code, "slli shift overflow"));
1538 }
1539 Inst::Slli {
1540 imm: code.imm_i(),
1541 dest: code.rd(),
1542 src1: code.rs1(),
1543 }
1544 }
1545 0b101 => match xlen {
1546 Xlen::Rv32 => match code.funct7() {
1547 0b0000000 => Inst::Srli {
1548 imm: Imm::new_u32(code.rs2_imm()),
1549 dest: code.rd(),
1550 src1: code.rs1(),
1551 },
1552 0b0100000 => Inst::Srai {
1553 imm: Imm::new_u32(code.rs2_imm()),
1554 dest: code.rd(),
1555 src1: code.rs1(),
1556 },
1557 _ => return Err(decode_error(code, "srli shift overflow")),
1558 },
1559 Xlen::Rv64 => {
1560 let upper = code.funct7() >> 1;
1561 match upper {
1562 0b010000 => Inst::Srai {
1563 imm: Imm::new_u32(code.rs2_imm_plus()),
1564 dest: code.rd(),
1565 src1: code.rs1(),
1566 },
1567 0b000000 => Inst::Srli {
1568 imm: Imm::new_u32(code.rs2_imm_plus()),
1569 dest: code.rd(),
1570 src1: code.rs1(),
1571 },
1572 _ => return Err(decode_error(code, "srai/srli upper bits")),
1573 }
1574 }
1575 },
1576 _ => return Err(decode_error(code, "OP-IMM funct3")),
1577 },
1578 0b0011011 => {
1580 if xlen.is_32() {
1581 return Err(decode_error(code, "OP-IMM-32 only on RV64"));
1582 }
1583
1584 match code.funct3() {
1585 0b000 => Inst::AddiW {
1586 imm: code.imm_i(),
1587 dest: code.rd(),
1588 src1: code.rs1(),
1589 },
1590 0b001 => {
1592 if code.funct7() != 0 {
1593 return Err(decode_error(code, "SLLIW funct7"));
1594 }
1595
1596 Inst::SlliW {
1597 imm: Imm::new_u32(code.rs2_imm()),
1598 dest: code.rd(),
1599 src1: code.rs1(),
1600 }
1601 }
1602
1603 0b101 => match code.funct7() {
1604 0b0000000 => Inst::SrliW {
1605 imm: Imm::new_u32(code.rs2_imm()),
1606 dest: code.rd(),
1607 src1: code.rs1(),
1608 },
1609 0b0100000 => Inst::SraiW {
1610 imm: Imm::new_u32(code.rs2_imm()),
1611 dest: code.rd(),
1612 src1: code.rs1(),
1613 },
1614 _ => return Err(decode_error(code, "OP-IMM-32 funct7")),
1615 },
1616 _ => return Err(decode_error(code, "OP-IMM-32 funct3")),
1617 }
1618 }
1619 0b0110011 => {
1621 let (dest, src1, src2) = (code.rd(), code.rs1(), code.rs2());
1622 match (code.funct3(), code.funct7()) {
1623 (0b000, 0b0000000) => Inst::Add { dest, src1, src2 },
1624 (0b000, 0b0100000) => Inst::Sub { dest, src1, src2 },
1625 (0b001, 0b0000000) => Inst::Sll { dest, src1, src2 },
1626 (0b010, 0b0000000) => Inst::Slt { dest, src1, src2 },
1627 (0b011, 0b0000000) => Inst::Sltu { dest, src1, src2 },
1628 (0b100, 0b0000000) => Inst::Xor { dest, src1, src2 },
1629 (0b101, 0b0000000) => Inst::Srl { dest, src1, src2 },
1630 (0b101, 0b0100000) => Inst::Sra { dest, src1, src2 },
1631 (0b110, 0b0000000) => Inst::Or { dest, src1, src2 },
1632 (0b111, 0b0000000) => Inst::And { dest, src1, src2 },
1633
1634 (0b000, 0b0000001) => Inst::Mul { dest, src1, src2 },
1635 (0b001, 0b0000001) => Inst::Mulh { dest, src1, src2 },
1636 (0b010, 0b0000001) => Inst::Mulhsu { dest, src1, src2 },
1637 (0b011, 0b0000001) => Inst::Mulhu { dest, src1, src2 },
1638 (0b100, 0b0000001) => Inst::Div { dest, src1, src2 },
1639 (0b101, 0b0000001) => Inst::Divu { dest, src1, src2 },
1640 (0b110, 0b0000001) => Inst::Rem { dest, src1, src2 },
1641 (0b111, 0b0000001) => Inst::Remu { dest, src1, src2 },
1642 _ => return Err(decode_error(code, "OP funct3/funct7")),
1643 }
1644 }
1645 0b0111011 => {
1647 if xlen.is_32() {
1648 return Err(decode_error(code, "OP-IMM-32 only on RV64"));
1649 }
1650
1651 let (dest, src1, src2) = (code.rd(), code.rs1(), code.rs2());
1652 match (code.funct3(), code.funct7()) {
1653 (0b000, 0b0000000) => Inst::AddW { dest, src1, src2 },
1654 (0b000, 0b0100000) => Inst::SubW { dest, src1, src2 },
1655 (0b001, 0b0000000) => Inst::SllW { dest, src1, src2 },
1656 (0b101, 0b0000000) => Inst::SrlW { dest, src1, src2 },
1657 (0b101, 0b0100000) => Inst::SraW { dest, src1, src2 },
1658
1659 (0b000, 0b0000001) => Inst::MulW { dest, src1, src2 },
1660 (0b100, 0b0000001) => Inst::DivW { dest, src1, src2 },
1661 (0b101, 0b0000001) => Inst::DivuW { dest, src1, src2 },
1662 (0b110, 0b0000001) => Inst::RemW { dest, src1, src2 },
1663 (0b111, 0b0000001) => Inst::RemuW { dest, src1, src2 },
1664 _ => return Err(decode_error(code, "OP-32 funct3/funct7")),
1665 }
1666 }
1667 0b0001111 => {
1669 let fm = code.extract(28..=31);
1670 let pred = FenceSet {
1671 device_input: code.extract(27..=27) == 1,
1672 device_output: code.extract(26..=26) == 1,
1673 memory_read: code.extract(25..=25) == 1,
1674 memory_write: code.extract(24..=24) == 1,
1675 };
1676 let succ = FenceSet {
1677 device_input: code.extract(23..=23) == 1,
1678 device_output: code.extract(22..=22) == 1,
1679 memory_read: code.extract(21..=21) == 1,
1680 memory_write: code.extract(20..=20) == 1,
1681 };
1682
1683 match code.funct3() {
1684 0b000 => Inst::Fence {
1685 fence: Fence {
1686 fm: fm as u8,
1687 pred,
1688 succ,
1689 dest: code.rd(),
1690 src: code.rs1(),
1691 },
1692 },
1693 _ => return Err(decode_error(code, "MISC-MEM funct3")),
1694 }
1695 }
1696 0b1110011 => {
1698 if code.0 == 0b11000000000000000001000001110011 {
1699 return Err(decode_error(code, "unimp instruction"));
1700 }
1701 if code.rd().0 != 0 {
1702 return Err(decode_error(code, "SYSTEM rd"));
1703 }
1704 if code.funct3() != 0 {
1705 return Err(decode_error(code, "SYSTEM funct3"));
1706 }
1707 if code.rs1().0 != 0 {
1708 return Err(decode_error(code, "SYSTEM rs1"));
1709 }
1710 match code.imm_i().as_u32() {
1711 0b000000000000 => Inst::Ecall,
1712 0b000000000001 => Inst::Ebreak,
1713 _ => return Err(decode_error(code, "SYSTEM imm")),
1714 }
1715 }
1716 0b00101111 => {
1718 if code.funct3() != 0b010 {
1720 return Err(decode_error(code, "AMO width funct3"));
1721 }
1722
1723 let kind = code.extract(27..=31);
1724 let aq = code.extract(26..=26) == 1;
1725 let rl = code.extract(25..=25) == 1;
1726
1727 let order = AmoOrdering::from_aq_rl(aq, rl);
1728
1729 match kind {
1730 0b00010 => {
1732 if code.rs2().0 != 0 {
1733 return Err(decode_error(code, "AMO.LR rs2"));
1734 }
1735
1736 Inst::LrW {
1737 order,
1738 dest: code.rd(),
1739 addr: code.rs1(),
1740 }
1741 }
1742 0b00011 => Inst::ScW {
1744 order,
1745 dest: code.rd(),
1746 addr: code.rs1(),
1747 src: code.rs2(),
1748 },
1749 _ => {
1750 let op = match kind {
1751 0b00001 => AmoOp::Swap,
1752 0b00000 => AmoOp::Add,
1753 0b00100 => AmoOp::Xor,
1754 0b01100 => AmoOp::And,
1755 0b01000 => AmoOp::Or,
1756 0b10000 => AmoOp::Min,
1757 0b10100 => AmoOp::Max,
1758 0b11000 => AmoOp::Minu,
1759 0b11100 => AmoOp::Maxu,
1760 _ => return Err(decode_error(code, "AMO op funct7")),
1761 };
1762 Inst::AmoW {
1763 order,
1764 op,
1765 dest: code.rd(),
1766 addr: code.rs1(),
1767 src: code.rs2(),
1768 }
1769 }
1770 }
1771 }
1772 _ => return Err(decode_error(code, "opcode")),
1773 };
1774 Ok(inst)
1775 }
1776 pub fn encode_normal(&self, xlen: Xlen) -> u32 {
1778 let code = InstCode(0);
1779 macro_rules! BRANCH {
1780 ($offset:ident, $src1:ident, $src2:ident => $a:expr) => {
1781 $a.with_opcode(0b1100011)
1782 .with_imm_b(*$offset)
1783 .with_rs1(*$src1)
1784 .with_rs2(*$src2)
1785 };
1786 }
1787 macro_rules! LOAD {
1788 ($offset:ident, $src1:ident, $dest:ident => $a:expr) => {
1789 $a.with_opcode(0b0000011)
1790 .with_imm_i(*$offset)
1791 .with_rs1(*$src1)
1792 .with_rd(*$dest)
1793 };
1794 }
1795 macro_rules! STORE {
1796 ($offset:ident, $src1:ident, $src2:ident => $a:expr) => {
1797 $a.with_opcode(0b0100011)
1798 .with_imm_s(*$offset)
1799 .with_rs1(*$src1)
1800 .with_rs2(*$src2)
1801 };
1802 }
1803 macro_rules! OP_IMM {
1804 ($offset:ident, $src1:ident, $dest:ident => $a:expr) => {
1805 $a.with_opcode(0b0010011)
1806 .with_imm_i(*$offset)
1807 .with_rs1(*$src1)
1808 .with_rd(*$dest)
1809 };
1810 }
1811 macro_rules! OP_IMM_32 {
1812 ($offset:ident, $src1:ident, $dest:ident => $a:expr) => {
1813 $a.with_opcode(0b0011011)
1814 .with_imm_i(*$offset)
1815 .with_rs1(*$src1)
1816 .with_rd(*$dest)
1817 };
1818 }
1819 macro_rules! OP {
1820 ($src1:ident, $src2:ident, $dest:ident => $a:expr) => {
1821 $a.with_opcode(0b0110011)
1822 .with_rs2(*$src2)
1823 .with_rs1(*$src1)
1824 .with_rd(*$dest)
1825 };
1826 }
1827 macro_rules! OP_32 {
1828 ($src1:ident, $src2:ident, $dest:ident => $a:expr) => {
1829 $a.with_opcode(0b0111011)
1830 .with_rs2(*$src2)
1831 .with_rs1(*$src1)
1832 .with_rd(*$dest)
1833 };
1834 }
1835 let code: InstCode = match self {
1836 Inst::Lui { uimm, dest } => {
1837 code.with_opcode(0b0110111).with_rd(*dest).with_imm_u(*uimm)
1838 }
1839 Inst::Auipc { uimm, dest } => {
1840 code.with_opcode(0b0010111).with_rd(*dest).with_imm_u(*uimm)
1841 }
1842 Inst::Jal { offset, dest } => code
1843 .with_opcode(0b1101111)
1844 .with_imm_j(*offset)
1845 .with_rd(*dest),
1846 Inst::Jalr { offset, base, dest } => code
1847 .with_opcode(0b1100111)
1848 .with_funct3(0b000)
1849 .with_imm_i(*offset)
1850 .with_rs1(*base)
1851 .with_rd(*dest),
1852 Inst::Beq { offset, src1, src2 } => {
1853 BRANCH!(offset,src1,src2 => code).with_funct3(0b000)
1854 }
1855 Inst::Bne { offset, src1, src2 } => {
1856 BRANCH!(offset,src1,src2 => code).with_funct3(0b001)
1857 }
1858 Inst::Blt { offset, src1, src2 } => {
1859 BRANCH!(offset,src1,src2 => code).with_funct3(0b100)
1860 }
1861 Inst::Bge { offset, src1, src2 } => {
1862 BRANCH!(offset,src1,src2 => code).with_funct3(0b101)
1863 }
1864 Inst::Bltu { offset, src1, src2 } => {
1865 BRANCH!(offset,src1,src2 => code).with_funct3(0b110)
1866 }
1867 Inst::Bgeu { offset, src1, src2 } => {
1868 BRANCH!(offset,src1,src2 => code).with_funct3(0b111)
1869 }
1870 Inst::Lb { offset, dest, base } => LOAD!(offset,base,dest => code).with_funct3(0b000),
1871 Inst::Lbu { offset, dest, base } => LOAD!(offset,base,dest => code).with_funct3(0b100),
1872 Inst::Lh { offset, dest, base } => LOAD!(offset,base,dest => code).with_funct3(0b001),
1873 Inst::Lhu { offset, dest, base } => LOAD!(offset,base,dest => code).with_funct3(0b101),
1874 Inst::Lw { offset, dest, base } => LOAD!(offset,base,dest => code).with_funct3(0b010),
1875 Inst::Lwu { offset, dest, base } => LOAD!(offset,base,dest => code).with_funct3(0b110),
1876 Inst::Ld { offset, dest, base } => LOAD!(offset,base,dest => code).with_funct3(0b011),
1877 Inst::Sb { offset, src, base } => STORE!(offset,base,src => code).with_funct3(0b000),
1878 Inst::Sh { offset, src, base } => STORE!(offset,base,src => code).with_funct3(0b001),
1879 Inst::Sw { offset, src, base } => STORE!(offset,base,src => code).with_funct3(0b010),
1880 Inst::Sd { offset, src, base } => STORE!(offset,base,src => code).with_funct3(0b011),
1881 Inst::Addi { imm, dest, src1 } => OP_IMM!(imm,src1,dest => code).with_funct3(0b000),
1882 Inst::AddiW { imm, dest, src1 } => OP_IMM_32!(imm,src1,dest => code).with_funct3(0b000),
1883 Inst::Slti { imm, dest, src1 } => OP_IMM!(imm,src1,dest => code).with_funct3(0b010),
1884 Inst::Sltiu { imm, dest, src1 } => OP_IMM!(imm,src1,dest => code).with_funct3(0b011),
1885 Inst::Xori { imm, dest, src1 } => OP_IMM!(imm,src1,dest => code).with_funct3(0b100),
1886 Inst::Ori { imm, dest, src1 } => OP_IMM!(imm,src1,dest => code).with_funct3(0b110),
1887 Inst::Andi { imm, dest, src1 } => OP_IMM!(imm,src1,dest => code).with_funct3(0b111),
1888 Inst::Slli { imm, dest, src1 } => OP_IMM!(imm,src1,dest => code).with_funct3(0b001),
1889 Inst::SlliW { imm, dest, src1 } => OP_IMM_32!(imm,src1,dest => code).with_funct3(0b001),
1890 Inst::Srli { imm, dest, src1 } => {
1891 match OP_IMM!(imm,src1,dest => code).with_funct3(0b101) {
1892 x => match xlen {
1893 Xlen::Rv32 => x.with_funct7(0b0000000).with_rs2_imm(imm.as_u32()),
1894 Xlen::Rv64 => x.with_funct7(0b0000000).with_rs2_imm_plus(imm.as_u32()),
1895 },
1896 }
1897 }
1898 Inst::SrliW { imm, dest, src1 } => OP_IMM_32!(imm,src1,dest => code)
1899 .with_funct3(0b101)
1900 .with_funct7(0b0000000)
1901 .with_rs2_imm(imm.as_u32()),
1902 Inst::Srai { imm, dest, src1 } => {
1903 match OP_IMM!(imm,src1,dest => code).with_funct3(0b101) {
1904 x => match xlen {
1905 Xlen::Rv32 => x.with_funct7(0b0100000).with_rs2_imm(imm.as_u32()),
1906 Xlen::Rv64 => x.with_funct7(0b0100000).with_rs2_imm_plus(imm.as_u32()),
1907 },
1908 }
1909 }
1910 Inst::SraiW { imm, dest, src1 } => OP_IMM_32!(imm,src1,dest => code)
1911 .with_funct3(0b101)
1912 .with_funct7(0b0100000)
1913 .with_rs2_imm(imm.as_u32()),
1914 Inst::Add { dest, src1, src2 } => OP!(src1,src2,dest => code)
1915 .with_funct3(0b000)
1916 .with_funct7(0b0000000),
1917 Inst::AddW { dest, src1, src2 } => OP_32!(src1,src2,dest => code)
1918 .with_funct3(0b000)
1919 .with_funct7(0b0000000),
1920 Inst::Sub { dest, src1, src2 } => OP!(src1,src2,dest => code)
1921 .with_funct3(0b000)
1922 .with_funct7(0b0100000),
1923 Inst::SubW { dest, src1, src2 } => OP_32!(src1,src2,dest => code)
1924 .with_funct3(0b000)
1925 .with_funct7(0b0100000),
1926 Inst::Sll { dest, src1, src2 } => OP!(src1,src2,dest => code)
1927 .with_funct3(0b001)
1928 .with_funct7(0b0000000),
1929 Inst::SllW { dest, src1, src2 } => OP_32!(src1,src2,dest => code)
1930 .with_funct3(0b001)
1931 .with_funct7(0b0000000),
1932 Inst::Slt { dest, src1, src2 } => OP!(src1,src2,dest => code)
1933 .with_funct3(0b010)
1934 .with_funct7(0b0000000),
1935 Inst::Sltu { dest, src1, src2 } => OP!(src1,src2,dest => code)
1936 .with_funct3(0b011)
1937 .with_funct7(0b0000000),
1938 Inst::Xor { dest, src1, src2 } => OP!(src1,src2,dest => code)
1939 .with_funct3(0b100)
1940 .with_funct7(0b0000000),
1941 Inst::Srl { dest, src1, src2 } => OP!(src1,src2,dest => code)
1942 .with_funct3(0b101)
1943 .with_funct7(0b0000000),
1944 Inst::SrlW { dest, src1, src2 } => OP_32!(src1,src2,dest => code)
1945 .with_funct3(0b101)
1946 .with_funct7(0b0000000),
1947 Inst::Sra { dest, src1, src2 } => OP!(src1,src2,dest => code)
1948 .with_funct3(0b101)
1949 .with_funct7(0b0100000),
1950 Inst::SraW { dest, src1, src2 } => OP_32!(src1,src2,dest => code)
1951 .with_funct3(0b101)
1952 .with_funct7(0b0100000),
1953 Inst::Or { dest, src1, src2 } => OP!(src1,src2,dest => code)
1954 .with_funct3(0b110)
1955 .with_funct7(0b0000000),
1956 Inst::And { dest, src1, src2 } => OP!(src1,src2,dest => code)
1957 .with_funct3(0b111)
1958 .with_funct7(0b0000000),
1959 Inst::Fence { fence } => match code
1960 .with_opcode(0b0001111)
1961 .insert(28..=31, fence.fm as u32)
1962 .with_rd(fence.dest)
1963 .with_rs1(fence.src)
1964 {
1965 mut v => {
1966 let mut i = |x, b| v = v.insert(x..=x, if b { 1 } else { 0 });
1967 i(27, fence.pred.device_input);
1968 i(26, fence.pred.device_output);
1969 i(25, fence.pred.memory_read);
1970 i(24, fence.pred.memory_write);
1971 i(23, fence.succ.device_input);
1972 i(22, fence.succ.device_output);
1973 i(21, fence.succ.memory_read);
1974 i(20, fence.succ.memory_write);
1975 v
1976 }
1977 },
1978 Inst::Ecall => code
1979 .with_opcode(0b1110011)
1980 .with_imm_i(Imm::new_u32(0b000000000000)),
1981 Inst::Ebreak => code
1982 .with_opcode(0b1110011)
1983 .with_imm_i(Imm::new_u32(0b000000000001)),
1984 Inst::Mul { dest, src1, src2 } => OP!(src1,src2,dest => code)
1985 .with_funct3(0b000)
1986 .with_funct7(0b0000001),
1987 Inst::MulW { dest, src1, src2 } => OP_32!(src1,src2,dest => code)
1988 .with_funct3(0b000)
1989 .with_funct7(0b0000001),
1990 Inst::Mulh { dest, src1, src2 } => OP!(src1,src2,dest => code)
1991 .with_funct3(0b001)
1992 .with_funct7(0b0000001),
1993 Inst::Mulhsu { dest, src1, src2 } => OP!(src1,src2,dest => code)
1994 .with_funct3(0b010)
1995 .with_funct7(0b0000001),
1996 Inst::Mulhu { dest, src1, src2 } => OP!(src1,src2,dest => code)
1997 .with_funct3(0b011)
1998 .with_funct7(0b0000001),
1999 Inst::Div { dest, src1, src2 } => OP!(src1,src2,dest => code)
2000 .with_funct3(0b100)
2001 .with_funct7(0b0000001),
2002 Inst::DivW { dest, src1, src2 } => OP_32!(src1,src2,dest => code)
2003 .with_funct3(0b100)
2004 .with_funct7(0b0000001),
2005 Inst::Divu { dest, src1, src2 } => OP!(src1,src2,dest => code)
2006 .with_funct3(0b101)
2007 .with_funct7(0b0000001),
2008 Inst::DivuW { dest, src1, src2 } => OP_32!(src1,src2,dest => code)
2009 .with_funct3(0b101)
2010 .with_funct7(0b0000001),
2011 Inst::Rem { dest, src1, src2 } => OP!(src1,src2,dest => code)
2012 .with_funct3(0b110)
2013 .with_funct7(0b0000001),
2014 Inst::RemW { dest, src1, src2 } => OP_32!(src1,src2,dest => code)
2015 .with_funct3(0b110)
2016 .with_funct7(0b0000001),
2017 Inst::Remu { dest, src1, src2 } => OP!(src1,src2,dest => code)
2018 .with_funct3(0b111)
2019 .with_funct7(0b0000001),
2020 Inst::RemuW { dest, src1, src2 } => OP_32!(src1,src2,dest => code)
2021 .with_funct3(0b111)
2022 .with_funct7(0b0000001),
2023 Inst::LrW { order, dest, addr } => match code
2024 .with_opcode(0b00101111)
2025 .with_funct3(0b010)
2026 .insert(26..=26, if order.aq_rl().0 { 1 } else { 0 })
2027 .insert(25..=25, if order.aq_rl().1 { 1 } else { 0 })
2028 {
2029 code => code.insert(27..=31, 0b00010).with_rd(*dest).with_rs1(*addr),
2030 },
2031 Inst::ScW {
2032 order,
2033 dest,
2034 addr,
2035 src,
2036 } => match code
2037 .with_opcode(0b00101111)
2038 .with_funct3(0b010)
2039 .insert(26..=26, if order.aq_rl().0 { 1 } else { 0 })
2040 .insert(25..=25, if order.aq_rl().1 { 1 } else { 0 })
2041 {
2042 code => code
2043 .insert(27..=31, 0b00011)
2044 .with_rd(*dest)
2045 .with_rs1(*addr)
2046 .with_rs2(*src),
2047 },
2048 Inst::AmoW {
2049 order,
2050 op,
2051 dest,
2052 addr,
2053 src,
2054 } => match code
2055 .with_opcode(0b00101111)
2056 .with_funct3(0b010)
2057 .insert(26..=26, if order.aq_rl().0 { 1 } else { 0 })
2058 .insert(25..=25, if order.aq_rl().1 { 1 } else { 0 })
2059 {
2060 code => code.with_rd(*dest).with_rs1(*addr).with_rs2(*src).insert(
2061 27..=31,
2062 match op {
2063 AmoOp::Swap => 0b00001,
2064 AmoOp::Add => 0b00000,
2065 AmoOp::Xor => 0b00100,
2066 AmoOp::And => 0b01100,
2067 AmoOp::Or => 0b01000,
2068 AmoOp::Min => 0b10000,
2069 AmoOp::Max => 0b10100,
2070 AmoOp::Minu => 0b11000,
2071 AmoOp::Maxu => 0b11100,
2072 },
2073 ),
2074 },
2075 };
2076 code.0
2077 }
2078}
2079
2080#[cfg(test)]
2081mod tests {
2082 extern crate std;
2083 use core::sync::atomic::AtomicU32;
2084 use core::sync::atomic::Ordering;
2085 use core::u32;
2086 use std::prelude::rust_2024::*;
2087
2088 use std::fmt::Write as _;
2089 use std::io::Write as _;
2090
2091 use object::Object;
2092 use object::ObjectSection;
2093 use rayon::iter::IntoParallelRefIterator;
2094 use rayon::iter::ParallelIterator;
2095
2096 use crate::Fence;
2097 use crate::FenceSet;
2098 use crate::Imm;
2099 use crate::Inst;
2100 use crate::Reg;
2101 use crate::Xlen;
2102
2103 #[test]
2104 #[cfg_attr(not(slow_tests), ignore = "cfg(slow_tests) not enabled")]
2105 fn exhaustive_decode_no_panic_32() {
2106 exhaustive_decode_no_panic(Xlen::Rv32);
2107 }
2108
2109 #[test]
2110 #[cfg_attr(not(slow_tests), ignore = "cfg(slow_tests) not enabled")]
2111 fn exhaustive_decode_no_panic_64() {
2112 exhaustive_decode_no_panic(Xlen::Rv64);
2113 }
2114
2115 fn exhaustive_decode_no_panic(xlen: Xlen) {
2116 for i in 0..u32::MAX {
2117 if (i % (2 << 25)) == 0 {
2118 let percent = i as f32 / (u32::MAX as f32);
2119 let done = (100.0 * percent) as usize;
2120 std::print!("\r{}{}", "#".repeat(done), "-".repeat(100 - done));
2121 std::io::stdout().flush().unwrap();
2122 }
2123 let i2 = Inst::decode(i, xlen);
2124 if let Ok((i2, crate::IsCompressed::No)) = i2 {
2125 if is_inst_supposed_to_roundtrip(&i2) {
2126 assert_eq!(
2127 i2,
2128 Inst::decode(i2.encode_normal(xlen), xlen)
2129 .expect("to succeed")
2130 .0,
2131 "encoded inst different: {i2} from {i} encodes differently"
2132 );
2133 }
2134 }
2135 }
2136 let i2 = Inst::decode(u32::MAX, xlen);
2137 let i = u32::MAX;
2138 if let Ok((i2, crate::IsCompressed::No)) = i2 {
2139 if is_inst_supposed_to_roundtrip(&i2) {
2140 assert_eq!(
2141 i2,
2142 Inst::decode(i2.encode_normal(xlen), xlen)
2143 .expect("to succeed")
2144 .0,
2145 "encoded inst different: {i2} from {i} encodes differently"
2146 );
2147 }
2148 }
2149 }
2150
2151 #[test]
2152 fn size_of_instruction() {
2153 assert!(
2154 size_of::<Inst>() <= 16,
2155 "size of instruction is too large: {}",
2156 size_of::<Inst>()
2157 );
2158 }
2159
2160 const TEST_SECTION_NAME: &str = ".text.rvdctest";
2161
2162 fn is_inst_supposed_to_roundtrip(inst: &Inst) -> bool {
2166 match inst {
2167 Inst::Fence {
2169 fence:
2170 Fence {
2171 fm: 0b1000,
2172 pred:
2173 FenceSet {
2174 device_input: false,
2175 device_output: false,
2176 memory_read: true,
2177 memory_write: true,
2178 },
2179 succ:
2180 FenceSet {
2181 device_input: false,
2182 device_output: false,
2183 memory_read: true,
2184 memory_write: true,
2185 },
2186 src: Reg::ZERO,
2187 dest: Reg::ZERO,
2188 },
2189 } => true,
2190 Inst::Fence {
2192 fence:
2193 Fence {
2194 fm: 0b0000,
2195 pred: _,
2196 succ: _,
2197 src: Reg::ZERO,
2198 dest: Reg::ZERO,
2199 },
2200 } => true,
2201 Inst::Fence { .. } => false,
2203 _ => true,
2204 }
2205 }
2206
2207 fn is_compressed_inst_supposed_to_roundtrip(inst: &Inst) -> bool {
2208 match inst {
2209 Inst::Addi {
2211 dest: Reg::ZERO, ..
2212 } => false,
2213 Inst::Addi { imm: Imm::ZERO, .. } => false,
2215 Inst::Addi {
2217 dest: Reg::SP,
2218 src1: Reg::SP,
2219 ..
2220 } => false,
2221 Inst::Slli {
2223 dest: Reg::ZERO, ..
2224 }
2225 | Inst::Slli { imm: Imm::ZERO, .. }
2226 | Inst::Srli {
2227 dest: Reg::ZERO, ..
2228 }
2229 | Inst::Srli { imm: Imm::ZERO, .. }
2230 | Inst::Srai {
2231 dest: Reg::ZERO, ..
2232 }
2233 | Inst::Srai { imm: Imm::ZERO, .. } => false,
2234 Inst::Lui {
2236 dest: Reg::ZERO, ..
2237 } => false,
2238 _ => true,
2239 }
2240 }
2241
2242 const SKIP_CHUNKS: u32 = 0;
2244
2245 #[test]
2246 fn ensure_no_chunks_are_skipped() {
2247 assert_eq!(SKIP_CHUNKS, 0);
2248 }
2249
2250 #[test]
2251 #[cfg_attr(not(slow_tests), ignore = "cfg(slow_tests) not enabled")]
2252 fn normal_clang_roundtrip() {
2253 const CHUNKS: u32 = 128;
2254 const CHUNK_SIZE: u32 = u32::MAX / CHUNKS;
2255
2256 let chunks = ((SKIP_CHUNKS * CHUNK_SIZE)..u32::MAX)
2257 .step_by(CHUNK_SIZE as usize)
2258 .collect::<Vec<_>>();
2259
2260 let start_time = std::time::Instant::now();
2261 let completed = AtomicU32::new(0);
2262
2263 chunks.par_iter().for_each(|&start| {
2264 let insts = (start..=start.saturating_add(CHUNK_SIZE))
2265 .filter_map(|code| Some((code, Inst::decode_normal(code, Xlen::Rv32).ok()?)))
2266 .filter(|(_, inst)| is_inst_supposed_to_roundtrip(inst))
2267 .collect::<Vec<_>>();
2268
2269 let mut text = std::format!(".section {TEST_SECTION_NAME}\n.globl _start\n_start:\n");
2270 for (_, inst) in &insts {
2271 writeln!(text, " {inst}").unwrap();
2272 }
2273
2274 let data = clang_assemble(&text, "-march=rv32ima_zihintpause");
2275
2276 for (i, result_code) in data.chunks(4).enumerate() {
2277 let result_code = u32::from_le_bytes(result_code.try_into().unwrap());
2278
2279 assert_eq!(
2280 insts[i].0, result_code,
2281 "failed to rountrip!\n\
2282 instruction `{:0>32b}` failed to rountrip\n\
2283 resulted in `{:0>32b}` instead.\n\
2284 disassembly of original instruction: `{}`",
2285 insts[i].0, result_code, insts[i].1
2286 );
2287 }
2288
2289 let already_completed = completed.fetch_add(1, Ordering::Relaxed);
2290 let already_elapsed = start_time.elapsed();
2291
2292 let remaining_chunks = CHUNKS.saturating_sub(already_completed);
2293 let remaining =
2294 already_elapsed / std::cmp::max(already_completed, 1) * remaining_chunks;
2295
2296 writeln!(
2297 std::io::stdout(),
2298 "Completed chunk {already_completed}/{CHUNKS} (estimated {remaining:?} remaining)",
2299 )
2300 .unwrap();
2301 });
2302 }
2303
2304 #[test]
2305 #[ignore = "this doesn't quite work yet because there is often a non-canonical encoding"]
2306 fn compressed_clang_roundtrip() {
2307 let insts = (0..=u16::MAX)
2308 .filter_map(|code| Some((code, Inst::decode_compressed(code, Xlen::Rv32).ok()?)))
2309 .filter(|(_, inst)| is_compressed_inst_supposed_to_roundtrip(inst))
2310 .collect::<Vec<_>>();
2311
2312 let mut text = std::format!(".section {TEST_SECTION_NAME}\n.globl _start\n_start:\n");
2313 for (_, inst) in &insts {
2314 writeln!(text, " {inst}").unwrap();
2315 }
2316
2317 let data = clang_assemble(&text, "-march=rv32imac");
2318
2319 for (i, result_code) in data.chunks(2).enumerate() {
2320 assert!(
2321 Inst::first_byte_is_compressed(result_code[0]),
2322 "failed to roundtrip {i}th instruction!\n\
2323 instruction `{:0>16b}` resulted in an uncompressed instruction from clang\n\
2324 disassembly of original instruction: `{}`",
2325 insts[i].0,
2326 insts[i].1
2327 );
2328
2329 let result_code = u16::from_le_bytes(result_code.try_into().unwrap());
2330
2331 assert_eq!(
2332 insts[i].0, result_code,
2333 "failed to rountrip {i}th instruction!\n\
2334 instruction `{:0>16b}` failed to rountrip\n\
2335 resulted in `{:0>16b}` instead.\n\
2336 disassembly of original instruction: `{}`",
2337 insts[i].0, result_code, insts[i].1
2338 );
2339 }
2340 }
2341
2342 fn clang_assemble(text: &str, march_flag: &str) -> Vec<u8> {
2343 let tmp = tempfile::tempdir().unwrap();
2344
2345 let path = tmp.path().join("16.s");
2346 let bin_path = tmp.path().join("16.o");
2347 std::fs::write(&path, text).unwrap();
2348
2349 let mut clang = std::process::Command::new("clang");
2350 clang.args(["-target", "riscv32-unknown-none-elf", march_flag, "-c"]);
2351 clang.arg(path);
2352 clang.arg("-o");
2353 clang.arg(&bin_path);
2354 let out = clang.output().unwrap();
2355 if !out.status.success() {
2356 panic!(
2357 "failed to run clang:\n{}",
2358 String::from_utf8_lossy(&out.stderr)
2359 );
2360 }
2361
2362 let obj = std::fs::read(bin_path).unwrap();
2363 let obj = object::File::parse(&*obj).unwrap();
2364 let section = obj.section_by_name(TEST_SECTION_NAME).unwrap();
2365 let data = section.data().unwrap();
2366 data.to_owned()
2367 }
2368}