Skip to main content

ab_riscv_interpreter/rv32/a/
zaamo.rs

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