Skip to main content

ab_riscv_interpreter/rv64/a/
zaamo.rs

1//! RV64 Zaamo extension
2
3#[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                // The 4-byte access must not cross a misaligned atomicity granule (4096 bytes)
58                // boundary
59                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                // The 4-byte access must not cross a misaligned atomicity granule (4096 bytes)
80                // boundary
81                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                // The 4-byte access must not cross a misaligned atomicity granule (4096 bytes)
103                // boundary
104                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                // The 4-byte access must not cross a misaligned atomicity granule (4096 bytes)
126                // boundary
127                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                // The 4-byte access must not cross a misaligned atomicity granule (4096 bytes)
149                // boundary
150                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                // The 4-byte access must not cross a misaligned atomicity granule (4096 bytes)
172                // boundary
173                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                // The 4-byte access must not cross a misaligned atomicity granule (4096 bytes)
199                // boundary
200                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                // The 4-byte access must not cross a misaligned atomicity granule (4096 bytes)
226                // boundary
227                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                // The 4-byte access must not cross a misaligned atomicity granule (4096 bytes)
253                // boundary
254                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                // The 8-byte access must not cross a misaligned atomicity granule (4096 bytes)
281                // boundary
282                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                // The 8-byte access must not cross a misaligned atomicity granule (4096 bytes)
300                // boundary
301                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                // The 8-byte access must not cross a misaligned atomicity granule (4096 bytes)
319                // boundary
320                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                // The 8-byte access must not cross a misaligned atomicity granule (4096 bytes)
338                // boundary
339                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                // The 8-byte access must not cross a misaligned atomicity granule (4096 bytes)
357                // boundary
358                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                // The 8-byte access must not cross a misaligned atomicity granule (4096 bytes)
376                // boundary
377                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                // The 8-byte access must not cross a misaligned atomicity granule (4096 bytes)
400                // boundary
401                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                // The 8-byte access must not cross a misaligned atomicity granule (4096 bytes)
424                // boundary
425                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                // The 8-byte access must not cross a misaligned atomicity granule (4096 bytes)
444                // boundary
445                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}