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 == 0b001010000111 {
84                            Some(Self::Orcb { rd, rs1 })
85                        } else if funct12 == 0b011010111000 {
86                            Some(Self::Rev8 { rd, rs1 })
87                        } else if funct6 == 0b011000 {
88                            Some(Self::Rori {
89                                rd,
90                                rs1,
91                                shamt: low6,
92                            })
93                        } else {
94                            None
95                        }
96                    }
97                    _ => None,
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                            Some(Self::Rol { rd, rs1, rs2 })
109                        } else {
110                            None
111                        }
112                    }
113                    0b100 => match funct7 {
114                        0b0100000 => Some(Self::Xnor { rd, rs1, rs2 }),
115                        0b0000101 => Some(Self::Min { rd, rs1, rs2 }),
116                        _ => None,
117                    },
118                    0b101 => match funct7 {
119                        0b0110000 => Some(Self::Ror { rd, rs1, rs2 }),
120                        0b0000101 => Some(Self::Minu { rd, rs1, rs2 }),
121                        _ => None,
122                    },
123                    0b110 => match funct7 {
124                        0b0100000 => Some(Self::Orn { rd, rs1, rs2 }),
125                        0b0000101 => Some(Self::Max { rd, rs1, rs2 }),
126                        _ => None,
127                    },
128                    0b111 => match funct7 {
129                        0b0100000 => Some(Self::Andn { rd, rs1, rs2 }),
130                        0b0000101 => Some(Self::Maxu { rd, rs1, rs2 }),
131                        _ => None,
132                    },
133                    _ => None,
134                }
135            }
136            // OP-IMM-32
137            0b0011011 => {
138                let rd = Reg::from_bits(rd_bits)?;
139                let rs1 = Reg::from_bits(rs1_bits)?;
140                match funct3 {
141                    0b001 => {
142                        if funct7 == 0b0110000 {
143                            match rs2_bits {
144                                0 => Some(Self::Clzw { rd, rs1 }),
145                                1 => Some(Self::Ctzw { rd, rs1 }),
146                                2 => Some(Self::Cpopw { rd, rs1 }),
147                                _ => None,
148                            }
149                        } else {
150                            None
151                        }
152                    }
153                    0b101 => {
154                        if funct7 == 0b0110000 {
155                            let shamt = rs2_bits;
156                            Some(Self::Roriw { rd, rs1, shamt })
157                        } else {
158                            None
159                        }
160                    }
161                    _ => None,
162                }
163            }
164            // OP-32
165            0b0111011 => {
166                let rd = Reg::from_bits(rd_bits)?;
167                let rs1 = Reg::from_bits(rs1_bits)?;
168                let rs2 = Reg::from_bits(rs2_bits)?;
169                match funct3 {
170                    0b001 => {
171                        if funct7 == 0b0110000 {
172                            Some(Self::Rolw { rd, rs1, rs2 })
173                        } else {
174                            None
175                        }
176                    }
177                    0b100 => {
178                        if funct7 == 0b0000100 && rs2_bits == 0 {
179                            Some(Self::Zexth { rd, rs1 })
180                        } else {
181                            None
182                        }
183                    }
184                    0b101 => {
185                        if funct7 == 0b0110000 {
186                            Some(Self::Rorw { rd, rs1, rs2 })
187                        } else {
188                            None
189                        }
190                    }
191                    _ => None,
192                }
193            }
194            _ => None,
195        }
196    }
197
198    #[inline(always)]
199    fn alignment() -> u8 {
200        size_of::<u32>() as u8
201    }
202
203    #[inline(always)]
204    fn size(&self) -> u8 {
205        size_of::<u32>() as u8
206    }
207}
208
209impl<Reg> fmt::Display for Rv64ZbbInstruction<Reg>
210where
211    Reg: fmt::Display,
212{
213    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214        match self {
215            Self::Andn { rd, rs1, rs2 } => write!(f, "andn {}, {}, {}", rd, rs1, rs2),
216            Self::Orn { rd, rs1, rs2 } => write!(f, "orn {}, {}, {}", rd, rs1, rs2),
217            Self::Xnor { rd, rs1, rs2 } => write!(f, "xnor {}, {}, {}", rd, rs1, rs2),
218            Self::Clz { rd, rs1 } => write!(f, "clz {}, {}", rd, rs1),
219            Self::Clzw { rd, rs1 } => write!(f, "clzw {}, {}", rd, rs1),
220            Self::Ctz { rd, rs1 } => write!(f, "ctz {}, {}", rd, rs1),
221            Self::Ctzw { rd, rs1 } => write!(f, "ctzw {}, {}", rd, rs1),
222            Self::Cpop { rd, rs1 } => write!(f, "cpop {}, {}", rd, rs1),
223            Self::Cpopw { rd, rs1 } => write!(f, "cpopw {}, {}", rd, rs1),
224            Self::Max { rd, rs1, rs2 } => write!(f, "max {}, {}, {}", rd, rs1, rs2),
225            Self::Maxu { rd, rs1, rs2 } => write!(f, "maxu {}, {}, {}", rd, rs1, rs2),
226            Self::Min { rd, rs1, rs2 } => write!(f, "min {}, {}, {}", rd, rs1, rs2),
227            Self::Minu { rd, rs1, rs2 } => write!(f, "minu {}, {}, {}", rd, rs1, rs2),
228            Self::Sextb { rd, rs1 } => write!(f, "sext.b {}, {}", rd, rs1),
229            Self::Sexth { rd, rs1 } => write!(f, "sext.h {}, {}", rd, rs1),
230            Self::Zexth { rd, rs1 } => write!(f, "zext.h {}, {}", rd, rs1),
231            Self::Rol { rd, rs1, rs2 } => write!(f, "rol {}, {}, {}", rd, rs1, rs2),
232            Self::Rolw { rd, rs1, rs2 } => write!(f, "rolw {}, {}, {}", rd, rs1, rs2),
233            Self::Ror { rd, rs1, rs2 } => write!(f, "ror {}, {}, {}", rd, rs1, rs2),
234            Self::Rori { rd, rs1, shamt } => write!(f, "rori {}, {}, {}", rd, rs1, shamt),
235            Self::Roriw { rd, rs1, shamt } => write!(f, "roriw {}, {}, {}", rd, rs1, shamt),
236            Self::Rorw { rd, rs1, rs2 } => write!(f, "rorw {}, {}, {}", rd, rs1, rs2),
237            Self::Orcb { rd, rs1 } => write!(f, "orc.b {}, {}", rd, rs1),
238            Self::Rev8 { rd, rs1 } => write!(f, "rev8 {}, {}", rd, rs1),
239        }
240    }
241}