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