1#[cfg(test)]
4mod tests;
5pub mod zicsr_helpers;
6
7use crate::{
8 Csrs, ExecutableInstruction, ExecutableInstructionCsr, ExecutableInstructionOperands,
9 ExecutionError, ExecutionResult, FetchInstructionResult, InstructionFetcher,
10 OpaqueThreadedExecutionResult, RegisterFile, Rs1Rs2OperandValues, Rs1Rs2Operands,
11 ThreadedExecutableInstruction, ThreadedExecutionResult,
12};
13use ab_riscv_macros::instruction_execution;
14use ab_riscv_primitives::prelude::*;
15
16#[instruction_execution]
17const impl<Reg> ExecutableInstructionOperands for ZicsrInstruction<Reg> where Reg: Register {}
18
19#[instruction_execution]
20const impl<Reg, Env> ExecutableInstructionCsr<Env> for ZicsrInstruction<Reg> where Reg: Register {}
21
22#[instruction_execution]
23const impl<Reg, Regs, Env, Memory, PC> ExecutableInstruction<Regs, Env, Memory, PC>
24 for ZicsrInstruction<Reg>
25where
26 Reg: [const] Register,
27 Regs: [const] RegisterFile<Reg>,
28 Env: [const] Csrs<Reg>,
29{
30 #[inline(always)]
31 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
32 fn execute(
33 self,
34 Rs1Rs2OperandValues {
35 rs1_value,
36 rs2_value: _,
37 }: Rs1Rs2OperandValues<<Self::Reg as Register>::Type>,
38 _regs: &mut Regs,
39 env: &mut Env,
40 _memory: &mut Memory,
41 _program_counter: &mut PC,
42 ) -> ExecutionResult<Self::Reg> {
43 match self {
44 Self::Csrrw {
49 rd,
50 rs1: _,
51 csr_index,
52 } => {
53 let csr_is_read_only = (csr_index >> 10) == 0b11;
54 if csr_is_read_only {
55 ::core::hint::cold_path();
56 return ExecutionResult::Err(ExecutionError::CsrReadOnly { csr_index });
57 }
58 zicsr_helpers::check_csr_privilege_level(env, csr_index)?;
59
60 let write_value = rs1_value;
61
62 let read_output = if rd == Reg::ZERO {
64 ::core::hint::cold_path();
65 Reg::Type::from(0u8)
66 } else {
67 let read_value = match env.read_csr(csr_index) {
68 Ok(read_value) => read_value,
69 Err(err) => {
70 ::core::hint::cold_path();
71 return ExecutionResult::Err(ExecutionError::from(err));
72 }
73 };
74 zicsr_helpers::process_csr_read::<Reg, Env, Self>(
75 env, csr_index, true, read_value,
76 )?
77 };
78
79 let write_output = zicsr_helpers::process_csr_write::<Reg, Env, Self>(
80 env,
81 csr_index,
82 write_value,
83 )?;
84 match env.write_csr(csr_index, write_output) {
85 Ok(()) => ExecutionResult::Continue {
86 rd,
87 value: read_output,
88 },
89 Err(err) => {
90 ::core::hint::cold_path();
91 ExecutionResult::Err(ExecutionError::from(err))
92 }
93 }
94 }
95
96 Self::Csrrs { rd, rs1, csr_index } => {
101 let csr_is_read_only = (csr_index >> 10) == 0b11;
102 if rs1 != Reg::ZERO && csr_is_read_only {
103 ::core::hint::cold_path();
104 return ExecutionResult::Err(ExecutionError::CsrReadOnly { csr_index });
105 }
106 zicsr_helpers::check_csr_privilege_level(env, csr_index)?;
107
108 let read_value = match env.read_csr(csr_index) {
109 Ok(read_value) => read_value,
110 Err(error) => {
111 ::core::hint::cold_path();
112 return ExecutionResult::Err(ExecutionError::from(error));
113 }
114 };
115 let read_output = zicsr_helpers::process_csr_read::<Reg, Env, Self>(
116 env,
117 csr_index,
118 rs1 != Reg::ZERO,
119 read_value,
120 )?;
121
122 if rs1 == Reg::ZERO {
123 ::core::hint::cold_path();
124 } else {
125 let write_value = read_value | rs1_value;
126 let write_output = zicsr_helpers::process_csr_write::<Reg, Env, Self>(
127 env,
128 csr_index,
129 write_value,
130 )?;
131 if let Err(error) = env.write_csr(csr_index, write_output) {
132 ::core::hint::cold_path();
133 return ExecutionResult::Err(ExecutionError::from(error));
134 }
135 }
136 ExecutionResult::Continue {
137 rd,
138 value: read_output,
139 }
140 }
141
142 Self::Csrrc { rd, rs1, csr_index } => {
147 let csr_is_read_only = (csr_index >> 10) == 0b11;
148 if rs1 != Reg::ZERO && csr_is_read_only {
149 ::core::hint::cold_path();
150 return ExecutionResult::Err(ExecutionError::CsrReadOnly { csr_index });
151 }
152 zicsr_helpers::check_csr_privilege_level(env, csr_index)?;
153
154 let read_value = match env.read_csr(csr_index) {
155 Ok(read_value) => read_value,
156 Err(error) => {
157 ::core::hint::cold_path();
158 return ExecutionResult::Err(ExecutionError::from(error));
159 }
160 };
161 let read_output = zicsr_helpers::process_csr_read::<Reg, Env, Self>(
162 env,
163 csr_index,
164 rs1 != Reg::ZERO,
165 read_value,
166 )?;
167
168 if rs1 == Reg::ZERO {
169 ::core::hint::cold_path();
170 } else {
171 let write_value = read_value & !rs1_value;
172 let write_output = zicsr_helpers::process_csr_write::<Reg, Env, Self>(
173 env,
174 csr_index,
175 write_value,
176 )?;
177 if let Err(error) = env.write_csr(csr_index, write_output) {
178 ::core::hint::cold_path();
179 return ExecutionResult::Err(ExecutionError::from(error));
180 }
181 }
182
183 ExecutionResult::Continue {
184 rd,
185 value: read_output,
186 }
187 }
188
189 Self::Csrrwi {
193 rd,
194 zimm,
195 csr_index,
196 } => {
197 let csr_is_read_only = (csr_index >> 10) == 0b11;
198 if csr_is_read_only {
199 ::core::hint::cold_path();
200 return ExecutionResult::Err(ExecutionError::CsrReadOnly { csr_index });
201 }
202 zicsr_helpers::check_csr_privilege_level(env, csr_index)?;
203
204 let read_output = if rd == Reg::ZERO {
205 ::core::hint::cold_path();
206 Reg::Type::from(0u8)
207 } else {
208 let read_value = match env.read_csr(csr_index) {
209 Ok(read_value) => read_value,
210 Err(error) => {
211 ::core::hint::cold_path();
212 return ExecutionResult::Err(ExecutionError::from(error));
213 }
214 };
215 zicsr_helpers::process_csr_read::<Reg, Env, Self>(
216 env, csr_index, true, read_value,
217 )?
218 };
219
220 let write_output = zicsr_helpers::process_csr_write::<Reg, Env, Self>(
221 env,
222 csr_index,
223 zimm.into(),
224 )?;
225 match env.write_csr(csr_index, write_output) {
226 Ok(()) => ExecutionResult::Continue {
227 rd,
228 value: read_output,
229 },
230 Err(error) => {
231 ::core::hint::cold_path();
232 ExecutionResult::Err(ExecutionError::from(error))
233 }
234 }
235 }
236
237 Self::Csrrsi {
242 rd,
243 zimm,
244 csr_index,
245 } => {
246 let csr_is_read_only = (csr_index >> 10) == 0b11;
247 if zimm != 0 && csr_is_read_only {
248 ::core::hint::cold_path();
249 return ExecutionResult::Err(ExecutionError::CsrReadOnly { csr_index });
250 }
251 zicsr_helpers::check_csr_privilege_level(env, csr_index)?;
252
253 let read_value = match env.read_csr(csr_index) {
254 Ok(read_value) => read_value,
255 Err(error) => {
256 ::core::hint::cold_path();
257 return ExecutionResult::Err(ExecutionError::from(error));
258 }
259 };
260 let read_output = zicsr_helpers::process_csr_read::<Reg, Env, Self>(
261 env,
262 csr_index,
263 zimm != 0,
264 read_value,
265 )?;
266
267 if zimm == 0 {
268 ::core::hint::cold_path();
269 } else {
270 let write_value = read_value | Reg::Type::from(zimm);
271 let write_output = zicsr_helpers::process_csr_write::<Reg, Env, Self>(
272 env,
273 csr_index,
274 write_value,
275 )?;
276 if let Err(error) = env.write_csr(csr_index, write_output) {
277 ::core::hint::cold_path();
278 return ExecutionResult::Err(ExecutionError::from(error));
279 }
280 }
281
282 ExecutionResult::Continue {
283 rd,
284 value: read_output,
285 }
286 }
287
288 Self::Csrrci {
293 rd,
294 zimm,
295 csr_index,
296 } => {
297 let csr_is_read_only = (csr_index >> 10) == 0b11;
298 if zimm != 0 && csr_is_read_only {
299 ::core::hint::cold_path();
300 return ExecutionResult::Err(ExecutionError::CsrReadOnly { csr_index });
301 }
302 zicsr_helpers::check_csr_privilege_level(env, csr_index)?;
303
304 let read_value = match env.read_csr(csr_index) {
305 Ok(read_value) => read_value,
306 Err(error) => {
307 ::core::hint::cold_path();
308 return ExecutionResult::Err(ExecutionError::from(error));
309 }
310 };
311 let read_output = zicsr_helpers::process_csr_read::<Reg, Env, Self>(
312 env,
313 csr_index,
314 zimm != 0,
315 read_value,
316 )?;
317
318 if zimm == 0 {
319 ::core::hint::cold_path();
320 } else {
321 let write_value = read_value & !Reg::Type::from(zimm);
322 let write_output = zicsr_helpers::process_csr_write::<Reg, Env, Self>(
323 env,
324 csr_index,
325 write_value,
326 )?;
327 if let Err(error) = env.write_csr(csr_index, write_output) {
328 ::core::hint::cold_path();
329 return ExecutionResult::Err(ExecutionError::from(error));
330 }
331 }
332
333 ExecutionResult::Continue {
334 rd,
335 value: read_output,
336 }
337 }
338 }
339 }
340}