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