ab_riscv_interpreter/rv32/
zacas.rs1#[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> ExecutableInstructionOperands for Rv32ZacasInstruction<Reg> where
18 Reg: Register<Type = u32>
19{
20}
21
22#[instruction_execution]
23const impl<Reg, Env> ExecutableInstructionCsr<Env> for Rv32ZacasInstruction<Reg> where
24 Reg: Register<Type = u32>
25{
26}
27
28#[instruction_execution]
29const impl<Reg, Regs, Env, Memory, PC> ExecutableInstruction<Regs, Env, Memory, PC>
30 for Rv32ZacasInstruction<Reg>
31where
32 Reg: [const] Register<Type = u32>,
33 Regs: [const] RegisterFile<Reg>,
34 Memory: [const] VirtualMemory,
35{
36 #[inline(always)]
37 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
38 fn execute(
39 self,
40 Rs1Rs2OperandValues {
41 rs1_value,
42 rs2_value,
43 }: Rs1Rs2OperandValues<<Self::Reg as Register>::Type>,
44 regs: &mut Regs,
45 _env: &mut Env,
46 memory: &mut Memory,
47 _program_counter: &mut PC,
48 ) -> ExecutionResult<Self::Reg> {
49 match self {
50 Self::AmocasW {
51 rd,
52 rs1: _,
53 rs2: _,
54 aq: _,
55 rl: _,
56 } => {
57 let addr = u64::from(rs1_value);
58 if addr / 4096 != (addr + 3) / 4096 {
61 ::core::hint::cold_path();
62 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
63 address: PackedAddress::new(addr),
64 });
65 }
66 let compare = regs.read(rd);
67 let old = amo_helpers::amo_read::<u32, _, _>(memory, addr)?;
68 if old == compare {
69 memory.write(addr, rs2_value)?;
70 }
71 ExecutionResult::Continue { rd, value: old }
72 }
73 Self::AmocasD {
74 rd,
75 rs1: _,
76 rs2,
77 rd_hi,
78 rs2_hi,
79 aq: _,
80 rl: _,
81 } => {
82 let addr = u64::from(rs1_value);
83 if addr / 4096 != (addr + 7) / 4096 {
86 ::core::hint::cold_path();
87 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
88 address: PackedAddress::new(addr),
89 });
90 }
91 let compare_lo = regs.read(rd);
96 let compare_hi = if rd == Reg::ZERO { 0 } else { regs.read(rd_hi) };
97 let swap_hi = if rs2 == Reg::ZERO {
98 0
99 } else {
100 regs.read(rs2_hi)
101 };
102 let old_lo = amo_helpers::amo_read::<u32, _, _>(memory, addr)?;
103 let old_hi = amo_helpers::amo_read::<u32, _, _>(memory, addr + 4)?;
104 if old_lo == compare_lo && old_hi == compare_hi {
105 memory.write(addr, rs2_value)?;
106 memory.write(addr + 4, swap_hi)?;
107 }
108 if rd != Reg::ZERO {
112 regs.write(rd_hi, old_hi);
113 }
114 ExecutionResult::Continue { rd, value: old_lo }
115 }
116 }
117 }
118}