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