Skip to main content

ab_riscv_primitives/instructions/rv32/b/
zbb.rs

1//! RV32 Zbb extension
2
3#[cfg(test)]
4mod tests;
5
6use crate::instructions::Instruction;
7use crate::registers::general_purpose::Register;
8use ab_riscv_macros::instruction;
9use core::fmt;
10
11/// RISC-V RV32 Zbb instruction (Basic bit manipulation)
12#[instruction]
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum Rv32ZbbInstruction<Reg> {
15    Andn { rd: Reg, rs1: Reg, rs2: Reg },
16    Orn { rd: Reg, rs1: Reg, rs2: Reg },
17    Xnor { rd: Reg, rs1: Reg, rs2: Reg },
18    Clz { rd: Reg, rs1: Reg },
19    Ctz { rd: Reg, rs1: Reg },
20    Cpop { rd: Reg, rs1: Reg },
21    Max { rd: Reg, rs1: Reg, rs2: Reg },
22    Maxu { rd: Reg, rs1: Reg, rs2: Reg },
23    Min { rd: Reg, rs1: Reg, rs2: Reg },
24    Minu { rd: Reg, rs1: Reg, rs2: Reg },
25    Sextb { rd: Reg, rs1: Reg },
26    Sexth { rd: Reg, rs1: Reg },
27    Zexth { rd: Reg, rs1: Reg },
28    Rol { rd: Reg, rs1: Reg, rs2: Reg },
29    Ror { rd: Reg, rs1: Reg, rs2: Reg },
30    Rori { rd: Reg, rs1: Reg, shamt: u8 },
31    Orcb { rd: Reg, rs1: Reg },
32    Rev8 { rd: Reg, rs1: Reg },
33}
34
35#[instruction]
36const impl<Reg> Instruction for Rv32ZbbInstruction<Reg>
37where
38    Reg: [const] Register<Type = u32>,
39{
40    type Reg = Reg;
41
42    #[inline(always)]
43    #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
44    fn try_decode(instruction: u32) -> Option<Self> {
45        let opcode = (instruction & 0b111_1111) as u8;
46        let rd_bits = ((instruction >> 7) & 0x1f) as u8;
47        let funct3 = ((instruction >> 12) & 0b111) as u8;
48        let rs1_bits = ((instruction >> 15) & 0x1f) as u8;
49        let rs2_bits = ((instruction >> 20) & 0x1f) as u8;
50        let funct7 = ((instruction >> 25) & 0b111_1111) as u8;
51        let funct6 = ((instruction >> 26) & 0b11_1111) as u8;
52        // For I-type: bits [25:20]
53        let low5 = ((instruction >> 20) & 0x1f) as u8;
54        let funct12 = ((instruction >> 20) & 0xfff) as u16;
55
56        match opcode {
57            // OP-IMM
58            0b001_0011 => {
59                let rd = Reg::from_bits(rd_bits)?;
60                let rs1 = Reg::from_bits(rs1_bits)?;
61                match funct3 {
62                    0b001 => {
63                        // RV32: shamt is 5 bits; funct7 distinguishes the operation
64                        if funct7 == 0b011_0000 {
65                            match rs2_bits {
66                                0 => Some(Self::Clz { rd, rs1 }),
67                                1 => Some(Self::Ctz { rd, rs1 }),
68                                2 => Some(Self::Cpop { rd, rs1 }),
69                                4 => Some(Self::Sextb { rd, rs1 }),
70                                5 => Some(Self::Sexth { rd, rs1 }),
71                                _ => None,
72                            }
73                        } else {
74                            None
75                        }
76                    }
77                    0b101 => {
78                        // orc.b: funct12 = 0b0010_1000_0111
79                        // rev8 for RV32: funct12 = 0b0110_1001_1000
80                        // rori: funct6 = 0b01_1000, shamt in bits [24:20]
81                        if funct12 == 0b0010_1000_0111 {
82                            Some(Self::Orcb { rd, rs1 })
83                        } else if funct12 == 0b0110_1001_1000 {
84                            Some(Self::Rev8 { rd, rs1 })
85                        } else if funct6 == 0b01_1000 {
86                            Some(Self::Rori {
87                                rd,
88                                rs1,
89                                shamt: low5,
90                            })
91                        } else {
92                            None
93                        }
94                    }
95                    _ => None,
96                }
97            }
98            // OP / R-type
99            0b011_0011 => {
100                let rd = Reg::from_bits(rd_bits)?;
101                let rs1 = Reg::from_bits(rs1_bits)?;
102                let rs2 = Reg::from_bits(rs2_bits)?;
103                match funct3 {
104                    0b001 => {
105                        if funct7 == 0b011_0000 {
106                            Some(Self::Rol { rd, rs1, rs2 })
107                        } else {
108                            None
109                        }
110                    }
111                    0b100 => match funct7 {
112                        0b010_0000 => Some(Self::Xnor { rd, rs1, rs2 }),
113                        0b000_0101 => Some(Self::Min { rd, rs1, rs2 }),
114                        // zext.h for RV32 uses OP (0b011_0011), funct7=0b000_0100, rs2=0
115                        0b000_0100 => {
116                            if rs2_bits == 0 {
117                                Some(Self::Zexth { rd, rs1 })
118                            } else {
119                                None
120                            }
121                        }
122                        _ => None,
123                    },
124                    0b101 => match funct7 {
125                        0b011_0000 => Some(Self::Ror { rd, rs1, rs2 }),
126                        0b000_0101 => Some(Self::Minu { rd, rs1, rs2 }),
127                        _ => None,
128                    },
129                    0b110 => match funct7 {
130                        0b010_0000 => Some(Self::Orn { rd, rs1, rs2 }),
131                        0b000_0101 => Some(Self::Max { rd, rs1, rs2 }),
132                        _ => None,
133                    },
134                    0b111 => match funct7 {
135                        0b010_0000 => Some(Self::Andn { rd, rs1, rs2 }),
136                        0b000_0101 => Some(Self::Maxu { rd, rs1, rs2 }),
137                        _ => None,
138                    },
139                    _ => None,
140                }
141            }
142            _ => None,
143        }
144    }
145
146    #[inline(always)]
147    fn alignment() -> u8 {
148        align_of::<u32>() as u8
149    }
150
151    #[inline(always)]
152    fn size(&self) -> u8 {
153        size_of::<u32>() as u8
154    }
155}
156
157#[instruction]
158impl<Reg> fmt::Display for Rv32ZbbInstruction<Reg>
159where
160    Reg: fmt::Display,
161{
162    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
163        match self {
164            Self::Andn { rd, rs1, rs2 } => write!(f, "andn {rd}, {rs1}, {rs2}"),
165            Self::Orn { rd, rs1, rs2 } => write!(f, "orn {rd}, {rs1}, {rs2}"),
166            Self::Xnor { rd, rs1, rs2 } => write!(f, "xnor {rd}, {rs1}, {rs2}"),
167            Self::Clz { rd, rs1 } => write!(f, "clz {rd}, {rs1}"),
168            Self::Ctz { rd, rs1 } => write!(f, "ctz {rd}, {rs1}"),
169            Self::Cpop { rd, rs1 } => write!(f, "cpop {rd}, {rs1}"),
170            Self::Max { rd, rs1, rs2 } => write!(f, "max {rd}, {rs1}, {rs2}"),
171            Self::Maxu { rd, rs1, rs2 } => write!(f, "maxu {rd}, {rs1}, {rs2}"),
172            Self::Min { rd, rs1, rs2 } => write!(f, "min {rd}, {rs1}, {rs2}"),
173            Self::Minu { rd, rs1, rs2 } => write!(f, "minu {rd}, {rs1}, {rs2}"),
174            Self::Sextb { rd, rs1 } => write!(f, "sext.b {rd}, {rs1}"),
175            Self::Sexth { rd, rs1 } => write!(f, "sext.h {rd}, {rs1}"),
176            Self::Zexth { rd, rs1 } => write!(f, "zext.h {rd}, {rs1}"),
177            Self::Rol { rd, rs1, rs2 } => write!(f, "rol {rd}, {rs1}, {rs2}"),
178            Self::Ror { rd, rs1, rs2 } => write!(f, "ror {rd}, {rs1}, {rs2}"),
179            Self::Rori { rd, rs1, shamt } => write!(f, "rori {rd}, {rs1}, {shamt}"),
180            Self::Orcb { rd, rs1 } => write!(f, "orc.b {rd}, {rs1}"),
181            Self::Rev8 { rd, rs1 } => write!(f, "rev8 {rd}, {rs1}"),
182        }
183    }
184}