ab_riscv_interpreter/rv64/
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 Rv64ZacasInstruction<Reg> where
17 Reg: Register<Type = u64>
18{
19}
20
21#[instruction_execution]
22const impl<Reg, Env> ExecutableInstructionCsr<Env> for Rv64ZacasInstruction<Reg> where
23 Reg: Register<Type = u64>
24{
25}
26
27#[instruction_execution]
28const impl<Reg, Regs, Env, Memory, PC> ExecutableInstruction<Regs, Env, Memory, PC>
29 for Rv64ZacasInstruction<Reg>
30where
31 Reg: [const] Register<Type = u64>,
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 = 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) as u32;
67 let old = memory.read::<i32>(addr)?;
68 if old.cast_unsigned() == compare {
69 memory.write(addr, rs2_value as u32)?;
70 }
71 ExecutionResult::Continue {
72 rd,
73 value: i64::from(old).cast_unsigned(),
74 }
75 }
76 Self::AmocasD {
77 rd,
78 rs1: _,
79 rs2: _,
80 aq: _,
81 rl: _,
82 } => {
83 let addr = rs1_value;
84 if addr / 4096 != (addr + 7) / 4096 {
87 ::core::hint::cold_path();
88 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
89 address: PackedAddress::new(addr),
90 });
91 }
92 let compare = regs.read(rd);
93 let old = memory.read::<u64>(addr)?;
94 if old == compare {
95 memory.write(addr, rs2_value)?;
96 }
97 ExecutionResult::Continue { rd, value: old }
98 }
99 Self::AmocasQ {
100 rd,
101 rs1: _,
102 rs2,
103 rd_hi,
104 rs2_hi,
105 aq: _,
106 rl: _,
107 } => {
108 let addr = rs1_value;
109 if addr / 4096 != (addr + 15) / 4096 {
112 ::core::hint::cold_path();
113 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
114 address: PackedAddress::new(addr),
115 });
116 }
117 let compare_lo = regs.read(rd);
122 let compare_hi = if rd == Reg::ZERO { 0 } else { regs.read(rd_hi) };
123 let swap_hi = if rs2 == Reg::ZERO {
124 0
125 } else {
126 regs.read(rs2_hi)
127 };
128 let old_lo = memory.read::<u64>(addr)?;
129 let old_hi = memory.read::<u64>(addr + 8)?;
130 if old_lo == compare_lo && old_hi == compare_hi {
131 memory.write(addr, rs2_value)?;
132 memory.write(addr + 8, swap_hi)?;
133 }
134 if rd != Reg::ZERO {
138 regs.write(rd_hi, old_hi);
139 }
140 ExecutionResult::Continue { rd, value: old_lo }
141 }
142 }
143 }
144}