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 Rv32ZbbZbkbSharedInstruction<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 Ror { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg },
29 Rori { rd: Hart::Reg, rs1: Hart::Reg, shamt: Shamt<u32> },
30 Rev8 { rd: Hart::Reg, rs1: Hart::Reg },
31}
32
33#[instruction]
34const impl<Reg, Hart> Instruction for Rv32ZbbZbkbSharedInstruction<Hart>
35where
36 Reg: [const] Register<Type = u32>,
37 Hart: [const] HartConfig<Reg = Reg>,
38{
39 const OWN_ISA_EXTENSIONS: &'static [IsaExtension] = &[];
40
41 const ALIGNMENT: u8 = align_of::<u32>() as u8;
42
43 type Hart = Hart;
44
45 #[inline(always)]
46 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
47 fn try_decode(instruction: u32) -> Option<Self> {
48 let opcode = (instruction & 0b111_1111) as u8;
49 let rd_bits = ((instruction >> 7) & 0x1f) as u8;
50 let funct3 = ((instruction >> 12) & 0b111) as u8;
51 let rs1_bits = ((instruction >> 15) & 0x1f) as u8;
52 let rs2_bits = ((instruction >> 20) & 0x1f) as u8;
53 let funct7 = ((instruction >> 25) & 0b111_1111) as u8;
54 let low5 = ((instruction >> 20) & 0x1f) as u8;
56 let funct12 = ((instruction >> 20) & 0xfff) as u16;
57
58 match opcode {
59 0b001_0011 => {
61 let rd = Reg::from_bits(rd_bits)?;
62 let rs1 = Reg::from_bits(rs1_bits)?;
63 match funct3 {
64 0b101 => {
65 if funct12 == 0b0110_1001_1000 {
69 Some(Self::Rev8 { rd, rs1 })
70 } else if funct7 == 0b011_0000 {
71 Some(Self::Rori {
72 rd,
73 rs1,
74 shamt: Shamt::<u32>::new(low5)?,
75 })
76 } else {
77 None
78 }
79 }
80 _ => None,
81 }
82 }
83 0b011_0011 => {
85 let rd = Reg::from_bits(rd_bits)?;
86 let rs1 = Reg::from_bits(rs1_bits)?;
87 let rs2 = Reg::from_bits(rs2_bits)?;
88 match (funct3, funct7) {
89 (0b001, 0b011_0000) => Some(Self::Rol { rd, rs1, rs2 }),
90 (0b100, 0b010_0000) => Some(Self::Xnor { rd, rs1, rs2 }),
91 (0b101, 0b011_0000) => Some(Self::Ror { rd, rs1, rs2 }),
92 (0b110, 0b010_0000) => Some(Self::Orn { rd, rs1, rs2 }),
93 (0b111, 0b010_0000) => Some(Self::Andn { rd, rs1, rs2 }),
94 _ => None,
95 }
96 }
97 _ => None,
98 }
99 }
100
101 #[inline(always)]
102 fn size(&self) -> u8 {
103 size_of::<u32>() as u8
104 }
105}
106
107#[instruction]
108impl<Reg, Hart> fmt::Display for Rv32ZbbZbkbSharedInstruction<Hart>
109where
110 Reg: fmt::Display,
111 Hart: HartConfig<Reg = Reg>,
112{
113 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114 match self {
115 Self::Andn { rd, rs1, rs2 } => write!(f, "andn {rd}, {rs1}, {rs2}"),
116 Self::Orn { rd, rs1, rs2 } => write!(f, "orn {rd}, {rs1}, {rs2}"),
117 Self::Xnor { rd, rs1, rs2 } => write!(f, "xnor {rd}, {rs1}, {rs2}"),
118 Self::Rol { rd, rs1, rs2 } => write!(f, "rol {rd}, {rs1}, {rs2}"),
119 Self::Ror { rd, rs1, rs2 } => write!(f, "ror {rd}, {rs1}, {rs2}"),
120 Self::Rori { rd, rs1, shamt } => write!(f, "rori {rd}, {rs1}, {shamt}"),
121 Self::Rev8 { rd, rs1 } => write!(f, "rev8 {rd}, {rs1}"),
122 }
123 }
124}
125
126#[instruction(
128 reorder = [
129 Andn, Orn, Xnor, Clz, Ctz, Cpop, Max, Maxu, Min, Minu, Sextb, Sexth, Zexth, Rol, Ror, Rori,
130 Orcb, Rev8,
131 ],
132 inherit = [Rv32ZbbZbkbSharedInstruction],
133)]
134#[derive(Debug, Clone, Copy)]
135#[derive_const(PartialEq, Eq)]
136#[rustfmt::skip]
137pub enum Rv32ZbbInstruction<Hart>
138where
139 Hart: HartConfig,
140{
141 Clz { rd: Hart::Reg, rs1: Hart::Reg },
142 Ctz { rd: Hart::Reg, rs1: Hart::Reg },
143 Cpop { rd: Hart::Reg, rs1: Hart::Reg },
144 Max { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg },
145 Maxu { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg },
146 Min { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg },
147 Minu { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg },
148 Sextb { rd: Hart::Reg, rs1: Hart::Reg },
149 Sexth { rd: Hart::Reg, rs1: Hart::Reg },
150 Zexth { rd: Hart::Reg, rs1: Hart::Reg },
151 Orcb { rd: Hart::Reg, rs1: Hart::Reg },
152}
153
154#[instruction]
155const impl<Reg, Hart> Instruction for Rv32ZbbInstruction<Hart>
156where
157 Reg: [const] Register<Type = u32>,
158 Hart: [const] HartConfig<Reg = Reg>,
159{
160 const OWN_ISA_EXTENSIONS: &'static [IsaExtension] = &[IsaExtension::new("zbb", 1, 0)];
161
162 const ALIGNMENT: u8 = align_of::<u32>() as u8;
163
164 type Hart = Hart;
165
166 #[inline(always)]
167 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
168 fn try_decode(instruction: u32) -> Option<Self> {
169 let opcode = (instruction & 0b111_1111) as u8;
170 let rd_bits = ((instruction >> 7) & 0x1f) as u8;
171 let funct3 = ((instruction >> 12) & 0b111) as u8;
172 let rs1_bits = ((instruction >> 15) & 0x1f) as u8;
173 let rs2_bits = ((instruction >> 20) & 0x1f) as u8;
174 let funct7 = ((instruction >> 25) & 0b111_1111) as u8;
175 let funct12 = ((instruction >> 20) & 0xfff) as u16;
176
177 match opcode {
178 0b001_0011 => {
180 let rd = Reg::from_bits(rd_bits)?;
181 let rs1 = Reg::from_bits(rs1_bits)?;
182 match funct3 {
183 0b001 => {
184 if funct7 == 0b011_0000 {
186 match rs2_bits {
187 0 => Some(Self::Clz { rd, rs1 }),
188 1 => Some(Self::Ctz { rd, rs1 }),
189 2 => Some(Self::Cpop { rd, rs1 }),
190 4 => Some(Self::Sextb { rd, rs1 }),
191 5 => Some(Self::Sexth { rd, rs1 }),
192 _ => None,
193 }
194 } else {
195 None
196 }
197 }
198 0b101 => {
199 if funct12 == 0b0010_1000_0111 {
201 Some(Self::Orcb { rd, rs1 })
202 } else {
203 None
204 }
205 }
206 _ => None,
207 }
208 }
209 0b011_0011 => {
211 let rd = Reg::from_bits(rd_bits)?;
212 let rs1 = Reg::from_bits(rs1_bits)?;
213 let rs2 = Reg::from_bits(rs2_bits)?;
214 match (funct3, funct7) {
215 (0b100, 0b000_0101) => Some(Self::Min { rd, rs1, rs2 }),
216 (0b100, 0b000_0100) if rs2_bits == 0 => Some(Self::Zexth { rd, rs1 }),
218 (0b101, 0b000_0101) => Some(Self::Minu { rd, rs1, rs2 }),
219 (0b110, 0b000_0101) => Some(Self::Max { rd, rs1, rs2 }),
220 (0b111, 0b000_0101) => Some(Self::Maxu { rd, rs1, rs2 }),
221 _ => None,
222 }
223 }
224 _ => None,
225 }
226 }
227
228 #[inline(always)]
229 fn size(&self) -> u8 {
230 size_of::<u32>() as u8
231 }
232}
233
234#[instruction]
235impl<Reg, Hart> fmt::Display for Rv32ZbbInstruction<Hart>
236where
237 Reg: fmt::Display + Copy,
238 Hart: HartConfig<Reg = Reg>,
239{
240 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
241 match self {
242 Self::Clz { rd, rs1 } => write!(f, "clz {rd}, {rs1}"),
243 Self::Ctz { rd, rs1 } => write!(f, "ctz {rd}, {rs1}"),
244 Self::Cpop { rd, rs1 } => write!(f, "cpop {rd}, {rs1}"),
245 Self::Max { rd, rs1, rs2 } => write!(f, "max {rd}, {rs1}, {rs2}"),
246 Self::Maxu { rd, rs1, rs2 } => write!(f, "maxu {rd}, {rs1}, {rs2}"),
247 Self::Min { rd, rs1, rs2 } => write!(f, "min {rd}, {rs1}, {rs2}"),
248 Self::Minu { rd, rs1, rs2 } => write!(f, "minu {rd}, {rs1}, {rs2}"),
249 Self::Sextb { rd, rs1 } => write!(f, "sext.b {rd}, {rs1}"),
250 Self::Sexth { rd, rs1 } => write!(f, "sext.h {rd}, {rs1}"),
251 Self::Zexth { rd, rs1 } => write!(f, "zext.h {rd}, {rs1}"),
252 Self::Orcb { rd, rs1 } => write!(f, "orc.b {rd}, {rs1}"),
253 }
254 }
255}