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, Hart> ExecutableInstructionOperands for Rv64ZaamoInstruction<Hart>
18where
19 Reg: Register<Type = u64>,
20 Hart: HartConfig<Reg = Reg>,
21{
22}
23
24#[instruction_execution]
25const impl<Reg, Hart, Env> ExecutableInstructionCsr<Env> for Rv64ZaamoInstruction<Hart>
26where
27 Reg: Register<Type = u64>,
28 Hart: HartConfig<Reg = Reg>,
29{
30}
31
32#[instruction_execution]
33const impl<Reg, Hart, Regs, Env, Memory, PC> ExecutableInstruction<Regs, Env, Memory, PC>
34 for Rv64ZaamoInstruction<Hart>
35where
36 Reg: [const] Register<Type = u64>,
37 Hart: HartConfig<Reg = Reg>,
38 Regs: [const] RegisterFile<Reg>,
39 Memory: [const] VirtualMemory,
40{
41 #[inline(always)]
42 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
43 fn execute(
44 self,
45 Rs1Rs2OperandValues {
46 rs1_value,
47 rs2_value,
48 }: Rs1Rs2OperandValues<Reg::Type>,
49 _regs: &mut Regs,
50 _env: &mut Env,
51 memory: &mut Memory,
52 _program_counter: &PC,
53 ) -> ExecutionResult<Reg> {
54 match self {
55 Self::Amoswap {
56 rd,
57 rs1: _,
58 rs2: _,
59 aq: _,
60 rl: _,
61 } => {
62 if rs1_value / 4096 != (rs1_value + 3) / 4096 {
65 ::core::hint::cold_path();
66 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
67 address: PackedAddress::new(rs1_value),
68 });
69 }
70 let old = amo_helpers::amo_read::<i32, _, _>(memory, rs1_value)?;
71 memory.write(rs1_value, rs2_value as u32)?;
72 ExecutionResult::Continue {
73 rd,
74 value: i64::from(old).cast_unsigned(),
75 }
76 }
77 Self::Amoadd {
78 rd,
79 rs1: _,
80 rs2: _,
81 aq: _,
82 rl: _,
83 } => {
84 if rs1_value / 4096 != (rs1_value + 3) / 4096 {
87 ::core::hint::cold_path();
88 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
89 address: PackedAddress::new(rs1_value),
90 });
91 }
92 let old = amo_helpers::amo_read::<i32, _, _>(memory, rs1_value)?;
93 let new = (old.cast_unsigned()).wrapping_add(rs2_value as u32);
94 memory.write(rs1_value, new)?;
95 ExecutionResult::Continue {
96 rd,
97 value: i64::from(old).cast_unsigned(),
98 }
99 }
100 Self::Amoxor {
101 rd,
102 rs1: _,
103 rs2: _,
104 aq: _,
105 rl: _,
106 } => {
107 if rs1_value / 4096 != (rs1_value + 3) / 4096 {
110 ::core::hint::cold_path();
111 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
112 address: PackedAddress::new(rs1_value),
113 });
114 }
115 let old = amo_helpers::amo_read::<i32, _, _>(memory, rs1_value)?;
116 let new = old.cast_unsigned() ^ (rs2_value as u32);
117 memory.write(rs1_value, new)?;
118 ExecutionResult::Continue {
119 rd,
120 value: i64::from(old).cast_unsigned(),
121 }
122 }
123 Self::Amoand {
124 rd,
125 rs1: _,
126 rs2: _,
127 aq: _,
128 rl: _,
129 } => {
130 if rs1_value / 4096 != (rs1_value + 3) / 4096 {
133 ::core::hint::cold_path();
134 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
135 address: PackedAddress::new(rs1_value),
136 });
137 }
138 let old = amo_helpers::amo_read::<i32, _, _>(memory, rs1_value)?;
139 let new = old.cast_unsigned() & (rs2_value as u32);
140 memory.write(rs1_value, new)?;
141 ExecutionResult::Continue {
142 rd,
143 value: i64::from(old).cast_unsigned(),
144 }
145 }
146 Self::Amoor {
147 rd,
148 rs1: _,
149 rs2: _,
150 aq: _,
151 rl: _,
152 } => {
153 if rs1_value / 4096 != (rs1_value + 3) / 4096 {
156 ::core::hint::cold_path();
157 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
158 address: PackedAddress::new(rs1_value),
159 });
160 }
161 let old = amo_helpers::amo_read::<i32, _, _>(memory, rs1_value)?;
162 let new = old.cast_unsigned() | (rs2_value as u32);
163 memory.write(rs1_value, new)?;
164 ExecutionResult::Continue {
165 rd,
166 value: i64::from(old).cast_unsigned(),
167 }
168 }
169 Self::Amomin {
170 rd,
171 rs1: _,
172 rs2: _,
173 aq: _,
174 rl: _,
175 } => {
176 if rs1_value / 4096 != (rs1_value + 3) / 4096 {
179 ::core::hint::cold_path();
180 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
181 address: PackedAddress::new(rs1_value),
182 });
183 }
184 let old = amo_helpers::amo_read::<i32, _, _>(memory, rs1_value)?;
185 let new = if old < (rs2_value as u32).cast_signed() {
186 old.cast_unsigned()
187 } else {
188 rs2_value as u32
189 };
190 memory.write(rs1_value, new)?;
191 ExecutionResult::Continue {
192 rd,
193 value: i64::from(old).cast_unsigned(),
194 }
195 }
196 Self::Amomax {
197 rd,
198 rs1: _,
199 rs2: _,
200 aq: _,
201 rl: _,
202 } => {
203 if rs1_value / 4096 != (rs1_value + 3) / 4096 {
206 ::core::hint::cold_path();
207 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
208 address: PackedAddress::new(rs1_value),
209 });
210 }
211 let old = amo_helpers::amo_read::<i32, _, _>(memory, rs1_value)?;
212 let new = if old > (rs2_value as u32).cast_signed() {
213 old.cast_unsigned()
214 } else {
215 rs2_value as u32
216 };
217 memory.write(rs1_value, new)?;
218 ExecutionResult::Continue {
219 rd,
220 value: i64::from(old).cast_unsigned(),
221 }
222 }
223 Self::Amominu {
224 rd,
225 rs1: _,
226 rs2: _,
227 aq: _,
228 rl: _,
229 } => {
230 if rs1_value / 4096 != (rs1_value + 3) / 4096 {
233 ::core::hint::cold_path();
234 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
235 address: PackedAddress::new(rs1_value),
236 });
237 }
238 let old = amo_helpers::amo_read::<i32, _, _>(memory, rs1_value)?;
239 let new = if old.cast_unsigned() < (rs2_value as u32) {
240 old.cast_unsigned()
241 } else {
242 rs2_value as u32
243 };
244 memory.write(rs1_value, new)?;
245 ExecutionResult::Continue {
246 rd,
247 value: i64::from(old).cast_unsigned(),
248 }
249 }
250 Self::Amomaxu {
251 rd,
252 rs1: _,
253 rs2: _,
254 aq: _,
255 rl: _,
256 } => {
257 if rs1_value / 4096 != (rs1_value + 3) / 4096 {
260 ::core::hint::cold_path();
261 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
262 address: PackedAddress::new(rs1_value),
263 });
264 }
265 let old = amo_helpers::amo_read::<i32, _, _>(memory, rs1_value)?;
266 let new = if old.cast_unsigned() > (rs2_value as u32) {
267 old.cast_unsigned()
268 } else {
269 rs2_value as u32
270 };
271 memory.write(rs1_value, new)?;
272 ExecutionResult::Continue {
273 rd,
274 value: i64::from(old).cast_unsigned(),
275 }
276 }
277
278 Self::AmoswapD {
279 rd,
280 rs1: _,
281 rs2: _,
282 aq: _,
283 rl: _,
284 } => {
285 if rs1_value / 4096 != (rs1_value + 7) / 4096 {
288 ::core::hint::cold_path();
289 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
290 address: PackedAddress::new(rs1_value),
291 });
292 }
293 let old = amo_helpers::amo_read::<u64, _, _>(memory, rs1_value)?;
294 memory.write(rs1_value, rs2_value)?;
295 ExecutionResult::Continue { rd, value: old }
296 }
297 Self::AmoaddD {
298 rd,
299 rs1: _,
300 rs2: _,
301 aq: _,
302 rl: _,
303 } => {
304 if rs1_value / 4096 != (rs1_value + 7) / 4096 {
307 ::core::hint::cold_path();
308 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
309 address: PackedAddress::new(rs1_value),
310 });
311 }
312 let old = amo_helpers::amo_read::<u64, _, _>(memory, rs1_value)?;
313 memory.write(rs1_value, old.wrapping_add(rs2_value))?;
314 ExecutionResult::Continue { rd, value: old }
315 }
316 Self::AmoxorD {
317 rd,
318 rs1: _,
319 rs2: _,
320 aq: _,
321 rl: _,
322 } => {
323 if rs1_value / 4096 != (rs1_value + 7) / 4096 {
326 ::core::hint::cold_path();
327 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
328 address: PackedAddress::new(rs1_value),
329 });
330 }
331 let old = amo_helpers::amo_read::<u64, _, _>(memory, rs1_value)?;
332 memory.write(rs1_value, old ^ rs2_value)?;
333 ExecutionResult::Continue { rd, value: old }
334 }
335 Self::AmoandD {
336 rd,
337 rs1: _,
338 rs2: _,
339 aq: _,
340 rl: _,
341 } => {
342 if rs1_value / 4096 != (rs1_value + 7) / 4096 {
345 ::core::hint::cold_path();
346 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
347 address: PackedAddress::new(rs1_value),
348 });
349 }
350 let old = amo_helpers::amo_read::<u64, _, _>(memory, rs1_value)?;
351 memory.write(rs1_value, old & rs2_value)?;
352 ExecutionResult::Continue { rd, value: old }
353 }
354 Self::AmoorD {
355 rd,
356 rs1: _,
357 rs2: _,
358 aq: _,
359 rl: _,
360 } => {
361 if rs1_value / 4096 != (rs1_value + 7) / 4096 {
364 ::core::hint::cold_path();
365 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
366 address: PackedAddress::new(rs1_value),
367 });
368 }
369 let old = amo_helpers::amo_read::<u64, _, _>(memory, rs1_value)?;
370 memory.write(rs1_value, old | rs2_value)?;
371 ExecutionResult::Continue { rd, value: old }
372 }
373 Self::AmominD {
374 rd,
375 rs1: _,
376 rs2: _,
377 aq: _,
378 rl: _,
379 } => {
380 if rs1_value / 4096 != (rs1_value + 7) / 4096 {
383 ::core::hint::cold_path();
384 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
385 address: PackedAddress::new(rs1_value),
386 });
387 }
388 let old = amo_helpers::amo_read::<u64, _, _>(memory, rs1_value)?;
389 let new = if old.cast_signed() < rs2_value.cast_signed() {
390 old
391 } else {
392 rs2_value
393 };
394 memory.write(rs1_value, new)?;
395 ExecutionResult::Continue { rd, value: old }
396 }
397 Self::AmomaxD {
398 rd,
399 rs1: _,
400 rs2: _,
401 aq: _,
402 rl: _,
403 } => {
404 if rs1_value / 4096 != (rs1_value + 7) / 4096 {
407 ::core::hint::cold_path();
408 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
409 address: PackedAddress::new(rs1_value),
410 });
411 }
412 let old = amo_helpers::amo_read::<u64, _, _>(memory, rs1_value)?;
413 let new = if old.cast_signed() > rs2_value.cast_signed() {
414 old
415 } else {
416 rs2_value
417 };
418 memory.write(rs1_value, new)?;
419 ExecutionResult::Continue { rd, value: old }
420 }
421 Self::AmominuD {
422 rd,
423 rs1: _,
424 rs2: _,
425 aq: _,
426 rl: _,
427 } => {
428 if rs1_value / 4096 != (rs1_value + 7) / 4096 {
431 ::core::hint::cold_path();
432 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
433 address: PackedAddress::new(rs1_value),
434 });
435 }
436 let old = amo_helpers::amo_read::<u64, _, _>(memory, rs1_value)?;
437 let new = if old < rs2_value { old } else { rs2_value };
438 memory.write(rs1_value, new)?;
439 ExecutionResult::Continue { rd, value: old }
440 }
441 Self::AmomaxuD {
442 rd,
443 rs1: _,
444 rs2: _,
445 aq: _,
446 rl: _,
447 } => {
448 if rs1_value / 4096 != (rs1_value + 7) / 4096 {
451 ::core::hint::cold_path();
452 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
453 address: PackedAddress::new(rs1_value),
454 });
455 }
456 let old = amo_helpers::amo_read::<u64, _, _>(memory, rs1_value)?;
457 let new = if old > rs2_value { old } else { rs2_value };
458 memory.write(rs1_value, new)?;
459 ExecutionResult::Continue { rd, value: old }
460 }
461 }
462 }
463}