1#[cfg(test)]
4mod tests;
5pub mod zicsr_helpers;
6
7use crate::{
8 CsrError, Csrs, ExecutableInstruction, ExecutableInstructionCsr, ExecutableInstructionOperands,
9 ExecutionError, RegisterFile, Rs1Rs2OperandValues, Rs1Rs2Operands,
10};
11use ab_riscv_macros::instruction_execution;
12use ab_riscv_primitives::prelude::*;
13use core::ops::ControlFlow;
14
15#[instruction_execution]
16impl<Reg> ExecutableInstructionOperands for ZicsrInstruction<Reg> where Reg: Register {}
17
18#[instruction_execution]
19impl<Reg, ExtState, CustomError> ExecutableInstructionCsr<ExtState, CustomError>
20 for ZicsrInstruction<Reg>
21where
22 Reg: Register,
23{
24}
25
26#[instruction_execution]
27impl<Reg, Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
28 ExecutableInstruction<Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
29 for ZicsrInstruction<Reg>
30where
31 Reg: Register,
32 Regs: RegisterFile<Reg>,
33 ExtState: Csrs<Reg, CustomError>,
34{
35 #[inline(always)]
36 fn execute(
37 self,
38 Rs1Rs2OperandValues {
39 rs1_value,
40 rs2_value: _,
41 }: Rs1Rs2OperandValues<<Self::Reg as Register>::Type>,
42 _regs: &mut Regs,
43 ext_state: &mut ExtState,
44 _memory: &mut Memory,
45 _program_counter: &mut PC,
46 _system_instruction_handler: &mut InstructionHandler,
47 ) -> Result<
48 ControlFlow<(), (Self::Reg, <Self::Reg as Register>::Type)>,
49 ExecutionError<Reg::Type, CustomError>,
50 > {
51 match self {
52 Self::Csrrw {
57 rd,
58 rs1: _,
59 csr_index,
60 } => {
61 let csr_is_read_only = (csr_index >> 10) == 0b11;
62 if csr_is_read_only {
63 ::core::hint::cold_path();
64 return Err(ExecutionError::CsrError(CsrError::ReadOnly { csr_index }));
65 }
66 zicsr_helpers::check_csr_privilege_level(ext_state, csr_index)?;
67
68 let write_value = rs1_value;
69
70 let read_output = if rd == Reg::ZERO {
72 ::core::hint::cold_path();
73 Reg::Type::from(0u8)
74 } else {
75 let read_value = match ext_state.read_csr(csr_index) {
76 Ok(read_value) => read_value,
77 Err(err) => {
78 ::core::hint::cold_path();
79 return Err(ExecutionError::CsrError(err));
80 }
81 };
82 ext_state.process_csr_read::<Self>(csr_index, read_value)?
83 };
84
85 let write_output = ext_state.process_csr_write::<Self>(csr_index, write_value)?;
86 match ext_state.write_csr(csr_index, write_output) {
87 Ok(()) => Ok(ControlFlow::Continue((rd, read_output))),
88 Err(err) => {
89 ::core::hint::cold_path();
90 Err(ExecutionError::CsrError(err))
91 }
92 }
93 }
94
95 Self::Csrrs { rd, rs1, csr_index } => {
100 let csr_is_read_only = (csr_index >> 10) == 0b11;
101 if rs1 != Reg::ZERO && csr_is_read_only {
102 ::core::hint::cold_path();
103 return Err(ExecutionError::CsrError(CsrError::ReadOnly { csr_index }));
104 }
105 zicsr_helpers::check_csr_privilege_level(ext_state, csr_index)?;
106
107 let read_value = match ext_state.read_csr(csr_index) {
108 Ok(read_value) => read_value,
109 Err(error) => {
110 ::core::hint::cold_path();
111 return Err(ExecutionError::CsrError(error));
112 }
113 };
114 let read_output = ext_state.process_csr_read::<Self>(csr_index, read_value)?;
115
116 if rs1 == Reg::ZERO {
117 ::core::hint::cold_path();
118 } else {
119 let write_value = read_value | rs1_value;
120 let write_output =
121 ext_state.process_csr_write::<Self>(csr_index, write_value)?;
122 if let Err(error) = ext_state.write_csr(csr_index, write_output) {
123 ::core::hint::cold_path();
124 return Err(ExecutionError::CsrError(error));
125 }
126 }
127 Ok(ControlFlow::Continue((rd, read_output)))
128 }
129
130 Self::Csrrc { rd, rs1, csr_index } => {
135 let csr_is_read_only = (csr_index >> 10) == 0b11;
136 if rs1 != Reg::ZERO && csr_is_read_only {
137 ::core::hint::cold_path();
138 return Err(ExecutionError::CsrError(CsrError::ReadOnly { csr_index }));
139 }
140 zicsr_helpers::check_csr_privilege_level(ext_state, csr_index)?;
141
142 let read_value = match ext_state.read_csr(csr_index) {
143 Ok(read_value) => read_value,
144 Err(error) => {
145 ::core::hint::cold_path();
146 return Err(ExecutionError::CsrError(error));
147 }
148 };
149 let read_output = ext_state.process_csr_read::<Self>(csr_index, read_value)?;
150
151 if rs1 == Reg::ZERO {
152 ::core::hint::cold_path();
153 } else {
154 let write_value = read_value & !rs1_value;
155 let write_output =
156 ext_state.process_csr_write::<Self>(csr_index, write_value)?;
157 if let Err(error) = ext_state.write_csr(csr_index, write_output) {
158 ::core::hint::cold_path();
159 return Err(ExecutionError::CsrError(error));
160 }
161 }
162
163 Ok(ControlFlow::Continue((rd, read_output)))
164 }
165
166 Self::Csrrwi {
170 rd,
171 zimm,
172 csr_index,
173 } => {
174 let csr_is_read_only = (csr_index >> 10) == 0b11;
175 if csr_is_read_only {
176 ::core::hint::cold_path();
177 return Err(ExecutionError::CsrError(CsrError::ReadOnly { csr_index }));
178 }
179 zicsr_helpers::check_csr_privilege_level(ext_state, csr_index)?;
180
181 let read_output = if rd == Reg::ZERO {
182 ::core::hint::cold_path();
183 Reg::Type::from(0u8)
184 } else {
185 let read_value = match ext_state.read_csr(csr_index) {
186 Ok(read_value) => read_value,
187 Err(error) => {
188 ::core::hint::cold_path();
189 return Err(ExecutionError::CsrError(error));
190 }
191 };
192 ext_state.process_csr_read::<Self>(csr_index, read_value)?
193 };
194
195 let write_output = ext_state.process_csr_write::<Self>(csr_index, zimm.into())?;
196 match ext_state.write_csr(csr_index, write_output) {
197 Ok(()) => Ok(ControlFlow::Continue((rd, read_output))),
198 Err(error) => {
199 ::core::hint::cold_path();
200 Err(ExecutionError::CsrError(error))
201 }
202 }
203 }
204
205 Self::Csrrsi {
210 rd,
211 zimm,
212 csr_index,
213 } => {
214 let csr_is_read_only = (csr_index >> 10) == 0b11;
215 if zimm != 0 && csr_is_read_only {
216 ::core::hint::cold_path();
217 return Err(ExecutionError::CsrError(CsrError::ReadOnly { csr_index }));
218 }
219 zicsr_helpers::check_csr_privilege_level(ext_state, csr_index)?;
220
221 let read_value = match ext_state.read_csr(csr_index) {
222 Ok(read_value) => read_value,
223 Err(error) => {
224 ::core::hint::cold_path();
225 return Err(ExecutionError::CsrError(error));
226 }
227 };
228 let read_output = ext_state.process_csr_read::<Self>(csr_index, read_value)?;
229
230 if zimm == 0 {
231 ::core::hint::cold_path();
232 } else {
233 let write_value = read_value | Reg::Type::from(zimm);
234 let write_output =
235 ext_state.process_csr_write::<Self>(csr_index, write_value)?;
236 if let Err(error) = ext_state.write_csr(csr_index, write_output) {
237 ::core::hint::cold_path();
238 return Err(ExecutionError::CsrError(error));
239 }
240 }
241
242 Ok(ControlFlow::Continue((rd, read_output)))
243 }
244
245 Self::Csrrci {
250 rd,
251 zimm,
252 csr_index,
253 } => {
254 let csr_is_read_only = (csr_index >> 10) == 0b11;
255 if zimm != 0 && csr_is_read_only {
256 ::core::hint::cold_path();
257 return Err(ExecutionError::CsrError(CsrError::ReadOnly { csr_index }));
258 }
259 zicsr_helpers::check_csr_privilege_level(ext_state, csr_index)?;
260
261 let read_value = match ext_state.read_csr(csr_index) {
262 Ok(read_value) => read_value,
263 Err(error) => {
264 ::core::hint::cold_path();
265 return Err(ExecutionError::CsrError(error));
266 }
267 };
268 let read_output = ext_state.process_csr_read::<Self>(csr_index, read_value)?;
269
270 if zimm == 0 {
271 ::core::hint::cold_path();
272 } else {
273 let write_value = read_value & !Reg::Type::from(zimm);
274 let write_output =
275 ext_state.process_csr_write::<Self>(csr_index, write_value)?;
276 if let Err(error) = ext_state.write_csr(csr_index, write_output) {
277 ::core::hint::cold_path();
278 return Err(ExecutionError::CsrError(error));
279 }
280 }
281
282 Ok(ControlFlow::Continue((rd, read_output)))
283 }
284 }
285 }
286}