Skip to main content

ab_riscv_interpreter/rv32/a/
zaamo.rs

1//! RV32 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 Rv32ZaamoInstruction<Reg> where
18    Reg: Register<Type = u32>
19{
20}
21
22#[instruction_execution]
23const impl<Reg, Env> ExecutableInstructionCsr<Env> for Rv32ZaamoInstruction<Reg> where
24    Reg: Register<Type = u32>
25{
26}
27
28#[instruction_execution]
29const impl<Reg, Regs, Env, Memory, PC> ExecutableInstruction<Regs, Env, Memory, PC>
30    for Rv32ZaamoInstruction<Reg>
31where
32    Reg: [const] Register<Type = u32>,
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(u64::from(rs1_value)),
63                    });
64                }
65                let old = amo_helpers::amo_read::<u32, _, _>(memory, u64::from(rs1_value))?;
66                memory.write(u64::from(rs1_value), rs2_value)?;
67                ExecutionResult::Continue { rd, value: old }
68            }
69            Self::Amoadd {
70                rd,
71                rs1: _,
72                rs2: _,
73                aq: _,
74                rl: _,
75            } => {
76                // The 4-byte access must not cross a misaligned atomicity granule (4096 bytes)
77                // boundary
78                if rs1_value / 4096 != (rs1_value + 3) / 4096 {
79                    ::core::hint::cold_path();
80                    return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
81                        address: PackedAddress::new(u64::from(rs1_value)),
82                    });
83                }
84                let old = amo_helpers::amo_read::<u32, _, _>(memory, u64::from(rs1_value))?;
85                memory.write(u64::from(rs1_value), old.wrapping_add(rs2_value))?;
86                ExecutionResult::Continue { rd, value: old }
87            }
88            Self::Amoxor {
89                rd,
90                rs1: _,
91                rs2: _,
92                aq: _,
93                rl: _,
94            } => {
95                // The 4-byte access must not cross a misaligned atomicity granule (4096 bytes)
96                // boundary
97                if rs1_value / 4096 != (rs1_value + 3) / 4096 {
98                    ::core::hint::cold_path();
99                    return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
100                        address: PackedAddress::new(u64::from(rs1_value)),
101                    });
102                }
103                let old = amo_helpers::amo_read::<u32, _, _>(memory, u64::from(rs1_value))?;
104                memory.write(u64::from(rs1_value), old ^ rs2_value)?;
105                ExecutionResult::Continue { rd, value: old }
106            }
107            Self::Amoand {
108                rd,
109                rs1: _,
110                rs2: _,
111                aq: _,
112                rl: _,
113            } => {
114                // The 4-byte access must not cross a misaligned atomicity granule (4096 bytes)
115                // boundary
116                if rs1_value / 4096 != (rs1_value + 3) / 4096 {
117                    ::core::hint::cold_path();
118                    return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
119                        address: PackedAddress::new(u64::from(rs1_value)),
120                    });
121                }
122                let old = amo_helpers::amo_read::<u32, _, _>(memory, u64::from(rs1_value))?;
123                memory.write(u64::from(rs1_value), old & rs2_value)?;
124                ExecutionResult::Continue { rd, value: old }
125            }
126            Self::Amoor {
127                rd,
128                rs1: _,
129                rs2: _,
130                aq: _,
131                rl: _,
132            } => {
133                // The 4-byte access must not cross a misaligned atomicity granule (4096 bytes)
134                // boundary
135                if rs1_value / 4096 != (rs1_value + 3) / 4096 {
136                    ::core::hint::cold_path();
137                    return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
138                        address: PackedAddress::new(u64::from(rs1_value)),
139                    });
140                }
141                let old = amo_helpers::amo_read::<u32, _, _>(memory, u64::from(rs1_value))?;
142                memory.write(u64::from(rs1_value), old | rs2_value)?;
143                ExecutionResult::Continue { rd, value: old }
144            }
145            Self::Amomin {
146                rd,
147                rs1: _,
148                rs2: _,
149                aq: _,
150                rl: _,
151            } => {
152                // The 4-byte access must not cross a misaligned atomicity granule (4096 bytes)
153                // boundary
154                if rs1_value / 4096 != (rs1_value + 3) / 4096 {
155                    ::core::hint::cold_path();
156                    return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
157                        address: PackedAddress::new(u64::from(rs1_value)),
158                    });
159                }
160                let old = amo_helpers::amo_read::<u32, _, _>(memory, u64::from(rs1_value))?;
161                let new = if old.cast_signed() < rs2_value.cast_signed() {
162                    old
163                } else {
164                    rs2_value
165                };
166                memory.write(u64::from(rs1_value), new)?;
167                ExecutionResult::Continue { rd, value: old }
168            }
169            Self::Amomax {
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(u64::from(rs1_value)),
182                    });
183                }
184                let old = amo_helpers::amo_read::<u32, _, _>(memory, u64::from(rs1_value))?;
185                let new = if old.cast_signed() > rs2_value.cast_signed() {
186                    old
187                } else {
188                    rs2_value
189                };
190                memory.write(u64::from(rs1_value), new)?;
191                ExecutionResult::Continue { rd, value: old }
192            }
193            Self::Amominu {
194                rd,
195                rs1: _,
196                rs2: _,
197                aq: _,
198                rl: _,
199            } => {
200                // The 4-byte access must not cross a misaligned atomicity granule (4096 bytes)
201                // boundary
202                if rs1_value / 4096 != (rs1_value + 3) / 4096 {
203                    ::core::hint::cold_path();
204                    return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
205                        address: PackedAddress::new(u64::from(rs1_value)),
206                    });
207                }
208                let old = amo_helpers::amo_read::<u32, _, _>(memory, u64::from(rs1_value))?;
209                let new = if old < rs2_value { old } else { rs2_value };
210                memory.write(u64::from(rs1_value), new)?;
211                ExecutionResult::Continue { rd, value: old }
212            }
213            Self::Amomaxu {
214                rd,
215                rs1: _,
216                rs2: _,
217                aq: _,
218                rl: _,
219            } => {
220                // The 4-byte access must not cross a misaligned atomicity granule (4096 bytes)
221                // boundary
222                if rs1_value / 4096 != (rs1_value + 3) / 4096 {
223                    ::core::hint::cold_path();
224                    return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
225                        address: PackedAddress::new(u64::from(rs1_value)),
226                    });
227                }
228                let old = amo_helpers::amo_read::<u32, _, _>(memory, u64::from(rs1_value))?;
229                let new = if old > rs2_value { old } else { rs2_value };
230                memory.write(u64::from(rs1_value), new)?;
231                ExecutionResult::Continue { rd, value: old }
232            }
233        }
234    }
235}