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