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 Rv64ZaamoInstruction<Reg> where
18 Reg: Register<Type = u64>
19{
20}
21
22#[instruction_execution]
23const impl<Reg, Env> ExecutableInstructionCsr<Env> for Rv64ZaamoInstruction<Reg> where
24 Reg: Register<Type = u64>
25{
26}
27
28#[instruction_execution]
29const impl<Reg, Regs, Env, Memory, PC> ExecutableInstruction<Regs, Env, Memory, PC>
30 for Rv64ZaamoInstruction<Reg>
31where
32 Reg: [const] Register<Type = u64>,
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::Amoswap {
51 rd,
52 rs1: _,
53 rs2: _,
54 aq: _,
55 rl: _,
56 } => {
57 if rs1_value / 4096 != (rs1_value + 3) / 4096 {
60 ::core::hint::cold_path();
61 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
62 address: PackedAddress::new(rs1_value),
63 });
64 }
65 let old = amo_helpers::amo_read::<i32, _, _>(memory, rs1_value)?;
66 memory.write(rs1_value, rs2_value as u32)?;
67 ExecutionResult::Continue {
68 rd,
69 value: i64::from(old).cast_unsigned(),
70 }
71 }
72 Self::Amoadd {
73 rd,
74 rs1: _,
75 rs2: _,
76 aq: _,
77 rl: _,
78 } => {
79 if rs1_value / 4096 != (rs1_value + 3) / 4096 {
82 ::core::hint::cold_path();
83 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
84 address: PackedAddress::new(rs1_value),
85 });
86 }
87 let old = amo_helpers::amo_read::<i32, _, _>(memory, rs1_value)?;
88 let new = (old.cast_unsigned()).wrapping_add(rs2_value as u32);
89 memory.write(rs1_value, new)?;
90 ExecutionResult::Continue {
91 rd,
92 value: i64::from(old).cast_unsigned(),
93 }
94 }
95 Self::Amoxor {
96 rd,
97 rs1: _,
98 rs2: _,
99 aq: _,
100 rl: _,
101 } => {
102 if rs1_value / 4096 != (rs1_value + 3) / 4096 {
105 ::core::hint::cold_path();
106 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
107 address: PackedAddress::new(rs1_value),
108 });
109 }
110 let old = amo_helpers::amo_read::<i32, _, _>(memory, rs1_value)?;
111 let new = old.cast_unsigned() ^ (rs2_value as u32);
112 memory.write(rs1_value, new)?;
113 ExecutionResult::Continue {
114 rd,
115 value: i64::from(old).cast_unsigned(),
116 }
117 }
118 Self::Amoand {
119 rd,
120 rs1: _,
121 rs2: _,
122 aq: _,
123 rl: _,
124 } => {
125 if rs1_value / 4096 != (rs1_value + 3) / 4096 {
128 ::core::hint::cold_path();
129 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
130 address: PackedAddress::new(rs1_value),
131 });
132 }
133 let old = amo_helpers::amo_read::<i32, _, _>(memory, rs1_value)?;
134 let new = old.cast_unsigned() & (rs2_value as u32);
135 memory.write(rs1_value, new)?;
136 ExecutionResult::Continue {
137 rd,
138 value: i64::from(old).cast_unsigned(),
139 }
140 }
141 Self::Amoor {
142 rd,
143 rs1: _,
144 rs2: _,
145 aq: _,
146 rl: _,
147 } => {
148 if rs1_value / 4096 != (rs1_value + 3) / 4096 {
151 ::core::hint::cold_path();
152 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
153 address: PackedAddress::new(rs1_value),
154 });
155 }
156 let old = amo_helpers::amo_read::<i32, _, _>(memory, rs1_value)?;
157 let new = old.cast_unsigned() | (rs2_value as u32);
158 memory.write(rs1_value, new)?;
159 ExecutionResult::Continue {
160 rd,
161 value: i64::from(old).cast_unsigned(),
162 }
163 }
164 Self::Amomin {
165 rd,
166 rs1: _,
167 rs2: _,
168 aq: _,
169 rl: _,
170 } => {
171 if rs1_value / 4096 != (rs1_value + 3) / 4096 {
174 ::core::hint::cold_path();
175 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
176 address: PackedAddress::new(rs1_value),
177 });
178 }
179 let old = amo_helpers::amo_read::<i32, _, _>(memory, rs1_value)?;
180 let new = if old < (rs2_value as u32).cast_signed() {
181 old.cast_unsigned()
182 } else {
183 rs2_value as u32
184 };
185 memory.write(rs1_value, new)?;
186 ExecutionResult::Continue {
187 rd,
188 value: i64::from(old).cast_unsigned(),
189 }
190 }
191 Self::Amomax {
192 rd,
193 rs1: _,
194 rs2: _,
195 aq: _,
196 rl: _,
197 } => {
198 if rs1_value / 4096 != (rs1_value + 3) / 4096 {
201 ::core::hint::cold_path();
202 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
203 address: PackedAddress::new(rs1_value),
204 });
205 }
206 let old = amo_helpers::amo_read::<i32, _, _>(memory, rs1_value)?;
207 let new = if old > (rs2_value as u32).cast_signed() {
208 old.cast_unsigned()
209 } else {
210 rs2_value as u32
211 };
212 memory.write(rs1_value, new)?;
213 ExecutionResult::Continue {
214 rd,
215 value: i64::from(old).cast_unsigned(),
216 }
217 }
218 Self::Amominu {
219 rd,
220 rs1: _,
221 rs2: _,
222 aq: _,
223 rl: _,
224 } => {
225 if rs1_value / 4096 != (rs1_value + 3) / 4096 {
228 ::core::hint::cold_path();
229 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
230 address: PackedAddress::new(rs1_value),
231 });
232 }
233 let old = amo_helpers::amo_read::<i32, _, _>(memory, rs1_value)?;
234 let new = if old.cast_unsigned() < (rs2_value as u32) {
235 old.cast_unsigned()
236 } else {
237 rs2_value as u32
238 };
239 memory.write(rs1_value, new)?;
240 ExecutionResult::Continue {
241 rd,
242 value: i64::from(old).cast_unsigned(),
243 }
244 }
245 Self::Amomaxu {
246 rd,
247 rs1: _,
248 rs2: _,
249 aq: _,
250 rl: _,
251 } => {
252 if rs1_value / 4096 != (rs1_value + 3) / 4096 {
255 ::core::hint::cold_path();
256 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
257 address: PackedAddress::new(rs1_value),
258 });
259 }
260 let old = amo_helpers::amo_read::<i32, _, _>(memory, rs1_value)?;
261 let new = if old.cast_unsigned() > (rs2_value as u32) {
262 old.cast_unsigned()
263 } else {
264 rs2_value as u32
265 };
266 memory.write(rs1_value, new)?;
267 ExecutionResult::Continue {
268 rd,
269 value: i64::from(old).cast_unsigned(),
270 }
271 }
272
273 Self::AmoswapD {
274 rd,
275 rs1: _,
276 rs2: _,
277 aq: _,
278 rl: _,
279 } => {
280 if rs1_value / 4096 != (rs1_value + 7) / 4096 {
283 ::core::hint::cold_path();
284 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
285 address: PackedAddress::new(rs1_value),
286 });
287 }
288 let old = amo_helpers::amo_read::<u64, _, _>(memory, rs1_value)?;
289 memory.write(rs1_value, rs2_value)?;
290 ExecutionResult::Continue { rd, value: old }
291 }
292 Self::AmoaddD {
293 rd,
294 rs1: _,
295 rs2: _,
296 aq: _,
297 rl: _,
298 } => {
299 if rs1_value / 4096 != (rs1_value + 7) / 4096 {
302 ::core::hint::cold_path();
303 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
304 address: PackedAddress::new(rs1_value),
305 });
306 }
307 let old = amo_helpers::amo_read::<u64, _, _>(memory, rs1_value)?;
308 memory.write(rs1_value, old.wrapping_add(rs2_value))?;
309 ExecutionResult::Continue { rd, value: old }
310 }
311 Self::AmoxorD {
312 rd,
313 rs1: _,
314 rs2: _,
315 aq: _,
316 rl: _,
317 } => {
318 if rs1_value / 4096 != (rs1_value + 7) / 4096 {
321 ::core::hint::cold_path();
322 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
323 address: PackedAddress::new(rs1_value),
324 });
325 }
326 let old = amo_helpers::amo_read::<u64, _, _>(memory, rs1_value)?;
327 memory.write(rs1_value, old ^ rs2_value)?;
328 ExecutionResult::Continue { rd, value: old }
329 }
330 Self::AmoandD {
331 rd,
332 rs1: _,
333 rs2: _,
334 aq: _,
335 rl: _,
336 } => {
337 if rs1_value / 4096 != (rs1_value + 7) / 4096 {
340 ::core::hint::cold_path();
341 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
342 address: PackedAddress::new(rs1_value),
343 });
344 }
345 let old = amo_helpers::amo_read::<u64, _, _>(memory, rs1_value)?;
346 memory.write(rs1_value, old & rs2_value)?;
347 ExecutionResult::Continue { rd, value: old }
348 }
349 Self::AmoorD {
350 rd,
351 rs1: _,
352 rs2: _,
353 aq: _,
354 rl: _,
355 } => {
356 if rs1_value / 4096 != (rs1_value + 7) / 4096 {
359 ::core::hint::cold_path();
360 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
361 address: PackedAddress::new(rs1_value),
362 });
363 }
364 let old = amo_helpers::amo_read::<u64, _, _>(memory, rs1_value)?;
365 memory.write(rs1_value, old | rs2_value)?;
366 ExecutionResult::Continue { rd, value: old }
367 }
368 Self::AmominD {
369 rd,
370 rs1: _,
371 rs2: _,
372 aq: _,
373 rl: _,
374 } => {
375 if rs1_value / 4096 != (rs1_value + 7) / 4096 {
378 ::core::hint::cold_path();
379 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
380 address: PackedAddress::new(rs1_value),
381 });
382 }
383 let old = amo_helpers::amo_read::<u64, _, _>(memory, rs1_value)?;
384 let new = if old.cast_signed() < rs2_value.cast_signed() {
385 old
386 } else {
387 rs2_value
388 };
389 memory.write(rs1_value, new)?;
390 ExecutionResult::Continue { rd, value: old }
391 }
392 Self::AmomaxD {
393 rd,
394 rs1: _,
395 rs2: _,
396 aq: _,
397 rl: _,
398 } => {
399 if rs1_value / 4096 != (rs1_value + 7) / 4096 {
402 ::core::hint::cold_path();
403 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
404 address: PackedAddress::new(rs1_value),
405 });
406 }
407 let old = amo_helpers::amo_read::<u64, _, _>(memory, rs1_value)?;
408 let new = if old.cast_signed() > rs2_value.cast_signed() {
409 old
410 } else {
411 rs2_value
412 };
413 memory.write(rs1_value, new)?;
414 ExecutionResult::Continue { rd, value: old }
415 }
416 Self::AmominuD {
417 rd,
418 rs1: _,
419 rs2: _,
420 aq: _,
421 rl: _,
422 } => {
423 if rs1_value / 4096 != (rs1_value + 7) / 4096 {
426 ::core::hint::cold_path();
427 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
428 address: PackedAddress::new(rs1_value),
429 });
430 }
431 let old = amo_helpers::amo_read::<u64, _, _>(memory, rs1_value)?;
432 let new = if old < rs2_value { old } else { rs2_value };
433 memory.write(rs1_value, new)?;
434 ExecutionResult::Continue { rd, value: old }
435 }
436 Self::AmomaxuD {
437 rd,
438 rs1: _,
439 rs2: _,
440 aq: _,
441 rl: _,
442 } => {
443 if rs1_value / 4096 != (rs1_value + 7) / 4096 {
446 ::core::hint::cold_path();
447 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
448 address: PackedAddress::new(rs1_value),
449 });
450 }
451 let old = amo_helpers::amo_read::<u64, _, _>(memory, rs1_value)?;
452 let new = if old > rs2_value { old } else { rs2_value };
453 memory.write(rs1_value, new)?;
454 ExecutionResult::Continue { rd, value: old }
455 }
456 }
457 }
458}