ab_riscv_interpreter/rv32/
zacas.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 Rv32ZacasInstruction<Reg> where
17 Reg: Register<Type = u32>
18{
19}
20
21#[instruction_execution]
22const impl<Reg, Env> ExecutableInstructionCsr<Env> for Rv32ZacasInstruction<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 Rv32ZacasInstruction<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::AmocasW {
50 rd,
51 rs1: _,
52 rs2: _,
53 aq: _,
54 rl: _,
55 } => {
56 let addr = u64::from(rs1_value);
57 if addr / 4096 != (addr + 3) / 4096 {
60 ::core::hint::cold_path();
61 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
62 address: PackedAddress::new(addr),
63 });
64 }
65 let compare = regs.read(rd);
66 let old = memory.read::<u32>(addr)?;
67 if old == compare {
68 memory.write(addr, rs2_value)?;
69 }
70 ExecutionResult::Continue { rd, value: old }
71 }
72 Self::AmocasD {
73 rd,
74 rs1: _,
75 rs2,
76 rd_hi,
77 rs2_hi,
78 aq: _,
79 rl: _,
80 } => {
81 let addr = u64::from(rs1_value);
82 if addr / 4096 != (addr + 7) / 4096 {
85 ::core::hint::cold_path();
86 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
87 address: PackedAddress::new(addr),
88 });
89 }
90 let compare_lo = regs.read(rd);
95 let compare_hi = if rd == Reg::ZERO { 0 } else { regs.read(rd_hi) };
96 let swap_hi = if rs2 == Reg::ZERO {
97 0
98 } else {
99 regs.read(rs2_hi)
100 };
101 let old_lo = memory.read::<u32>(addr)?;
102 let old_hi = memory.read::<u32>(addr + 4)?;
103 if old_lo == compare_lo && old_hi == compare_hi {
104 memory.write(addr, rs2_value)?;
105 memory.write(addr + 4, swap_hi)?;
106 }
107 if rd != Reg::ZERO {
111 regs.write(rd_hi, old_hi);
112 }
113 ExecutionResult::Continue { rd, value: old_lo }
114 }
115 }
116 }
117}