ab_riscv_interpreter/rv32/a/
zaamo.rs1#[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 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 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 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 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 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 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 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 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 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}