1#[cfg(test)]
4mod tests;
5
6use crate::rv32::a::amo_helpers;
7use crate::{
8 ExecutableInstruction, ExecutableInstructionCsr, ExecutableInstructionOperands, ExecutionError,
9 ExecutionResult, FetchInstructionResult, InstructionFetcher, OpaqueThreadedExecutionResult,
10 PackedAddress, RegisterFile, Rs1Rs2OperandValues, Rs1Rs2Operands,
11 ThreadedExecutableInstruction, ThreadedExecutionResult, VirtualMemory,
12};
13use ab_riscv_macros::instruction_execution;
14use ab_riscv_primitives::prelude::*;
15
16#[instruction_execution]
17const impl<Reg> ExecutableInstructionOperands for Rv32ZabhaInstruction<Reg> where
18 Reg: Register<Type = u32>
19{
20}
21
22#[instruction_execution]
23const impl<Reg, Env> ExecutableInstructionCsr<Env> for Rv32ZabhaInstruction<Reg> where
24 Reg: Register<Type = u32>
25{
26}
27
28#[instruction_execution]
29const impl<Reg, Regs, Env, Memory, PC> ExecutableInstruction<Regs, Env, Memory, PC>
30 for Rv32ZabhaInstruction<Reg>
31where
32 Reg: [const] Register<Type = u32>,
33 Regs: [const] RegisterFile<Reg>,
34 Memory: [const] VirtualMemory,
35{
36 #[inline(always)]
37 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
38 fn execute(
39 self,
40 Rs1Rs2OperandValues {
41 rs1_value,
42 rs2_value,
43 }: Rs1Rs2OperandValues<<Self::Reg as Register>::Type>,
44 regs: &mut Regs,
45 _env: &mut Env,
46 memory: &mut Memory,
47 _program_counter: &mut PC,
48 ) -> ExecutionResult<Self::Reg> {
49 match self {
50 Self::AmoswapB {
51 rd,
52 rs1: _,
53 rs2: _,
54 aq: _,
55 rl: _,
56 } => {
57 let old = amo_helpers::amo_read::<i8, _, _>(memory, u64::from(rs1_value))?;
58 memory.write(u64::from(rs1_value), rs2_value as u8)?;
59 ExecutionResult::Continue {
60 rd,
61 value: i32::from(old).cast_unsigned(),
62 }
63 }
64 Self::AmoswapH {
65 rd,
66 rs1: _,
67 rs2: _,
68 aq: _,
69 rl: _,
70 } => {
71 if rs1_value / 4096 != (rs1_value + 1) / 4096 {
74 ::core::hint::cold_path();
75 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
76 address: PackedAddress::new(u64::from(rs1_value)),
77 });
78 }
79 let old = amo_helpers::amo_read::<i16, _, _>(memory, u64::from(rs1_value))?;
80 memory.write(u64::from(rs1_value), rs2_value as u16)?;
81 ExecutionResult::Continue {
82 rd,
83 value: i32::from(old).cast_unsigned(),
84 }
85 }
86 Self::AmoaddB {
87 rd,
88 rs1: _,
89 rs2: _,
90 aq: _,
91 rl: _,
92 } => {
93 let old = amo_helpers::amo_read::<i8, _, _>(memory, u64::from(rs1_value))?;
94 let new = old.cast_unsigned().wrapping_add(rs2_value as u8);
95 memory.write(u64::from(rs1_value), new)?;
96 ExecutionResult::Continue {
97 rd,
98 value: i32::from(old).cast_unsigned(),
99 }
100 }
101 Self::AmoaddH {
102 rd,
103 rs1: _,
104 rs2: _,
105 aq: _,
106 rl: _,
107 } => {
108 if rs1_value / 4096 != (rs1_value + 1) / 4096 {
111 ::core::hint::cold_path();
112 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
113 address: PackedAddress::new(u64::from(rs1_value)),
114 });
115 }
116 let old = amo_helpers::amo_read::<i16, _, _>(memory, u64::from(rs1_value))?;
117 let new = old.cast_unsigned().wrapping_add(rs2_value as u16);
118 memory.write(u64::from(rs1_value), new)?;
119 ExecutionResult::Continue {
120 rd,
121 value: i32::from(old).cast_unsigned(),
122 }
123 }
124 Self::AmoxorB {
125 rd,
126 rs1: _,
127 rs2: _,
128 aq: _,
129 rl: _,
130 } => {
131 let old = amo_helpers::amo_read::<i8, _, _>(memory, u64::from(rs1_value))?;
132 let new = old.cast_unsigned() ^ (rs2_value as u8);
133 memory.write(u64::from(rs1_value), new)?;
134 ExecutionResult::Continue {
135 rd,
136 value: i32::from(old).cast_unsigned(),
137 }
138 }
139 Self::AmoxorH {
140 rd,
141 rs1: _,
142 rs2: _,
143 aq: _,
144 rl: _,
145 } => {
146 if rs1_value / 4096 != (rs1_value + 1) / 4096 {
149 ::core::hint::cold_path();
150 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
151 address: PackedAddress::new(u64::from(rs1_value)),
152 });
153 }
154 let old = amo_helpers::amo_read::<i16, _, _>(memory, u64::from(rs1_value))?;
155 let new = old.cast_unsigned() ^ (rs2_value as u16);
156 memory.write(u64::from(rs1_value), new)?;
157 ExecutionResult::Continue {
158 rd,
159 value: i32::from(old).cast_unsigned(),
160 }
161 }
162 Self::AmoandB {
163 rd,
164 rs1: _,
165 rs2: _,
166 aq: _,
167 rl: _,
168 } => {
169 let old = amo_helpers::amo_read::<i8, _, _>(memory, u64::from(rs1_value))?;
170 let new = old.cast_unsigned() & (rs2_value as u8);
171 memory.write(u64::from(rs1_value), new)?;
172 ExecutionResult::Continue {
173 rd,
174 value: i32::from(old).cast_unsigned(),
175 }
176 }
177 Self::AmoandH {
178 rd,
179 rs1: _,
180 rs2: _,
181 aq: _,
182 rl: _,
183 } => {
184 if rs1_value / 4096 != (rs1_value + 1) / 4096 {
187 ::core::hint::cold_path();
188 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
189 address: PackedAddress::new(u64::from(rs1_value)),
190 });
191 }
192 let old = amo_helpers::amo_read::<i16, _, _>(memory, u64::from(rs1_value))?;
193 let new = old.cast_unsigned() & (rs2_value as u16);
194 memory.write(u64::from(rs1_value), new)?;
195 ExecutionResult::Continue {
196 rd,
197 value: i32::from(old).cast_unsigned(),
198 }
199 }
200 Self::AmoorB {
201 rd,
202 rs1: _,
203 rs2: _,
204 aq: _,
205 rl: _,
206 } => {
207 let old = amo_helpers::amo_read::<i8, _, _>(memory, u64::from(rs1_value))?;
208 let new = old.cast_unsigned() | (rs2_value as u8);
209 memory.write(u64::from(rs1_value), new)?;
210 ExecutionResult::Continue {
211 rd,
212 value: i32::from(old).cast_unsigned(),
213 }
214 }
215 Self::AmoorH {
216 rd,
217 rs1: _,
218 rs2: _,
219 aq: _,
220 rl: _,
221 } => {
222 if rs1_value / 4096 != (rs1_value + 1) / 4096 {
225 ::core::hint::cold_path();
226 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
227 address: PackedAddress::new(u64::from(rs1_value)),
228 });
229 }
230 let old = amo_helpers::amo_read::<i16, _, _>(memory, u64::from(rs1_value))?;
231 let new = old.cast_unsigned() | (rs2_value as u16);
232 memory.write(u64::from(rs1_value), new)?;
233 ExecutionResult::Continue {
234 rd,
235 value: i32::from(old).cast_unsigned(),
236 }
237 }
238 Self::AmominB {
239 rd,
240 rs1: _,
241 rs2: _,
242 aq: _,
243 rl: _,
244 } => {
245 let old = amo_helpers::amo_read::<i8, _, _>(memory, u64::from(rs1_value))?;
246 let new = if old < (rs2_value as u8).cast_signed() {
247 old.cast_unsigned()
248 } else {
249 rs2_value as u8
250 };
251 memory.write(u64::from(rs1_value), new)?;
252 ExecutionResult::Continue {
253 rd,
254 value: i32::from(old).cast_unsigned(),
255 }
256 }
257 Self::AmominH {
258 rd,
259 rs1: _,
260 rs2: _,
261 aq: _,
262 rl: _,
263 } => {
264 if rs1_value / 4096 != (rs1_value + 1) / 4096 {
267 ::core::hint::cold_path();
268 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
269 address: PackedAddress::new(u64::from(rs1_value)),
270 });
271 }
272 let old = amo_helpers::amo_read::<i16, _, _>(memory, u64::from(rs1_value))?;
273 let new = if old < (rs2_value as u16).cast_signed() {
274 old.cast_unsigned()
275 } else {
276 rs2_value as u16
277 };
278 memory.write(u64::from(rs1_value), new)?;
279 ExecutionResult::Continue {
280 rd,
281 value: i32::from(old).cast_unsigned(),
282 }
283 }
284 Self::AmomaxB {
285 rd,
286 rs1: _,
287 rs2: _,
288 aq: _,
289 rl: _,
290 } => {
291 let old = amo_helpers::amo_read::<i8, _, _>(memory, u64::from(rs1_value))?;
292 let new = if old > (rs2_value as u8).cast_signed() {
293 old.cast_unsigned()
294 } else {
295 rs2_value as u8
296 };
297 memory.write(u64::from(rs1_value), new)?;
298 ExecutionResult::Continue {
299 rd,
300 value: i32::from(old).cast_unsigned(),
301 }
302 }
303 Self::AmomaxH {
304 rd,
305 rs1: _,
306 rs2: _,
307 aq: _,
308 rl: _,
309 } => {
310 if rs1_value / 4096 != (rs1_value + 1) / 4096 {
313 ::core::hint::cold_path();
314 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
315 address: PackedAddress::new(u64::from(rs1_value)),
316 });
317 }
318 let old = amo_helpers::amo_read::<i16, _, _>(memory, u64::from(rs1_value))?;
319 let new = if old > (rs2_value as u16).cast_signed() {
320 old.cast_unsigned()
321 } else {
322 rs2_value as u16
323 };
324 memory.write(u64::from(rs1_value), new)?;
325 ExecutionResult::Continue {
326 rd,
327 value: i32::from(old).cast_unsigned(),
328 }
329 }
330 Self::AmominuB {
331 rd,
332 rs1: _,
333 rs2: _,
334 aq: _,
335 rl: _,
336 } => {
337 let old = amo_helpers::amo_read::<i8, _, _>(memory, u64::from(rs1_value))?;
338 let new = if old.cast_unsigned() < (rs2_value as u8) {
339 old.cast_unsigned()
340 } else {
341 rs2_value as u8
342 };
343 memory.write(u64::from(rs1_value), new)?;
344 ExecutionResult::Continue {
345 rd,
346 value: i32::from(old).cast_unsigned(),
347 }
348 }
349 Self::AmominuH {
350 rd,
351 rs1: _,
352 rs2: _,
353 aq: _,
354 rl: _,
355 } => {
356 if rs1_value / 4096 != (rs1_value + 1) / 4096 {
359 ::core::hint::cold_path();
360 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
361 address: PackedAddress::new(u64::from(rs1_value)),
362 });
363 }
364 let old = amo_helpers::amo_read::<i16, _, _>(memory, u64::from(rs1_value))?;
365 let new = if old.cast_unsigned() < (rs2_value as u16) {
366 old.cast_unsigned()
367 } else {
368 rs2_value as u16
369 };
370 memory.write(u64::from(rs1_value), new)?;
371 ExecutionResult::Continue {
372 rd,
373 value: i32::from(old).cast_unsigned(),
374 }
375 }
376 Self::AmomaxuB {
377 rd,
378 rs1: _,
379 rs2: _,
380 aq: _,
381 rl: _,
382 } => {
383 let old = amo_helpers::amo_read::<i8, _, _>(memory, u64::from(rs1_value))?;
384 let new = if old.cast_unsigned() > (rs2_value as u8) {
385 old.cast_unsigned()
386 } else {
387 rs2_value as u8
388 };
389 memory.write(u64::from(rs1_value), new)?;
390 ExecutionResult::Continue {
391 rd,
392 value: i32::from(old).cast_unsigned(),
393 }
394 }
395 Self::AmomaxuH {
396 rd,
397 rs1: _,
398 rs2: _,
399 aq: _,
400 rl: _,
401 } => {
402 if rs1_value / 4096 != (rs1_value + 1) / 4096 {
405 ::core::hint::cold_path();
406 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
407 address: PackedAddress::new(u64::from(rs1_value)),
408 });
409 }
410 let old = amo_helpers::amo_read::<i16, _, _>(memory, u64::from(rs1_value))?;
411 let new = if old.cast_unsigned() > (rs2_value as u16) {
412 old.cast_unsigned()
413 } else {
414 rs2_value as u16
415 };
416 memory.write(u64::from(rs1_value), new)?;
417 ExecutionResult::Continue {
418 rd,
419 value: i32::from(old).cast_unsigned(),
420 }
421 }
422 Self::AmocasB {
423 rd,
424 rs1: _,
425 rs2: _,
426 aq: _,
427 rl: _,
428 } => {
429 let compare = regs.read(rd) as u8;
430 let old = amo_helpers::amo_read::<i8, _, _>(memory, u64::from(rs1_value))?;
431 if old.cast_unsigned() == compare {
432 memory.write(u64::from(rs1_value), rs2_value as u8)?;
433 }
434 ExecutionResult::Continue {
435 rd,
436 value: i32::from(old).cast_unsigned(),
437 }
438 }
439 Self::AmocasH {
440 rd,
441 rs1: _,
442 rs2: _,
443 aq: _,
444 rl: _,
445 } => {
446 let compare = regs.read(rd) as u16;
447 if rs1_value / 4096 != (rs1_value + 1) / 4096 {
450 ::core::hint::cold_path();
451 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
452 address: PackedAddress::new(u64::from(rs1_value)),
453 });
454 }
455 let old = amo_helpers::amo_read::<i16, _, _>(memory, u64::from(rs1_value))?;
456 if old.cast_unsigned() == compare {
457 memory.write(u64::from(rs1_value), rs2_value as u16)?;
458 }
459 ExecutionResult::Continue {
460 rd,
461 value: i32::from(old).cast_unsigned(),
462 }
463 }
464 }
465 }
466}