1#[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 Rv32ZabhaInstruction<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 Rv32ZabhaInstruction<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 Rv32ZabhaInstruction<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::AmoswapB {
56 rd,
57 rs1: _,
58 rs2: _,
59 aq: _,
60 rl: _,
61 } => {
62 let old = amo_helpers::amo_read::<i8, _, _>(memory, u64::from(rs1_value))?;
63 memory.write(u64::from(rs1_value), rs2_value as u8)?;
64 ExecutionResult::Continue {
65 rd,
66 value: i32::from(old).cast_unsigned(),
67 }
68 }
69 Self::AmoswapH {
70 rd,
71 rs1: _,
72 rs2: _,
73 aq: _,
74 rl: _,
75 } => {
76 if rs1_value / 4096 != (rs1_value + 1) / 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::<i16, _, _>(memory, u64::from(rs1_value))?;
85 memory.write(u64::from(rs1_value), rs2_value as u16)?;
86 ExecutionResult::Continue {
87 rd,
88 value: i32::from(old).cast_unsigned(),
89 }
90 }
91 Self::AmoaddB {
92 rd,
93 rs1: _,
94 rs2: _,
95 aq: _,
96 rl: _,
97 } => {
98 let old = amo_helpers::amo_read::<i8, _, _>(memory, u64::from(rs1_value))?;
99 let new = old.cast_unsigned().wrapping_add(rs2_value as u8);
100 memory.write(u64::from(rs1_value), new)?;
101 ExecutionResult::Continue {
102 rd,
103 value: i32::from(old).cast_unsigned(),
104 }
105 }
106 Self::AmoaddH {
107 rd,
108 rs1: _,
109 rs2: _,
110 aq: _,
111 rl: _,
112 } => {
113 if rs1_value / 4096 != (rs1_value + 1) / 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 = amo_helpers::amo_read::<i16, _, _>(memory, u64::from(rs1_value))?;
122 let new = old.cast_unsigned().wrapping_add(rs2_value as u16);
123 memory.write(u64::from(rs1_value), new)?;
124 ExecutionResult::Continue {
125 rd,
126 value: i32::from(old).cast_unsigned(),
127 }
128 }
129 Self::AmoxorB {
130 rd,
131 rs1: _,
132 rs2: _,
133 aq: _,
134 rl: _,
135 } => {
136 let old = amo_helpers::amo_read::<i8, _, _>(memory, u64::from(rs1_value))?;
137 let new = old.cast_unsigned() ^ (rs2_value as u8);
138 memory.write(u64::from(rs1_value), new)?;
139 ExecutionResult::Continue {
140 rd,
141 value: i32::from(old).cast_unsigned(),
142 }
143 }
144 Self::AmoxorH {
145 rd,
146 rs1: _,
147 rs2: _,
148 aq: _,
149 rl: _,
150 } => {
151 if rs1_value / 4096 != (rs1_value + 1) / 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 = amo_helpers::amo_read::<i16, _, _>(memory, u64::from(rs1_value))?;
160 let new = old.cast_unsigned() ^ (rs2_value as u16);
161 memory.write(u64::from(rs1_value), new)?;
162 ExecutionResult::Continue {
163 rd,
164 value: i32::from(old).cast_unsigned(),
165 }
166 }
167 Self::AmoandB {
168 rd,
169 rs1: _,
170 rs2: _,
171 aq: _,
172 rl: _,
173 } => {
174 let old = amo_helpers::amo_read::<i8, _, _>(memory, u64::from(rs1_value))?;
175 let new = old.cast_unsigned() & (rs2_value as u8);
176 memory.write(u64::from(rs1_value), new)?;
177 ExecutionResult::Continue {
178 rd,
179 value: i32::from(old).cast_unsigned(),
180 }
181 }
182 Self::AmoandH {
183 rd,
184 rs1: _,
185 rs2: _,
186 aq: _,
187 rl: _,
188 } => {
189 if rs1_value / 4096 != (rs1_value + 1) / 4096 {
192 ::core::hint::cold_path();
193 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
194 address: PackedAddress::new(u64::from(rs1_value)),
195 });
196 }
197 let old = amo_helpers::amo_read::<i16, _, _>(memory, u64::from(rs1_value))?;
198 let new = old.cast_unsigned() & (rs2_value as u16);
199 memory.write(u64::from(rs1_value), new)?;
200 ExecutionResult::Continue {
201 rd,
202 value: i32::from(old).cast_unsigned(),
203 }
204 }
205 Self::AmoorB {
206 rd,
207 rs1: _,
208 rs2: _,
209 aq: _,
210 rl: _,
211 } => {
212 let old = amo_helpers::amo_read::<i8, _, _>(memory, u64::from(rs1_value))?;
213 let new = old.cast_unsigned() | (rs2_value as u8);
214 memory.write(u64::from(rs1_value), new)?;
215 ExecutionResult::Continue {
216 rd,
217 value: i32::from(old).cast_unsigned(),
218 }
219 }
220 Self::AmoorH {
221 rd,
222 rs1: _,
223 rs2: _,
224 aq: _,
225 rl: _,
226 } => {
227 if rs1_value / 4096 != (rs1_value + 1) / 4096 {
230 ::core::hint::cold_path();
231 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
232 address: PackedAddress::new(u64::from(rs1_value)),
233 });
234 }
235 let old = amo_helpers::amo_read::<i16, _, _>(memory, u64::from(rs1_value))?;
236 let new = old.cast_unsigned() | (rs2_value as u16);
237 memory.write(u64::from(rs1_value), new)?;
238 ExecutionResult::Continue {
239 rd,
240 value: i32::from(old).cast_unsigned(),
241 }
242 }
243 Self::AmominB {
244 rd,
245 rs1: _,
246 rs2: _,
247 aq: _,
248 rl: _,
249 } => {
250 let old = amo_helpers::amo_read::<i8, _, _>(memory, u64::from(rs1_value))?;
251 let new = if old < (rs2_value as u8).cast_signed() {
252 old.cast_unsigned()
253 } else {
254 rs2_value as u8
255 };
256 memory.write(u64::from(rs1_value), new)?;
257 ExecutionResult::Continue {
258 rd,
259 value: i32::from(old).cast_unsigned(),
260 }
261 }
262 Self::AmominH {
263 rd,
264 rs1: _,
265 rs2: _,
266 aq: _,
267 rl: _,
268 } => {
269 if rs1_value / 4096 != (rs1_value + 1) / 4096 {
272 ::core::hint::cold_path();
273 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
274 address: PackedAddress::new(u64::from(rs1_value)),
275 });
276 }
277 let old = amo_helpers::amo_read::<i16, _, _>(memory, u64::from(rs1_value))?;
278 let new = if old < (rs2_value as u16).cast_signed() {
279 old.cast_unsigned()
280 } else {
281 rs2_value as u16
282 };
283 memory.write(u64::from(rs1_value), new)?;
284 ExecutionResult::Continue {
285 rd,
286 value: i32::from(old).cast_unsigned(),
287 }
288 }
289 Self::AmomaxB {
290 rd,
291 rs1: _,
292 rs2: _,
293 aq: _,
294 rl: _,
295 } => {
296 let old = amo_helpers::amo_read::<i8, _, _>(memory, u64::from(rs1_value))?;
297 let new = if old > (rs2_value as u8).cast_signed() {
298 old.cast_unsigned()
299 } else {
300 rs2_value as u8
301 };
302 memory.write(u64::from(rs1_value), new)?;
303 ExecutionResult::Continue {
304 rd,
305 value: i32::from(old).cast_unsigned(),
306 }
307 }
308 Self::AmomaxH {
309 rd,
310 rs1: _,
311 rs2: _,
312 aq: _,
313 rl: _,
314 } => {
315 if rs1_value / 4096 != (rs1_value + 1) / 4096 {
318 ::core::hint::cold_path();
319 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
320 address: PackedAddress::new(u64::from(rs1_value)),
321 });
322 }
323 let old = amo_helpers::amo_read::<i16, _, _>(memory, u64::from(rs1_value))?;
324 let new = if old > (rs2_value as u16).cast_signed() {
325 old.cast_unsigned()
326 } else {
327 rs2_value as u16
328 };
329 memory.write(u64::from(rs1_value), new)?;
330 ExecutionResult::Continue {
331 rd,
332 value: i32::from(old).cast_unsigned(),
333 }
334 }
335 Self::AmominuB {
336 rd,
337 rs1: _,
338 rs2: _,
339 aq: _,
340 rl: _,
341 } => {
342 let old = amo_helpers::amo_read::<i8, _, _>(memory, u64::from(rs1_value))?;
343 let new = if old.cast_unsigned() < (rs2_value as u8) {
344 old.cast_unsigned()
345 } else {
346 rs2_value as u8
347 };
348 memory.write(u64::from(rs1_value), new)?;
349 ExecutionResult::Continue {
350 rd,
351 value: i32::from(old).cast_unsigned(),
352 }
353 }
354 Self::AmominuH {
355 rd,
356 rs1: _,
357 rs2: _,
358 aq: _,
359 rl: _,
360 } => {
361 if rs1_value / 4096 != (rs1_value + 1) / 4096 {
364 ::core::hint::cold_path();
365 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
366 address: PackedAddress::new(u64::from(rs1_value)),
367 });
368 }
369 let old = amo_helpers::amo_read::<i16, _, _>(memory, u64::from(rs1_value))?;
370 let new = if old.cast_unsigned() < (rs2_value as u16) {
371 old.cast_unsigned()
372 } else {
373 rs2_value as u16
374 };
375 memory.write(u64::from(rs1_value), new)?;
376 ExecutionResult::Continue {
377 rd,
378 value: i32::from(old).cast_unsigned(),
379 }
380 }
381 Self::AmomaxuB {
382 rd,
383 rs1: _,
384 rs2: _,
385 aq: _,
386 rl: _,
387 } => {
388 let old = amo_helpers::amo_read::<i8, _, _>(memory, u64::from(rs1_value))?;
389 let new = if old.cast_unsigned() > (rs2_value as u8) {
390 old.cast_unsigned()
391 } else {
392 rs2_value as u8
393 };
394 memory.write(u64::from(rs1_value), new)?;
395 ExecutionResult::Continue {
396 rd,
397 value: i32::from(old).cast_unsigned(),
398 }
399 }
400 Self::AmomaxuH {
401 rd,
402 rs1: _,
403 rs2: _,
404 aq: _,
405 rl: _,
406 } => {
407 if rs1_value / 4096 != (rs1_value + 1) / 4096 {
410 ::core::hint::cold_path();
411 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
412 address: PackedAddress::new(u64::from(rs1_value)),
413 });
414 }
415 let old = amo_helpers::amo_read::<i16, _, _>(memory, u64::from(rs1_value))?;
416 let new = if old.cast_unsigned() > (rs2_value as u16) {
417 old.cast_unsigned()
418 } else {
419 rs2_value as u16
420 };
421 memory.write(u64::from(rs1_value), new)?;
422 ExecutionResult::Continue {
423 rd,
424 value: i32::from(old).cast_unsigned(),
425 }
426 }
427 Self::AmocasB {
428 rd,
429 rs1: _,
430 rs2: _,
431 aq: _,
432 rl: _,
433 } => {
434 let compare = regs.read(rd) as u8;
435 let old = amo_helpers::amo_read::<i8, _, _>(memory, u64::from(rs1_value))?;
436 if old.cast_unsigned() == compare {
437 memory.write(u64::from(rs1_value), rs2_value as u8)?;
438 }
439 ExecutionResult::Continue {
440 rd,
441 value: i32::from(old).cast_unsigned(),
442 }
443 }
444 Self::AmocasH {
445 rd,
446 rs1: _,
447 rs2: _,
448 aq: _,
449 rl: _,
450 } => {
451 let compare = regs.read(rd) as u16;
452 if rs1_value / 4096 != (rs1_value + 1) / 4096 {
455 ::core::hint::cold_path();
456 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
457 address: PackedAddress::new(u64::from(rs1_value)),
458 });
459 }
460 let old = amo_helpers::amo_read::<i16, _, _>(memory, u64::from(rs1_value))?;
461 if old.cast_unsigned() == compare {
462 memory.write(u64::from(rs1_value), rs2_value as u16)?;
463 }
464 ExecutionResult::Continue {
465 rd,
466 value: i32::from(old).cast_unsigned(),
467 }
468 }
469 }
470 }
471}