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