ab_riscv_primitives/instruction/rv64/b/
zbb.rs

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