Skip to main content

ab_riscv_interpreter/rv64/a/
zaamo.rs

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