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, 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                // The 4-byte access must not cross a misaligned atomicity granule (4096 bytes)
63                // boundary
64                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                // The 4-byte access must not cross a misaligned atomicity granule (4096 bytes)
85                // boundary
86                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                // The 4-byte access must not cross a misaligned atomicity granule (4096 bytes)
108                // boundary
109                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                // The 4-byte access must not cross a misaligned atomicity granule (4096 bytes)
131                // boundary
132                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                // The 4-byte access must not cross a misaligned atomicity granule (4096 bytes)
154                // boundary
155                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                // The 4-byte access must not cross a misaligned atomicity granule (4096 bytes)
177                // boundary
178                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                // The 4-byte access must not cross a misaligned atomicity granule (4096 bytes)
204                // boundary
205                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                // The 4-byte access must not cross a misaligned atomicity granule (4096 bytes)
231                // boundary
232                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                // The 4-byte access must not cross a misaligned atomicity granule (4096 bytes)
258                // boundary
259                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                // The 8-byte access must not cross a misaligned atomicity granule (4096 bytes)
286                // boundary
287                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                // The 8-byte access must not cross a misaligned atomicity granule (4096 bytes)
305                // boundary
306                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                // The 8-byte access must not cross a misaligned atomicity granule (4096 bytes)
324                // boundary
325                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                // The 8-byte access must not cross a misaligned atomicity granule (4096 bytes)
343                // boundary
344                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                // The 8-byte access must not cross a misaligned atomicity granule (4096 bytes)
362                // boundary
363                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                // The 8-byte access must not cross a misaligned atomicity granule (4096 bytes)
381                // boundary
382                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                // The 8-byte access must not cross a misaligned atomicity granule (4096 bytes)
405                // boundary
406                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                // The 8-byte access must not cross a misaligned atomicity granule (4096 bytes)
429                // boundary
430                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                // The 8-byte access must not cross a misaligned atomicity granule (4096 bytes)
449                // boundary
450                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}