1#[cfg(test)]
4mod tests;
5
6use crate::instructions::Instruction;
7use crate::instructions::rv32::a::zaamo::Rv32ZaamoInstruction;
8use crate::registers::general_purpose::Register;
9use ab_riscv_macros::instruction;
10use core::fmt;
11
12#[instruction(inherit = [Rv32ZaamoInstruction])]
14#[derive(Debug, Clone, Copy)]
15#[derive_const(PartialEq, Eq)]
16#[rustfmt::skip]
17pub enum Rv32ZabhaInstruction<Reg> {
18 AmoswapB { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
19 AmoswapH { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
20 AmoaddB { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
21 AmoaddH { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
22 AmoxorB { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
23 AmoxorH { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
24 AmoandB { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
25 AmoandH { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
26 AmoorB { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
27 AmoorH { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
28 AmominB { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
29 AmominH { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
30 AmomaxB { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
31 AmomaxH { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
32 AmominuB { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
33 AmominuH { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
34 AmomaxuB { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
35 AmomaxuH { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
36 #[instruction(if = [Rv32ZacasInstruction])]
38 AmocasB { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
39 #[instruction(if = [Rv32ZacasInstruction])]
41 AmocasH { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
42}
43
44#[instruction]
45const impl<Reg> Instruction for Rv32ZabhaInstruction<Reg>
46where
47 Reg: [const] Register<Type = u32>,
48{
49 type Reg = Reg;
50
51 #[inline(always)]
52 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
53 fn try_decode(instruction: u32) -> Option<Self> {
54 let opcode = (instruction & 0b111_1111) as u8;
55 let rd_bits = ((instruction >> 7) & 0x1f) as u8;
56 let funct3 = ((instruction >> 12) & 0b111) as u8;
57 let rs1_bits = ((instruction >> 15) & 0x1f) as u8;
58 let rs2_bits = ((instruction >> 20) & 0x1f) as u8;
59 let funct7 = ((instruction >> 25) & 0b111_1111) as u8;
60
61 match (opcode, funct3) {
62 (0b010_1111, 0b000 | 0b001) => {
64 let rd = Reg::from_bits(rd_bits)?;
65 let rs1 = Reg::from_bits(rs1_bits)?;
66 let rs2 = Reg::from_bits(rs2_bits)?;
67 let funct5 = funct7 >> 2;
68 let aq = (funct7 & 0b10) != 0;
69 let rl = (funct7 & 0b01) != 0;
70
71 if funct3 == 0b000 {
72 match funct5 {
73 0b00001 => Some(Self::AmoswapB {
74 rd,
75 rs1,
76 rs2,
77 aq,
78 rl,
79 }),
80 0b00000 => Some(Self::AmoaddB {
81 rd,
82 rs1,
83 rs2,
84 aq,
85 rl,
86 }),
87 0b00100 => Some(Self::AmoxorB {
88 rd,
89 rs1,
90 rs2,
91 aq,
92 rl,
93 }),
94 0b01100 => Some(Self::AmoandB {
95 rd,
96 rs1,
97 rs2,
98 aq,
99 rl,
100 }),
101 0b01000 => Some(Self::AmoorB {
102 rd,
103 rs1,
104 rs2,
105 aq,
106 rl,
107 }),
108 0b10000 => Some(Self::AmominB {
109 rd,
110 rs1,
111 rs2,
112 aq,
113 rl,
114 }),
115 0b10100 => Some(Self::AmomaxB {
116 rd,
117 rs1,
118 rs2,
119 aq,
120 rl,
121 }),
122 0b11000 => Some(Self::AmominuB {
123 rd,
124 rs1,
125 rs2,
126 aq,
127 rl,
128 }),
129 0b11100 => Some(Self::AmomaxuB {
130 rd,
131 rs1,
132 rs2,
133 aq,
134 rl,
135 }),
136 0b00101 => Some(Self::AmocasB {
137 rd,
138 rs1,
139 rs2,
140 aq,
141 rl,
142 }),
143 _ => None,
144 }
145 } else {
146 match funct5 {
147 0b00001 => Some(Self::AmoswapH {
148 rd,
149 rs1,
150 rs2,
151 aq,
152 rl,
153 }),
154 0b00000 => Some(Self::AmoaddH {
155 rd,
156 rs1,
157 rs2,
158 aq,
159 rl,
160 }),
161 0b00100 => Some(Self::AmoxorH {
162 rd,
163 rs1,
164 rs2,
165 aq,
166 rl,
167 }),
168 0b01100 => Some(Self::AmoandH {
169 rd,
170 rs1,
171 rs2,
172 aq,
173 rl,
174 }),
175 0b01000 => Some(Self::AmoorH {
176 rd,
177 rs1,
178 rs2,
179 aq,
180 rl,
181 }),
182 0b10000 => Some(Self::AmominH {
183 rd,
184 rs1,
185 rs2,
186 aq,
187 rl,
188 }),
189 0b10100 => Some(Self::AmomaxH {
190 rd,
191 rs1,
192 rs2,
193 aq,
194 rl,
195 }),
196 0b11000 => Some(Self::AmominuH {
197 rd,
198 rs1,
199 rs2,
200 aq,
201 rl,
202 }),
203 0b11100 => Some(Self::AmomaxuH {
204 rd,
205 rs1,
206 rs2,
207 aq,
208 rl,
209 }),
210 0b00101 => Some(Self::AmocasH {
211 rd,
212 rs1,
213 rs2,
214 aq,
215 rl,
216 }),
217 _ => None,
218 }
219 }
220 }
221 _ => None,
222 }
223 }
224
225 #[inline(always)]
226 fn alignment() -> u8 {
227 align_of::<u32>() as u8
228 }
229
230 #[inline(always)]
231 fn size(&self) -> u8 {
232 size_of::<u32>() as u8
233 }
234}
235
236#[inline(always)]
238fn aq_rl_suffix(aq: &bool, rl: &bool) -> &'static str {
239 match (*aq, *rl) {
240 (false, false) => "",
241 (true, false) => ".aq",
242 (false, true) => ".rl",
243 (true, true) => ".aqrl",
244 }
245}
246
247#[instruction]
248impl<Reg> fmt::Display for Rv32ZabhaInstruction<Reg>
249where
250 Reg: fmt::Display + Copy,
251{
252 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
253 #[rustfmt::skip]
254 match self {
255 Self::AmoswapB { rd, rs1, rs2, aq, rl } => write!(f, "amoswap.b{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
256 Self::AmoswapH { rd, rs1, rs2, aq, rl } => write!(f, "amoswap.h{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
257 Self::AmoaddB { rd, rs1, rs2, aq, rl } => write!(f, "amoadd.b{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
258 Self::AmoaddH { rd, rs1, rs2, aq, rl } => write!(f, "amoadd.h{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
259 Self::AmoxorB { rd, rs1, rs2, aq, rl } => write!(f, "amoxor.b{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
260 Self::AmoxorH { rd, rs1, rs2, aq, rl } => write!(f, "amoxor.h{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
261 Self::AmoandB { rd, rs1, rs2, aq, rl } => write!(f, "amoand.b{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
262 Self::AmoandH { rd, rs1, rs2, aq, rl } => write!(f, "amoand.h{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
263 Self::AmoorB { rd, rs1, rs2, aq, rl } => write!(f, "amoor.b{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
264 Self::AmoorH { rd, rs1, rs2, aq, rl } => write!(f, "amoor.h{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
265 Self::AmominB { rd, rs1, rs2, aq, rl } => write!(f, "amomin.b{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
266 Self::AmominH { rd, rs1, rs2, aq, rl } => write!(f, "amomin.h{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
267 Self::AmomaxB { rd, rs1, rs2, aq, rl } => write!(f, "amomax.b{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
268 Self::AmomaxH { rd, rs1, rs2, aq, rl } => write!(f, "amomax.h{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
269 Self::AmominuB { rd, rs1, rs2, aq, rl } => write!(f, "amominu.b{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
270 Self::AmominuH { rd, rs1, rs2, aq, rl } => write!(f, "amominu.h{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
271 Self::AmomaxuB { rd, rs1, rs2, aq, rl } => write!(f, "amomaxu.b{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
272 Self::AmomaxuH { rd, rs1, rs2, aq, rl } => write!(f, "amomaxu.h{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
273 Self::AmocasB { rd, rs1, rs2, aq, rl } => write!(f, "amocas.b{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
274 Self::AmocasH { rd, rs1, rs2, aq, rl } => write!(f, "amocas.h{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
275 }
276 }
277}