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]
36impl<Reg> const Instruction for Rv32ZbbInstruction<Reg>
37where
38    Reg: [const] Register<Type = u32>,
39{
40    type Reg = Reg;
41
42    #[inline(always)]
43    fn try_decode(instruction: u32) -> Option<Self> {
44        let opcode = (instruction & 0b111_1111) as u8;
45        let rd_bits = ((instruction >> 7) & 0x1f) as u8;
46        let funct3 = ((instruction >> 12) & 0b111) as u8;
47        let rs1_bits = ((instruction >> 15) & 0x1f) as u8;
48        let rs2_bits = ((instruction >> 20) & 0x1f) as u8;
49        let funct7 = ((instruction >> 25) & 0b111_1111) as u8;
50        let funct6 = ((instruction >> 26) & 0b11_1111) as u8;
51        // For I-type: bits [25:20]
52        let low5 = ((instruction >> 20) & 0x1f) as u8;
53        let funct12 = ((instruction >> 20) & 0xfff) as u16;
54
55        match opcode {
56            // OP-IMM
57            0b0010011 => {
58                let rd = Reg::from_bits(rd_bits)?;
59                let rs1 = Reg::from_bits(rs1_bits)?;
60                match funct3 {
61                    0b001 => {
62                        // RV32: shamt is 5 bits; funct7 distinguishes the operation
63                        if funct7 == 0b0110000 {
64                            match rs2_bits {
65                                0 => Some(Self::Clz { rd, rs1 }),
66                                1 => Some(Self::Ctz { rd, rs1 }),
67                                2 => Some(Self::Cpop { rd, rs1 }),
68                                4 => Some(Self::Sextb { rd, rs1 }),
69                                5 => Some(Self::Sexth { rd, rs1 }),
70                                _ => None,
71                            }
72                        } else {
73                            None
74                        }
75                    }
76                    0b101 => {
77                        // orc.b: funct12 = 0b001010000111
78                        // rev8 for RV32: funct12 = 0b011010011000
79                        // rori: funct6 = 0b011000, shamt in bits [24:20]
80                        if funct12 == 0b001010000111 {
81                            Some(Self::Orcb { rd, rs1 })
82                        } else if funct12 == 0b011010011000 {
83                            Some(Self::Rev8 { rd, rs1 })
84                        } else if funct6 == 0b011000 {
85                            Some(Self::Rori {
86                                rd,
87                                rs1,
88                                shamt: low5,
89                            })
90                        } else {
91                            None
92                        }
93                    }
94                    _ => None,
95                }
96            }
97            // OP / R-type
98            0b0110011 => {
99                let rd = Reg::from_bits(rd_bits)?;
100                let rs1 = Reg::from_bits(rs1_bits)?;
101                let rs2 = Reg::from_bits(rs2_bits)?;
102                match funct3 {
103                    0b001 => {
104                        if funct7 == 0b0110000 {
105                            Some(Self::Rol { rd, rs1, rs2 })
106                        } else {
107                            None
108                        }
109                    }
110                    0b100 => match funct7 {
111                        0b0100000 => Some(Self::Xnor { rd, rs1, rs2 }),
112                        0b0000101 => Some(Self::Min { rd, rs1, rs2 }),
113                        // zext.h for RV32 uses OP (0b0110011), funct7=0b0000100, rs2=0
114                        0b0000100 => {
115                            if rs2_bits == 0 {
116                                Some(Self::Zexth { rd, rs1 })
117                            } else {
118                                None
119                            }
120                        }
121                        _ => None,
122                    },
123                    0b101 => match funct7 {
124                        0b0110000 => Some(Self::Ror { rd, rs1, rs2 }),
125                        0b0000101 => Some(Self::Minu { rd, rs1, rs2 }),
126                        _ => None,
127                    },
128                    0b110 => match funct7 {
129                        0b0100000 => Some(Self::Orn { rd, rs1, rs2 }),
130                        0b0000101 => Some(Self::Max { rd, rs1, rs2 }),
131                        _ => None,
132                    },
133                    0b111 => match funct7 {
134                        0b0100000 => Some(Self::Andn { rd, rs1, rs2 }),
135                        0b0000101 => Some(Self::Maxu { rd, rs1, rs2 }),
136                        _ => None,
137                    },
138                    _ => None,
139                }
140            }
141            _ => None,
142        }
143    }
144
145    #[inline(always)]
146    fn alignment() -> u8 {
147        size_of::<u32>() as u8
148    }
149
150    #[inline(always)]
151    fn size(&self) -> u8 {
152        size_of::<u32>() as u8
153    }
154}
155
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}