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