1#[cfg(test)]
4mod tests;
5
6use crate::hart::HartConfig;
7use crate::instructions::utils::Shamt;
8use crate::instructions::{ImplementedExtension, Instruction, IsaExtension};
9use crate::registers::general_purpose::Register;
10use ab_riscv_macros::instruction;
11use core::fmt;
12
13#[instruction]
17#[derive(Debug, Clone, Copy)]
18#[derive_const(PartialEq, Eq)]
19#[rustfmt::skip]
20pub enum Rv64ZbbZbkbSharedInstruction<Hart>
21where
22 Hart: HartConfig,
23{
24 Andn { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg },
25 Orn { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg },
26 Xnor { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg },
27 Rol { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg },
28 Rolw { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg },
29 Ror { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg },
30 Rori { rd: Hart::Reg, rs1: Hart::Reg, shamt: Shamt<u64> },
31 Roriw { rd: Hart::Reg, rs1: Hart::Reg, shamt: Shamt<u32> },
32 Rorw { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg },
33 Rev8 { rd: Hart::Reg, rs1: Hart::Reg },
34}
35
36#[instruction]
37const impl<Reg, Hart> Instruction for Rv64ZbbZbkbSharedInstruction<Hart>
38where
39 Reg: [const] Register<Type = u64>,
40 Hart: [const] HartConfig<Reg = Reg>,
41{
42 const OWN_ISA_EXTENSIONS: &'static [IsaExtension] = &[];
43
44 const ALIGNMENT: u8 = align_of::<u32>() as u8;
45
46 type Hart = Hart;
47
48 #[inline(always)]
49 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
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 let low6 = ((instruction >> 20) & 0x3f) as u8;
60 let funct12 = ((instruction >> 20) & 0xfff) as u16;
61
62 match opcode {
63 0b001_0011 => {
65 let rd = Reg::from_bits(rd_bits)?;
66 let rs1 = Reg::from_bits(rs1_bits)?;
67 match funct3 {
68 0b101 => {
69 if funct12 == 0b0110_1011_1000 {
70 Some(Self::Rev8 { rd, rs1 })
71 } else if funct6 == 0b01_1000 {
72 Some(Self::Rori {
73 rd,
74 rs1,
75 shamt: Shamt::<u64>::new(low6)?,
76 })
77 } else {
78 None
79 }
80 }
81 _ => None,
82 }
83 }
84 0b011_0011 => {
86 let rd = Reg::from_bits(rd_bits)?;
87 let rs1 = Reg::from_bits(rs1_bits)?;
88 let rs2 = Reg::from_bits(rs2_bits)?;
89 match (funct3, funct7) {
90 (0b001, 0b011_0000) => Some(Self::Rol { rd, rs1, rs2 }),
91 (0b100, 0b010_0000) => Some(Self::Xnor { rd, rs1, rs2 }),
92 (0b101, 0b011_0000) => Some(Self::Ror { rd, rs1, rs2 }),
93 (0b110, 0b010_0000) => Some(Self::Orn { rd, rs1, rs2 }),
94 (0b111, 0b010_0000) => Some(Self::Andn { rd, rs1, rs2 }),
95 _ => None,
96 }
97 }
98 0b001_1011 => {
100 let rd = Reg::from_bits(rd_bits)?;
101 let rs1 = Reg::from_bits(rs1_bits)?;
102 match (funct3, funct7) {
103 (0b101, 0b011_0000) => {
104 let shamt = Shamt::<u32>::new(rs2_bits)?;
105 Some(Self::Roriw { rd, rs1, shamt })
106 }
107 _ => None,
108 }
109 }
110 0b011_1011 => {
112 let rd = Reg::from_bits(rd_bits)?;
113 let rs1 = Reg::from_bits(rs1_bits)?;
114 let rs2 = Reg::from_bits(rs2_bits)?;
115 match (funct3, funct7) {
116 (0b001, 0b011_0000) => Some(Self::Rolw { rd, rs1, rs2 }),
117 (0b101, 0b011_0000) => Some(Self::Rorw { rd, rs1, rs2 }),
118 _ => None,
119 }
120 }
121 _ => None,
122 }
123 }
124
125 #[inline(always)]
126 fn size(&self) -> u8 {
127 size_of::<u32>() as u8
128 }
129}
130
131#[instruction]
132impl<Reg, Hart> fmt::Display for Rv64ZbbZbkbSharedInstruction<Hart>
133where
134 Reg: fmt::Display,
135 Hart: HartConfig<Reg = Reg>,
136{
137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 match self {
139 Self::Andn { rd, rs1, rs2 } => write!(f, "andn {rd}, {rs1}, {rs2}"),
140 Self::Orn { rd, rs1, rs2 } => write!(f, "orn {rd}, {rs1}, {rs2}"),
141 Self::Xnor { rd, rs1, rs2 } => write!(f, "xnor {rd}, {rs1}, {rs2}"),
142 Self::Rol { rd, rs1, rs2 } => write!(f, "rol {rd}, {rs1}, {rs2}"),
143 Self::Rolw { rd, rs1, rs2 } => write!(f, "rolw {rd}, {rs1}, {rs2}"),
144 Self::Ror { rd, rs1, rs2 } => write!(f, "ror {rd}, {rs1}, {rs2}"),
145 Self::Rori { rd, rs1, shamt } => write!(f, "rori {rd}, {rs1}, {shamt}"),
146 Self::Roriw { rd, rs1, shamt } => write!(f, "roriw {rd}, {rs1}, {shamt}"),
147 Self::Rorw { rd, rs1, rs2 } => write!(f, "rorw {rd}, {rs1}, {rs2}"),
148 Self::Rev8 { rd, rs1 } => write!(f, "rev8 {rd}, {rs1}"),
149 }
150 }
151}
152
153#[instruction(
155 reorder = [
156 Andn, Orn, Xnor, Clz, Clzw, Ctz, Ctzw, Cpop, Cpopw, Max, Maxu, Min, Minu, Sextb, Sexth,
157 Zexth, Rol, Rolw, Ror, Rori, Roriw, Rorw, Orcb, Rev8,
158 ],
159 inherit = [Rv64ZbbZbkbSharedInstruction],
160)]
161#[derive(Debug, Clone, Copy)]
162#[derive_const(PartialEq, Eq)]
163#[rustfmt::skip]
164pub enum Rv64ZbbInstruction<Hart>
165where
166 Hart: HartConfig,
167{
168 Clz { rd: Hart::Reg, rs1: Hart::Reg },
170 Clzw { rd: Hart::Reg, rs1: Hart::Reg },
171 Ctz { rd: Hart::Reg, rs1: Hart::Reg },
172 Ctzw { rd: Hart::Reg, rs1: Hart::Reg },
173 Cpop { rd: Hart::Reg, rs1: Hart::Reg },
174 Cpopw { rd: Hart::Reg, rs1: Hart::Reg },
175 Max { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg },
176 Maxu { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg },
177 Min { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg },
178 Minu { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg },
179 Sextb { rd: Hart::Reg, rs1: Hart::Reg },
180 Sexth { rd: Hart::Reg, rs1: Hart::Reg },
181 Zexth { rd: Hart::Reg, rs1: Hart::Reg },
182 Orcb { rd: Hart::Reg, rs1: Hart::Reg },
183}
184
185#[instruction]
186const impl<Reg, Hart> Instruction for Rv64ZbbInstruction<Hart>
187where
188 Reg: [const] Register<Type = u64>,
189 Hart: [const] HartConfig<Reg = Reg>,
190{
191 const OWN_ISA_EXTENSIONS: &'static [IsaExtension] = &[IsaExtension::new("zbb", 1, 0)];
192
193 const ALIGNMENT: u8 = align_of::<u32>() as u8;
194
195 type Hart = Hart;
196
197 #[inline(always)]
198 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
199 fn try_decode(instruction: u32) -> Option<Self> {
200 let opcode = (instruction & 0b111_1111) as u8;
201 let rd_bits = ((instruction >> 7) & 0x1f) as u8;
202 let funct3 = ((instruction >> 12) & 0b111) as u8;
203 let rs1_bits = ((instruction >> 15) & 0x1f) as u8;
204 let rs2_bits = ((instruction >> 20) & 0x1f) as u8;
205 let funct7 = ((instruction >> 25) & 0b111_1111) as u8;
206 let funct6 = ((instruction >> 26) & 0b11_1111) as u8;
207 let low6 = ((instruction >> 20) & 0x3f) as u8;
209 let funct12 = ((instruction >> 20) & 0xfff) as u16;
210
211 match opcode {
212 0b001_0011 => {
214 let rd = Reg::from_bits(rd_bits)?;
215 let rs1 = Reg::from_bits(rs1_bits)?;
216 match funct3 {
217 0b001 => {
218 if funct6 == 0b01_1000 {
219 match low6 {
220 0 => Some(Self::Clz { rd, rs1 }),
221 1 => Some(Self::Ctz { rd, rs1 }),
222 2 => Some(Self::Cpop { rd, rs1 }),
223 4 => Some(Self::Sextb { rd, rs1 }),
224 5 => Some(Self::Sexth { rd, rs1 }),
225 _ => None,
226 }
227 } else {
228 None
229 }
230 }
231 0b101 => {
232 if funct12 == 0b0010_1000_0111 {
233 Some(Self::Orcb { rd, rs1 })
234 } else {
235 None
236 }
237 }
238 _ => None,
239 }
240 }
241 0b011_0011 => {
243 let rd = Reg::from_bits(rd_bits)?;
244 let rs1 = Reg::from_bits(rs1_bits)?;
245 let rs2 = Reg::from_bits(rs2_bits)?;
246 match (funct3, funct7) {
247 (0b100, 0b000_0101) => Some(Self::Min { rd, rs1, rs2 }),
248 (0b101, 0b000_0101) => Some(Self::Minu { rd, rs1, rs2 }),
249 (0b110, 0b000_0101) => Some(Self::Max { rd, rs1, rs2 }),
250 (0b111, 0b000_0101) => Some(Self::Maxu { rd, rs1, rs2 }),
251 _ => None,
252 }
253 }
254 0b001_1011 => {
256 let rd = Reg::from_bits(rd_bits)?;
257 let rs1 = Reg::from_bits(rs1_bits)?;
258 match (funct3, funct7) {
259 (0b001, 0b011_0000) => match rs2_bits {
260 0 => Some(Self::Clzw { rd, rs1 }),
261 1 => Some(Self::Ctzw { rd, rs1 }),
262 2 => Some(Self::Cpopw { rd, rs1 }),
263 _ => None,
264 },
265 _ => None,
266 }
267 }
268 0b011_1011 => {
270 let rd = Reg::from_bits(rd_bits)?;
271 let rs1 = Reg::from_bits(rs1_bits)?;
272 match (funct3, funct7) {
273 (0b100, 0b000_0100) if rs2_bits == 0 => Some(Self::Zexth { rd, rs1 }),
274 _ => None,
275 }
276 }
277 _ => None,
278 }
279 }
280
281 #[inline(always)]
282 fn size(&self) -> u8 {
283 size_of::<u32>() as u8
284 }
285}
286
287#[instruction]
288impl<Reg, Hart> fmt::Display for Rv64ZbbInstruction<Hart>
289where
290 Reg: fmt::Display + Copy,
291 Hart: HartConfig<Reg = Reg>,
292{
293 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
294 match self {
295 Self::Clz { rd, rs1 } => write!(f, "clz {rd}, {rs1}"),
296 Self::Clzw { rd, rs1 } => write!(f, "clzw {rd}, {rs1}"),
297 Self::Ctz { rd, rs1 } => write!(f, "ctz {rd}, {rs1}"),
298 Self::Ctzw { rd, rs1 } => write!(f, "ctzw {rd}, {rs1}"),
299 Self::Cpop { rd, rs1 } => write!(f, "cpop {rd}, {rs1}"),
300 Self::Cpopw { rd, rs1 } => write!(f, "cpopw {rd}, {rs1}"),
301 Self::Max { rd, rs1, rs2 } => write!(f, "max {rd}, {rs1}, {rs2}"),
302 Self::Maxu { rd, rs1, rs2 } => write!(f, "maxu {rd}, {rs1}, {rs2}"),
303 Self::Min { rd, rs1, rs2 } => write!(f, "min {rd}, {rs1}, {rs2}"),
304 Self::Minu { rd, rs1, rs2 } => write!(f, "minu {rd}, {rs1}, {rs2}"),
305 Self::Sextb { rd, rs1 } => write!(f, "sext.b {rd}, {rs1}"),
306 Self::Sexth { rd, rs1 } => write!(f, "sext.h {rd}, {rs1}"),
307 Self::Zexth { rd, rs1 } => write!(f, "zext.h {rd}, {rs1}"),
308 Self::Orcb { rd, rs1 } => write!(f, "orc.b {rd}, {rs1}"),
309 }
310 }
311}