1#[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 Rv64ZabhaInstruction<Reg> where
17 Reg: Register<Type = u64>
18{
19}
20
21#[instruction_execution]
22const impl<Reg, Env> ExecutableInstructionCsr<Env> for Rv64ZabhaInstruction<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 Rv64ZabhaInstruction<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::AmoswapB {
50 rd,
51 rs1: _,
52 rs2: _,
53 aq: _,
54 rl: _,
55 } => {
56 let old = memory.read::<i8>(rs1_value)?;
57 memory.write(rs1_value, rs2_value as u8)?;
58 ExecutionResult::Continue {
59 rd,
60 value: i64::from(old).cast_unsigned(),
61 }
62 }
63 Self::AmoswapH {
64 rd,
65 rs1: _,
66 rs2: _,
67 aq: _,
68 rl: _,
69 } => {
70 if rs1_value / 4096 != (rs1_value + 1) / 4096 {
73 ::core::hint::cold_path();
74 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
75 address: PackedAddress::new(rs1_value),
76 });
77 }
78 let old = memory.read::<i16>(rs1_value)?;
79 memory.write(rs1_value, rs2_value as u16)?;
80 ExecutionResult::Continue {
81 rd,
82 value: i64::from(old).cast_unsigned(),
83 }
84 }
85 Self::AmoaddB {
86 rd,
87 rs1: _,
88 rs2: _,
89 aq: _,
90 rl: _,
91 } => {
92 let old = memory.read::<i8>(rs1_value)?;
93 let new = old.cast_unsigned().wrapping_add(rs2_value as u8);
94 memory.write(rs1_value, new)?;
95 ExecutionResult::Continue {
96 rd,
97 value: i64::from(old).cast_unsigned(),
98 }
99 }
100 Self::AmoaddH {
101 rd,
102 rs1: _,
103 rs2: _,
104 aq: _,
105 rl: _,
106 } => {
107 if rs1_value / 4096 != (rs1_value + 1) / 4096 {
110 ::core::hint::cold_path();
111 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
112 address: PackedAddress::new(rs1_value),
113 });
114 }
115 let old = memory.read::<i16>(rs1_value)?;
116 let new = old.cast_unsigned().wrapping_add(rs2_value as u16);
117 memory.write(rs1_value, new)?;
118 ExecutionResult::Continue {
119 rd,
120 value: i64::from(old).cast_unsigned(),
121 }
122 }
123 Self::AmoxorB {
124 rd,
125 rs1: _,
126 rs2: _,
127 aq: _,
128 rl: _,
129 } => {
130 let old = memory.read::<i8>(rs1_value)?;
131 let new = old.cast_unsigned() ^ (rs2_value as u8);
132 memory.write(rs1_value, new)?;
133 ExecutionResult::Continue {
134 rd,
135 value: i64::from(old).cast_unsigned(),
136 }
137 }
138 Self::AmoxorH {
139 rd,
140 rs1: _,
141 rs2: _,
142 aq: _,
143 rl: _,
144 } => {
145 if rs1_value / 4096 != (rs1_value + 1) / 4096 {
148 ::core::hint::cold_path();
149 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
150 address: PackedAddress::new(rs1_value),
151 });
152 }
153 let old = memory.read::<i16>(rs1_value)?;
154 let new = old.cast_unsigned() ^ (rs2_value as u16);
155 memory.write(rs1_value, new)?;
156 ExecutionResult::Continue {
157 rd,
158 value: i64::from(old).cast_unsigned(),
159 }
160 }
161 Self::AmoandB {
162 rd,
163 rs1: _,
164 rs2: _,
165 aq: _,
166 rl: _,
167 } => {
168 let old = memory.read::<i8>(rs1_value)?;
169 let new = old.cast_unsigned() & (rs2_value as u8);
170 memory.write(rs1_value, new)?;
171 ExecutionResult::Continue {
172 rd,
173 value: i64::from(old).cast_unsigned(),
174 }
175 }
176 Self::AmoandH {
177 rd,
178 rs1: _,
179 rs2: _,
180 aq: _,
181 rl: _,
182 } => {
183 if rs1_value / 4096 != (rs1_value + 1) / 4096 {
186 ::core::hint::cold_path();
187 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
188 address: PackedAddress::new(rs1_value),
189 });
190 }
191 let old = memory.read::<i16>(rs1_value)?;
192 let new = old.cast_unsigned() & (rs2_value as u16);
193 memory.write(rs1_value, new)?;
194 ExecutionResult::Continue {
195 rd,
196 value: i64::from(old).cast_unsigned(),
197 }
198 }
199 Self::AmoorB {
200 rd,
201 rs1: _,
202 rs2: _,
203 aq: _,
204 rl: _,
205 } => {
206 let old = memory.read::<i8>(rs1_value)?;
207 let new = old.cast_unsigned() | (rs2_value as u8);
208 memory.write(rs1_value, new)?;
209 ExecutionResult::Continue {
210 rd,
211 value: i64::from(old).cast_unsigned(),
212 }
213 }
214 Self::AmoorH {
215 rd,
216 rs1: _,
217 rs2: _,
218 aq: _,
219 rl: _,
220 } => {
221 if rs1_value / 4096 != (rs1_value + 1) / 4096 {
224 ::core::hint::cold_path();
225 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
226 address: PackedAddress::new(rs1_value),
227 });
228 }
229 let old = memory.read::<i16>(rs1_value)?;
230 let new = old.cast_unsigned() | (rs2_value as u16);
231 memory.write(rs1_value, new)?;
232 ExecutionResult::Continue {
233 rd,
234 value: i64::from(old).cast_unsigned(),
235 }
236 }
237 Self::AmominB {
238 rd,
239 rs1: _,
240 rs2: _,
241 aq: _,
242 rl: _,
243 } => {
244 let old = memory.read::<i8>(rs1_value)?;
245 let new = if old < (rs2_value as u8).cast_signed() {
246 old.cast_unsigned()
247 } else {
248 rs2_value as u8
249 };
250 memory.write(rs1_value, new)?;
251 ExecutionResult::Continue {
252 rd,
253 value: i64::from(old).cast_unsigned(),
254 }
255 }
256 Self::AmominH {
257 rd,
258 rs1: _,
259 rs2: _,
260 aq: _,
261 rl: _,
262 } => {
263 if rs1_value / 4096 != (rs1_value + 1) / 4096 {
266 ::core::hint::cold_path();
267 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
268 address: PackedAddress::new(rs1_value),
269 });
270 }
271 let old = memory.read::<i16>(rs1_value)?;
272 let new = if old < (rs2_value as u16).cast_signed() {
273 old.cast_unsigned()
274 } else {
275 rs2_value as u16
276 };
277 memory.write(rs1_value, new)?;
278 ExecutionResult::Continue {
279 rd,
280 value: i64::from(old).cast_unsigned(),
281 }
282 }
283 Self::AmomaxB {
284 rd,
285 rs1: _,
286 rs2: _,
287 aq: _,
288 rl: _,
289 } => {
290 let old = memory.read::<i8>(rs1_value)?;
291 let new = if old > (rs2_value as u8).cast_signed() {
292 old.cast_unsigned()
293 } else {
294 rs2_value as u8
295 };
296 memory.write(rs1_value, new)?;
297 ExecutionResult::Continue {
298 rd,
299 value: i64::from(old).cast_unsigned(),
300 }
301 }
302 Self::AmomaxH {
303 rd,
304 rs1: _,
305 rs2: _,
306 aq: _,
307 rl: _,
308 } => {
309 if rs1_value / 4096 != (rs1_value + 1) / 4096 {
312 ::core::hint::cold_path();
313 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
314 address: PackedAddress::new(rs1_value),
315 });
316 }
317 let old = memory.read::<i16>(rs1_value)?;
318 let new = if old > (rs2_value as u16).cast_signed() {
319 old.cast_unsigned()
320 } else {
321 rs2_value as u16
322 };
323 memory.write(rs1_value, new)?;
324 ExecutionResult::Continue {
325 rd,
326 value: i64::from(old).cast_unsigned(),
327 }
328 }
329 Self::AmominuB {
330 rd,
331 rs1: _,
332 rs2: _,
333 aq: _,
334 rl: _,
335 } => {
336 let old = memory.read::<i8>(rs1_value)?;
337 let new = if old.cast_unsigned() < (rs2_value as u8) {
338 old.cast_unsigned()
339 } else {
340 rs2_value as u8
341 };
342 memory.write(rs1_value, new)?;
343 ExecutionResult::Continue {
344 rd,
345 value: i64::from(old).cast_unsigned(),
346 }
347 }
348 Self::AmominuH {
349 rd,
350 rs1: _,
351 rs2: _,
352 aq: _,
353 rl: _,
354 } => {
355 if rs1_value / 4096 != (rs1_value + 1) / 4096 {
358 ::core::hint::cold_path();
359 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
360 address: PackedAddress::new(rs1_value),
361 });
362 }
363 let old = memory.read::<i16>(rs1_value)?;
364 let new = if old.cast_unsigned() < (rs2_value as u16) {
365 old.cast_unsigned()
366 } else {
367 rs2_value as u16
368 };
369 memory.write(rs1_value, new)?;
370 ExecutionResult::Continue {
371 rd,
372 value: i64::from(old).cast_unsigned(),
373 }
374 }
375 Self::AmomaxuB {
376 rd,
377 rs1: _,
378 rs2: _,
379 aq: _,
380 rl: _,
381 } => {
382 let old = memory.read::<i8>(rs1_value)?;
383 let new = if old.cast_unsigned() > (rs2_value as u8) {
384 old.cast_unsigned()
385 } else {
386 rs2_value as u8
387 };
388 memory.write(rs1_value, new)?;
389 ExecutionResult::Continue {
390 rd,
391 value: i64::from(old).cast_unsigned(),
392 }
393 }
394 Self::AmomaxuH {
395 rd,
396 rs1: _,
397 rs2: _,
398 aq: _,
399 rl: _,
400 } => {
401 if rs1_value / 4096 != (rs1_value + 1) / 4096 {
404 ::core::hint::cold_path();
405 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
406 address: PackedAddress::new(rs1_value),
407 });
408 }
409 let old = memory.read::<i16>(rs1_value)?;
410 let new = if old.cast_unsigned() > (rs2_value as u16) {
411 old.cast_unsigned()
412 } else {
413 rs2_value as u16
414 };
415 memory.write(rs1_value, new)?;
416 ExecutionResult::Continue {
417 rd,
418 value: i64::from(old).cast_unsigned(),
419 }
420 }
421 Self::AmocasB {
422 rd,
423 rs1: _,
424 rs2: _,
425 aq: _,
426 rl: _,
427 } => {
428 let compare = regs.read(rd) as u8;
429 let old = memory.read::<i8>(rs1_value)?;
430 if old.cast_unsigned() == compare {
431 memory.write(rs1_value, rs2_value as u8)?;
432 }
433 ExecutionResult::Continue {
434 rd,
435 value: i64::from(old).cast_unsigned(),
436 }
437 }
438 Self::AmocasH {
439 rd,
440 rs1: _,
441 rs2: _,
442 aq: _,
443 rl: _,
444 } => {
445 let compare = regs.read(rd) as u16;
446 if rs1_value / 4096 != (rs1_value + 1) / 4096 {
449 ::core::hint::cold_path();
450 return ExecutionResult::Err(ExecutionError::MisalignedAtomic {
451 address: PackedAddress::new(rs1_value),
452 });
453 }
454 let old = memory.read::<i16>(rs1_value)?;
455 if old.cast_unsigned() == compare {
456 memory.write(rs1_value, rs2_value as u16)?;
457 }
458 ExecutionResult::Continue {
459 rd,
460 value: i64::from(old).cast_unsigned(),
461 }
462 }
463 }
464 }
465}