Skip to main content

ab_riscv_primitives/instructions/rv64/b/
zbb.rs

1//! RV64 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 RV64 Zbb instruction (Basic bit manipulation)
12#[instruction]
13#[derive(Debug, Clone, Copy)]
14#[derive_const(PartialEq, Eq)]
15pub enum Rv64ZbbInstruction<Reg> {
16    // RV64 Zbb instructions
17    Andn { rd: Reg, rs1: Reg, rs2: Reg },
18    Orn { rd: Reg, rs1: Reg, rs2: Reg },
19    Xnor { rd: Reg, rs1: Reg, rs2: Reg },
20    Clz { rd: Reg, rs1: Reg },
21    Clzw { rd: Reg, rs1: Reg },
22    Ctz { rd: Reg, rs1: Reg },
23    Ctzw { rd: Reg, rs1: Reg },
24    Cpop { rd: Reg, rs1: Reg },
25    Cpopw { rd: Reg, rs1: Reg },
26    Max { rd: Reg, rs1: Reg, rs2: Reg },
27    Maxu { rd: Reg, rs1: Reg, rs2: Reg },
28    Min { rd: Reg, rs1: Reg, rs2: Reg },
29    Minu { rd: Reg, rs1: Reg, rs2: Reg },
30    Sextb { rd: Reg, rs1: Reg },
31    Sexth { rd: Reg, rs1: Reg },
32    Zexth { rd: Reg, rs1: Reg },
33    Rol { rd: Reg, rs1: Reg, rs2: Reg },
34    Rolw { rd: Reg, rs1: Reg, rs2: Reg },
35    Ror { rd: Reg, rs1: Reg, rs2: Reg },
36    Rori { rd: Reg, rs1: Reg, shamt: u8 },
37    Roriw { rd: Reg, rs1: Reg, shamt: u8 },
38    Rorw { rd: Reg, rs1: Reg, rs2: Reg },
39    Orcb { rd: Reg, rs1: Reg },
40    Rev8 { rd: Reg, rs1: Reg },
41}
42
43#[instruction]
44const impl<Reg> Instruction for Rv64ZbbInstruction<Reg>
45where
46    Reg: [const] Register<Type = u64>,
47{
48    type Reg = Reg;
49
50    #[inline(always)]
51    #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
52    fn try_decode(instruction: u32) -> Option<Self> {
53        let opcode = (instruction & 0b111_1111) as u8;
54        let rd_bits = ((instruction >> 7) & 0x1f) as u8;
55        let funct3 = ((instruction >> 12) & 0b111) as u8;
56        let rs1_bits = ((instruction >> 15) & 0x1f) as u8;
57        let rs2_bits = ((instruction >> 20) & 0x1f) as u8;
58        let funct7 = ((instruction >> 25) & 0b111_1111) as u8;
59        let funct6 = ((instruction >> 26) & 0b11_1111) as u8;
60        // bits 25:20 for I-type distinctions
61        let low6 = ((instruction >> 20) & 0x3f) as u8;
62        let funct12 = ((instruction >> 20) & 0xfff) as u16;
63
64        match opcode {
65            // OP-IMM
66            0b001_0011 => {
67                let rd = Reg::from_bits(rd_bits)?;
68                let rs1 = Reg::from_bits(rs1_bits)?;
69                match funct3 {
70                    0b001 => {
71                        if funct6 == 0b01_1000 {
72                            match low6 {
73                                0 => Some(Self::Clz { rd, rs1 }),
74                                1 => Some(Self::Ctz { rd, rs1 }),
75                                2 => Some(Self::Cpop { rd, rs1 }),
76                                4 => Some(Self::Sextb { rd, rs1 }),
77                                5 => Some(Self::Sexth { rd, rs1 }),
78                                _ => None,
79                            }
80                        } else {
81                            None
82                        }
83                    }
84                    0b101 => {
85                        if funct12 == 0b0010_1000_0111 {
86                            Some(Self::Orcb { rd, rs1 })
87                        } else if funct12 == 0b0110_1011_1000 {
88                            Some(Self::Rev8 { rd, rs1 })
89                        } else if funct6 == 0b01_1000 {
90                            Some(Self::Rori {
91                                rd,
92                                rs1,
93                                shamt: low6,
94                            })
95                        } else {
96                            None
97                        }
98                    }
99                    _ => None,
100                }
101            }
102            // OP / R-type
103            0b011_0011 => {
104                let rd = Reg::from_bits(rd_bits)?;
105                let rs1 = Reg::from_bits(rs1_bits)?;
106                let rs2 = Reg::from_bits(rs2_bits)?;
107                match funct3 {
108                    0b001 => {
109                        if funct7 == 0b011_0000 {
110                            Some(Self::Rol { rd, rs1, rs2 })
111                        } else {
112                            None
113                        }
114                    }
115                    0b100 => match funct7 {
116                        0b010_0000 => Some(Self::Xnor { rd, rs1, rs2 }),
117                        0b000_0101 => Some(Self::Min { rd, rs1, rs2 }),
118                        _ => None,
119                    },
120                    0b101 => match funct7 {
121                        0b011_0000 => Some(Self::Ror { rd, rs1, rs2 }),
122                        0b000_0101 => Some(Self::Minu { rd, rs1, rs2 }),
123                        _ => None,
124                    },
125                    0b110 => match funct7 {
126                        0b010_0000 => Some(Self::Orn { rd, rs1, rs2 }),
127                        0b000_0101 => Some(Self::Max { rd, rs1, rs2 }),
128                        _ => None,
129                    },
130                    0b111 => match funct7 {
131                        0b010_0000 => Some(Self::Andn { rd, rs1, rs2 }),
132                        0b000_0101 => Some(Self::Maxu { rd, rs1, rs2 }),
133                        _ => None,
134                    },
135                    _ => None,
136                }
137            }
138            // OP-IMM-32
139            0b001_1011 => {
140                let rd = Reg::from_bits(rd_bits)?;
141                let rs1 = Reg::from_bits(rs1_bits)?;
142                match funct3 {
143                    0b001 => {
144                        if funct7 == 0b011_0000 {
145                            match rs2_bits {
146                                0 => Some(Self::Clzw { rd, rs1 }),
147                                1 => Some(Self::Ctzw { rd, rs1 }),
148                                2 => Some(Self::Cpopw { rd, rs1 }),
149                                _ => None,
150                            }
151                        } else {
152                            None
153                        }
154                    }
155                    0b101 => {
156                        if funct7 == 0b011_0000 {
157                            let shamt = rs2_bits;
158                            Some(Self::Roriw { rd, rs1, shamt })
159                        } else {
160                            None
161                        }
162                    }
163                    _ => None,
164                }
165            }
166            // OP-32
167            0b011_1011 => {
168                let rd = Reg::from_bits(rd_bits)?;
169                let rs1 = Reg::from_bits(rs1_bits)?;
170                let rs2 = Reg::from_bits(rs2_bits)?;
171                match funct3 {
172                    0b001 => {
173                        if funct7 == 0b011_0000 {
174                            Some(Self::Rolw { rd, rs1, rs2 })
175                        } else {
176                            None
177                        }
178                    }
179                    0b100 => {
180                        if funct7 == 0b000_0100 && rs2_bits == 0 {
181                            Some(Self::Zexth { rd, rs1 })
182                        } else {
183                            None
184                        }
185                    }
186                    0b101 => {
187                        if funct7 == 0b011_0000 {
188                            Some(Self::Rorw { rd, rs1, rs2 })
189                        } else {
190                            None
191                        }
192                    }
193                    _ => None,
194                }
195            }
196            _ => None,
197        }
198    }
199
200    #[inline(always)]
201    fn alignment() -> u8 {
202        align_of::<u32>() as u8
203    }
204
205    #[inline(always)]
206    fn size(&self) -> u8 {
207        size_of::<u32>() as u8
208    }
209}
210
211#[instruction]
212impl<Reg> fmt::Display for Rv64ZbbInstruction<Reg>
213where
214    Reg: fmt::Display,
215{
216    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
217        match self {
218            Self::Andn { rd, rs1, rs2 } => write!(f, "andn {rd}, {rs1}, {rs2}"),
219            Self::Orn { rd, rs1, rs2 } => write!(f, "orn {rd}, {rs1}, {rs2}"),
220            Self::Xnor { rd, rs1, rs2 } => write!(f, "xnor {rd}, {rs1}, {rs2}"),
221            Self::Clz { rd, rs1 } => write!(f, "clz {rd}, {rs1}"),
222            Self::Clzw { rd, rs1 } => write!(f, "clzw {rd}, {rs1}"),
223            Self::Ctz { rd, rs1 } => write!(f, "ctz {rd}, {rs1}"),
224            Self::Ctzw { rd, rs1 } => write!(f, "ctzw {rd}, {rs1}"),
225            Self::Cpop { rd, rs1 } => write!(f, "cpop {rd}, {rs1}"),
226            Self::Cpopw { rd, rs1 } => write!(f, "cpopw {rd}, {rs1}"),
227            Self::Max { rd, rs1, rs2 } => write!(f, "max {rd}, {rs1}, {rs2}"),
228            Self::Maxu { rd, rs1, rs2 } => write!(f, "maxu {rd}, {rs1}, {rs2}"),
229            Self::Min { rd, rs1, rs2 } => write!(f, "min {rd}, {rs1}, {rs2}"),
230            Self::Minu { rd, rs1, rs2 } => write!(f, "minu {rd}, {rs1}, {rs2}"),
231            Self::Sextb { rd, rs1 } => write!(f, "sext.b {rd}, {rs1}"),
232            Self::Sexth { rd, rs1 } => write!(f, "sext.h {rd}, {rs1}"),
233            Self::Zexth { rd, rs1 } => write!(f, "zext.h {rd}, {rs1}"),
234            Self::Rol { rd, rs1, rs2 } => write!(f, "rol {rd}, {rs1}, {rs2}"),
235            Self::Rolw { rd, rs1, rs2 } => write!(f, "rolw {rd}, {rs1}, {rs2}"),
236            Self::Ror { rd, rs1, rs2 } => write!(f, "ror {rd}, {rs1}, {rs2}"),
237            Self::Rori { rd, rs1, shamt } => write!(f, "rori {rd}, {rs1}, {shamt}"),
238            Self::Roriw { rd, rs1, shamt } => write!(f, "roriw {rd}, {rs1}, {shamt}"),
239            Self::Rorw { rd, rs1, rs2 } => write!(f, "rorw {rd}, {rs1}, {rs2}"),
240            Self::Orcb { rd, rs1 } => write!(f, "orc.b {rd}, {rs1}"),
241            Self::Rev8 { rd, rs1 } => write!(f, "rev8 {rd}, {rs1}"),
242        }
243    }
244}