1#[cfg(test)]
4mod tests;
5
6use crate::{
7 Address, CustomErrorPlaceholder, ExecutionError, FetchInstructionResult, InstructionFetcher,
8 ProgramCounter, ProgramCounterError, RegisterFile, SystemInstructionHandler, VirtualMemory,
9};
10use ab_riscv_primitives::prelude::*;
11use core::hint::cold_path;
12use core::marker::PhantomData;
13use core::ops::ControlFlow;
14
15pub const unsafe trait BasicRegister
21where
22 Self: [const] Register,
23{
24 const N: usize;
28
29 fn offset(self) -> u8;
31}
32
33unsafe impl<Type> const BasicRegister for EReg<Type>
35where
36 Self: [const] Register,
37{
38 const N: usize = 16;
39
40 #[inline(always)]
41 fn offset(self) -> u8 {
42 unsafe { core::mem::transmute::<Self, u8>(self) }
44 }
45}
46
47unsafe impl<Type> const BasicRegister for Reg<Type>
49where
50 Self: [const] Register,
51{
52 const N: usize = 32;
53
54 #[inline(always)]
55 fn offset(self) -> u8 {
56 unsafe { core::mem::transmute::<Self, u8>(self) }
58 }
59}
60
61#[derive(Debug, Clone, Copy)]
63#[repr(align(16))]
64pub struct BasicRegisters<Reg>
65where
66 Reg: BasicRegister,
67 [(); Reg::N]:,
68{
69 regs: [Reg::Type; Reg::N],
70}
71
72impl<Reg> Default for BasicRegisters<Reg>
73where
74 Reg: BasicRegister,
75 [(); Reg::N]:,
76{
77 #[inline(always)]
78 fn default() -> Self {
79 Self {
80 regs: [Reg::Type::default(); Reg::N],
81 }
82 }
83}
84
85impl<Reg> const RegisterFile<Reg> for BasicRegisters<Reg>
86where
87 Reg: [const] BasicRegister,
88 [(); Reg::N]:,
89{
90 #[inline(always)]
91 fn read(&self, reg: Reg) -> Reg::Type {
92 if reg == Reg::ZERO {
93 return Reg::Type::default();
95 }
96
97 *unsafe { self.regs.get_unchecked(usize::from(reg.offset())) }
99 }
100
101 #[inline(always)]
102 fn write(&mut self, reg: Reg, value: Reg::Type) {
103 *unsafe { self.regs.get_unchecked_mut(usize::from(reg.offset())) } = value;
105 }
106}
107
108#[derive(Debug)]
110pub struct BasicInterpreterState<Regs, ExtState, Memory, IF, InstructionHandler> {
111 pub regs: Regs,
113 pub ext_state: ExtState,
119 pub memory: Memory,
121 pub instruction_fetcher: IF,
123 pub system_instruction_handler: InstructionHandler,
125}
126
127#[derive(Debug, Copy, Clone)]
132pub struct BasicInstructionFetcher<I, CustomError = CustomErrorPlaceholder>
133where
134 I: Instruction,
135{
136 return_trap_address: Address<I>,
137 pc: Address<I>,
138 _phantom: PhantomData<CustomError>,
139}
140
141impl<I, Memory, CustomError> ProgramCounter<Address<I>, Memory, CustomError>
142 for BasicInstructionFetcher<I, CustomError>
143where
144 I: Instruction,
145 Memory: VirtualMemory,
146{
147 #[inline(always)]
148 fn get_pc(&self) -> Address<I> {
149 self.pc
150 }
151
152 #[inline]
153 fn set_pc(
154 &mut self,
155 _memory: &Memory,
156 pc: Address<I>,
157 ) -> Result<ControlFlow<()>, ProgramCounterError<Address<I>, CustomError>> {
158 if pc == self.return_trap_address {
159 cold_path();
160 return Ok(ControlFlow::Break(()));
161 }
162
163 if !pc.as_u64().is_multiple_of(u64::from(I::alignment())) {
164 cold_path();
165 return Err(ProgramCounterError::UnalignedInstruction { address: pc });
166 }
167
168 self.pc = pc;
169
170 Ok(ControlFlow::Continue(()))
171 }
172}
173
174impl<I, Memory, CustomError> InstructionFetcher<I, Memory, CustomError>
175 for BasicInstructionFetcher<I, CustomError>
176where
177 I: Instruction,
178 Memory: VirtualMemory,
179{
180 #[inline]
181 fn fetch_instruction(
182 &mut self,
183 memory: &Memory,
184 ) -> Result<FetchInstructionResult<I>, ExecutionError<Address<I>, CustomError>> {
185 let instruction = match memory.read(self.pc.as_u64()).or_else(|error| {
186 cold_path();
187 if let Ok(instruction) = memory.read::<u16>(self.pc.as_u64())
189 && (instruction & 0b11) != 0b11
190 {
191 return Ok(u32::from(instruction));
192 }
193 Err(error)
194 }) {
195 Ok(instruction) => instruction,
196 Err(error) => {
197 cold_path();
198 return Err(ExecutionError::MemoryAccess(error));
199 }
200 };
201
202 let Some(instruction) = I::try_decode(instruction) else {
203 cold_path();
204 return Err(ExecutionError::IllegalInstruction { address: self.pc });
205 };
206 self.pc += instruction.size().into();
207
208 Ok(FetchInstructionResult::Instruction(instruction))
209 }
210}
211
212impl<I, CustomError> BasicInstructionFetcher<I, CustomError>
213where
214 I: Instruction,
215{
216 #[inline(always)]
221 pub fn new(return_trap_address: Address<I>, pc: Address<I>) -> Self {
222 Self {
223 return_trap_address,
224 pc,
225 _phantom: PhantomData,
226 }
227 }
228}
229
230#[derive(Debug, Default, Clone, Copy)]
233pub struct IgnoreEcallSystemInstructionHandler;
234
235impl<Reg, Regs, Memory, PC, CustomError>
236 SystemInstructionHandler<Reg, Regs, Memory, PC, CustomError>
237 for IgnoreEcallSystemInstructionHandler
238where
239 Reg: Register,
240 Regs: RegisterFile<Reg>,
241{
242 fn handle_ecall(
243 &mut self,
244 _regs: &mut Regs,
245 _memory: &mut Memory,
246 _program_counter: &mut PC,
247 ) -> Result<ControlFlow<()>, ExecutionError<Reg::Type, CustomError>> {
248 Ok(ControlFlow::Continue(()))
249 }
250}