Skip to main content

ab_riscv_interpreter/
rv32.rs

1//! Base RISC-V RV32 instruction set
2
3pub mod a;
4pub mod b;
5pub mod c;
6pub mod m;
7#[cfg(test)]
8pub(crate) mod test_utils;
9#[cfg(test)]
10mod tests;
11pub mod zabha;
12pub mod zacas;
13pub mod zalasr;
14pub mod zce;
15pub mod zk;
16
17use crate::{
18    ExecutableInstruction, ExecutableInstructionCsr, ExecutableInstructionOperands, ExecutionError,
19    ExecutionResult, FetchInstructionResult, InstructionFetcher, OpaqueThreadedExecutionResult,
20    PackedAddress, ProgramCounter, RegisterFile, Rs1Rs2OperandValues, Rs1Rs2Operands,
21    SystemInstructionHandler, ThreadedExecutableInstruction, ThreadedExecutionResult,
22    VirtualMemory,
23};
24use ab_riscv_macros::instruction_execution;
25use ab_riscv_primitives::prelude::*;
26use core::ops::ControlFlow;
27
28#[instruction_execution]
29const impl<Reg> ExecutableInstructionOperands for Rv32Instruction<Reg> where
30    Reg: Register<Type = u32>
31{
32}
33
34#[instruction_execution]
35const impl<Reg, Env> ExecutableInstructionCsr<Env> for Rv32Instruction<Reg> where
36    Reg: Register<Type = u32>
37{
38}
39
40#[instruction_execution]
41const impl<Reg, Regs, Env, Memory, PC> ExecutableInstruction<Regs, Env, Memory, PC>
42    for Rv32Instruction<Reg>
43where
44    Reg: [const] Register<Type = u32>,
45    Regs: [const] RegisterFile<Reg>,
46    Env: [const] SystemInstructionHandler<Reg, Regs, Memory, PC>,
47    Memory: [const] VirtualMemory,
48    PC: [const] ProgramCounter<Reg::Type, Memory>,
49{
50    #[inline(always)]
51    #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
52    fn execute(
53        self,
54        Rs1Rs2OperandValues {
55            rs1_value,
56            rs2_value,
57        }: Rs1Rs2OperandValues<<Self::Reg as Register>::Type>,
58        regs: &mut Regs,
59        env: &mut Env,
60        memory: &mut Memory,
61        program_counter: &mut PC,
62    ) -> ExecutionResult<Self::Reg> {
63        match self {
64            Self::Add { rd, rs1: _, rs2: _ } => {
65                let value = rs1_value.wrapping_add(rs2_value);
66                ExecutionResult::Continue { rd, value }
67            }
68            Self::Sub { rd, rs1: _, rs2: _ } => {
69                let value = rs1_value.wrapping_sub(rs2_value);
70                ExecutionResult::Continue { rd, value }
71            }
72            Self::Sll { rd, rs1: _, rs2: _ } => {
73                let shamt = rs2_value & 0x1f;
74                let value = rs1_value << shamt;
75                ExecutionResult::Continue { rd, value }
76            }
77            Self::Slt { rd, rs1: _, rs2: _ } => {
78                let value = rs1_value.cast_signed() < rs2_value.cast_signed();
79                ExecutionResult::Continue {
80                    rd,
81                    value: u32::from(value),
82                }
83            }
84            Self::Sltu { rd, rs1: _, rs2: _ } => {
85                let value = rs1_value < rs2_value;
86                ExecutionResult::Continue {
87                    rd,
88                    value: u32::from(value),
89                }
90            }
91            Self::Xor { rd, rs1: _, rs2: _ } => {
92                let value = rs1_value ^ rs2_value;
93                ExecutionResult::Continue { rd, value }
94            }
95            Self::Srl { rd, rs1: _, rs2: _ } => {
96                let shamt = rs2_value & 0x1f;
97                let value = rs1_value >> shamt;
98                ExecutionResult::Continue { rd, value }
99            }
100            Self::Sra { rd, rs1: _, rs2: _ } => {
101                let shamt = rs2_value & 0x1f;
102                let value = rs1_value.cast_signed() >> shamt;
103                ExecutionResult::Continue {
104                    rd,
105                    value: value.cast_unsigned(),
106                }
107            }
108            Self::Or { rd, rs1: _, rs2: _ } => {
109                let value = rs1_value | rs2_value;
110                ExecutionResult::Continue { rd, value }
111            }
112            Self::And { rd, rs1: _, rs2: _ } => {
113                let value = rs1_value & rs2_value;
114                ExecutionResult::Continue { rd, value }
115            }
116
117            Self::Addi { rd, rs1: _, imm } => {
118                let value = rs1_value.wrapping_add(i32::from(imm).cast_unsigned());
119                ExecutionResult::Continue { rd, value }
120            }
121            Self::Slti { rd, rs1: _, imm } => {
122                let value = rs1_value.cast_signed() < i32::from(imm);
123                ExecutionResult::Continue {
124                    rd,
125                    value: u32::from(value),
126                }
127            }
128            Self::Sltiu { rd, rs1: _, imm } => {
129                let value = rs1_value < i32::from(imm).cast_unsigned();
130                ExecutionResult::Continue {
131                    rd,
132                    value: u32::from(value),
133                }
134            }
135            Self::Xori { rd, rs1: _, imm } => {
136                let value = rs1_value ^ i32::from(imm).cast_unsigned();
137                ExecutionResult::Continue { rd, value }
138            }
139            Self::Ori { rd, rs1: _, imm } => {
140                let value = rs1_value | i32::from(imm).cast_unsigned();
141                ExecutionResult::Continue { rd, value }
142            }
143            Self::Andi { rd, rs1: _, imm } => {
144                let value = rs1_value & i32::from(imm).cast_unsigned();
145                ExecutionResult::Continue { rd, value }
146            }
147            Self::Slli { rd, rs1: _, shamt } => {
148                let value = rs1_value << shamt;
149                ExecutionResult::Continue { rd, value }
150            }
151            Self::Srli { rd, rs1: _, shamt } => {
152                let value = rs1_value >> shamt;
153                ExecutionResult::Continue { rd, value }
154            }
155            Self::Srai { rd, rs1: _, shamt } => {
156                let value = rs1_value.cast_signed() >> shamt;
157                ExecutionResult::Continue {
158                    rd,
159                    value: value.cast_unsigned(),
160                }
161            }
162
163            Self::Lb { rd, rs1: _, imm } => {
164                let addr = rs1_value.wrapping_add(i32::from(imm).cast_unsigned());
165                let value = i32::from(memory.read::<i8>(u64::from(addr))?);
166                ExecutionResult::Continue {
167                    rd,
168                    value: value.cast_unsigned(),
169                }
170            }
171            Self::Lh { rd, rs1: _, imm } => {
172                let addr = rs1_value.wrapping_add(i32::from(imm).cast_unsigned());
173                let value = i32::from(memory.read::<i16>(u64::from(addr))?);
174                ExecutionResult::Continue {
175                    rd,
176                    value: value.cast_unsigned(),
177                }
178            }
179            Self::Lw { rd, rs1: _, imm } => {
180                let addr = rs1_value.wrapping_add(i32::from(imm).cast_unsigned());
181                let value = memory.read::<u32>(u64::from(addr))?;
182                ExecutionResult::Continue { rd, value }
183            }
184            Self::Lbu { rd, rs1: _, imm } => {
185                let addr = rs1_value.wrapping_add(i32::from(imm).cast_unsigned());
186                let value = memory.read::<u8>(u64::from(addr))?;
187                ExecutionResult::Continue {
188                    rd,
189                    value: u32::from(value),
190                }
191            }
192            Self::Lhu { rd, rs1: _, imm } => {
193                let addr = rs1_value.wrapping_add(i32::from(imm).cast_unsigned());
194                let value = memory.read::<u16>(u64::from(addr))?;
195                ExecutionResult::Continue {
196                    rd,
197                    value: u32::from(value),
198                }
199            }
200
201            Self::Jalr { rd, rs1: _, imm } => {
202                let target = (rs1_value.wrapping_add(i32::from(imm).cast_unsigned())) & !1u32;
203                regs.write(rd, program_counter.get_pc());
204
205                ExecutionResult::Jump { target }
206            }
207
208            Self::Sb {
209                rs2: _,
210                rs1: _,
211                imm,
212            } => {
213                let addr = rs1_value.wrapping_add(i32::from(imm).cast_unsigned());
214                memory.write(u64::from(addr), rs2_value as u8)?;
215                ExecutionResult::ContinueNoWrite
216            }
217            Self::Sh {
218                rs2: _,
219                rs1: _,
220                imm,
221            } => {
222                let addr = rs1_value.wrapping_add(i32::from(imm).cast_unsigned());
223                memory.write(u64::from(addr), rs2_value as u16)?;
224                ExecutionResult::ContinueNoWrite
225            }
226            Self::Sw {
227                rs2: _,
228                rs1: _,
229                imm,
230            } => {
231                let addr = rs1_value.wrapping_add(i32::from(imm).cast_unsigned());
232                memory.write(u64::from(addr), rs2_value)?;
233                ExecutionResult::ContinueNoWrite
234            }
235
236            Self::Beq {
237                rs1: _,
238                rs2: _,
239                imm,
240            } => {
241                if rs1_value == rs2_value {
242                    return ExecutionResult::Branch {
243                        offset: i32::from(imm),
244                    };
245                }
246
247                ExecutionResult::ContinueNoWrite
248            }
249            Self::Bne {
250                rs1: _,
251                rs2: _,
252                imm,
253            } => {
254                if rs1_value != rs2_value {
255                    return ExecutionResult::Branch {
256                        offset: i32::from(imm),
257                    };
258                }
259
260                ExecutionResult::ContinueNoWrite
261            }
262            Self::Blt {
263                rs1: _,
264                rs2: _,
265                imm,
266            } => {
267                if rs1_value.cast_signed() < rs2_value.cast_signed() {
268                    return ExecutionResult::Branch {
269                        offset: i32::from(imm),
270                    };
271                }
272
273                ExecutionResult::ContinueNoWrite
274            }
275            Self::Bge {
276                rs1: _,
277                rs2: _,
278                imm,
279            } => {
280                if rs1_value.cast_signed() >= rs2_value.cast_signed() {
281                    return ExecutionResult::Branch {
282                        offset: i32::from(imm),
283                    };
284                }
285
286                ExecutionResult::ContinueNoWrite
287            }
288            Self::Bltu {
289                rs1: _,
290                rs2: _,
291                imm,
292            } => {
293                if rs1_value < rs2_value {
294                    return ExecutionResult::Branch {
295                        offset: i32::from(imm),
296                    };
297                }
298
299                ExecutionResult::ContinueNoWrite
300            }
301            Self::Bgeu {
302                rs1: _,
303                rs2: _,
304                imm,
305            } => {
306                if rs1_value >= rs2_value {
307                    return ExecutionResult::Branch {
308                        offset: i32::from(imm),
309                    };
310                }
311
312                ExecutionResult::ContinueNoWrite
313            }
314
315            Self::Lui { rd, imm } => ExecutionResult::Continue {
316                rd,
317                value: imm.to_i32().cast_unsigned(),
318            },
319
320            Self::Auipc { rd, imm } => {
321                let old_pc = program_counter.old_pc(size_of::<u32>() as u8);
322                ExecutionResult::Continue {
323                    rd,
324                    value: old_pc.wrapping_add(imm.to_i32().cast_unsigned()),
325                }
326            }
327
328            Self::Jal { rd, imm } => {
329                let pc = program_counter.get_pc();
330                regs.write(rd, pc);
331
332                ExecutionResult::Branch {
333                    offset: imm.to_i32(),
334                }
335            }
336
337            Self::Fence { pred, succ } => {
338                env.handle_fence(pred, succ);
339                ExecutionResult::ContinueNoWrite
340            }
341            Self::FenceTso => {
342                env.handle_fence_tso();
343                ExecutionResult::ContinueNoWrite
344            }
345
346            Self::Ecall => match env.handle_ecall(regs, memory, program_counter)? {
347                ControlFlow::Continue(()) => ExecutionResult::ContinueNoWrite,
348                ControlFlow::Break(()) => ExecutionResult::Break,
349            },
350            Self::Ebreak => {
351                env.handle_ebreak(regs, memory, program_counter.get_pc());
352                ExecutionResult::ContinueNoWrite
353            }
354
355            Self::Unimp => {
356                let old_pc = program_counter.old_pc(size_of::<u32>() as u8);
357                ExecutionResult::Err(ExecutionError::IllegalInstruction {
358                    address: PackedAddress::new(old_pc),
359                })
360            }
361        }
362    }
363}