1#![feature(
2 bigint_helper_methods,
3 const_convert,
4 const_trait_impl,
5 control_flow_ok
6)]
7#![expect(incomplete_features, reason = "generic_const_exprs")]
8#![feature(generic_const_exprs)]
11#![no_std]
12
13pub mod rv64;
14
15use ab_riscv_primitives::instruction::Instruction;
16use ab_riscv_primitives::registers::Register;
17use core::marker::PhantomData;
18use core::ops::ControlFlow;
19
20type Address<I> = <<I as Instruction>::Reg as Register>::Type;
21
22#[derive(Debug, thiserror::Error)]
24pub enum VirtualMemoryError {
25 #[error("Out-of-bounds read at address {address}")]
27 OutOfBoundsRead {
28 address: u64,
30 },
31 #[error("Out-of-bounds write at address {address}")]
33 OutOfBoundsWrite {
34 address: u64,
36 },
37}
38
39mod private {
40 pub trait Sealed {}
41
42 impl Sealed for u8 {}
43 impl Sealed for u16 {}
44 impl Sealed for u32 {}
45 impl Sealed for u64 {}
46 impl Sealed for i8 {}
47 impl Sealed for i16 {}
48 impl Sealed for i32 {}
49 impl Sealed for i64 {}
50}
51
52pub trait BasicInt: Sized + Copy + private::Sealed {}
54
55impl BasicInt for u8 {}
56impl BasicInt for u16 {}
57impl BasicInt for u32 {}
58impl BasicInt for u64 {}
59impl BasicInt for i8 {}
60impl BasicInt for i16 {}
61impl BasicInt for i32 {}
62impl BasicInt for i64 {}
63
64pub trait VirtualMemory {
66 fn read<T>(&self, address: u64) -> Result<T, VirtualMemoryError>
68 where
69 T: BasicInt;
70
71 unsafe fn read_unchecked<T>(&self, address: u64) -> T
76 where
77 T: BasicInt;
78
79 fn write<T>(&mut self, address: u64, value: T) -> Result<(), VirtualMemoryError>
81 where
82 T: BasicInt;
83}
84
85#[derive(Debug, thiserror::Error)]
87pub enum ProgramCounterError<Address, Custom> {
88 #[error("Unaligned instruction at address {address}")]
90 UnalignedInstruction {
91 address: Address,
93 },
94 #[error("Memory access error: {0}")]
96 MemoryAccess(#[from] VirtualMemoryError),
97 #[error("Custom error: {0}")]
99 Custom(Custom),
100}
101
102pub trait ProgramCounter<Address, Memory, CustomError> {
104 fn get_pc(&self) -> Address;
106
107 fn set_pc(
109 &mut self,
110 memory: &mut Memory,
111 pc: Address,
112 ) -> Result<ControlFlow<()>, ProgramCounterError<Address, CustomError>>;
113}
114
115#[derive(Debug, thiserror::Error)]
117pub enum ExecutionError<Address, I, Custom> {
118 #[error("Unaligned instruction fetch at address {address}")]
120 UnalignedInstructionFetch {
121 address: Address,
123 },
124 #[error("Program counter error: {0}")]
126 ProgramCounter(#[from] ProgramCounterError<Address, Custom>),
127 #[error("Memory access error: {0}")]
129 MemoryAccess(#[from] VirtualMemoryError),
130 #[error("Unsupported instruction at address {address:#x}: {instruction}")]
132 UnsupportedInstruction {
133 address: Address,
135 instruction: I,
137 },
138 #[error("Unimplemented/illegal instruction at address {address:#x}")]
140 UnimpInstruction {
141 address: Address,
143 },
144 #[error("Invalid instruction at address {address:#x}: {instruction:#010x}")]
146 InvalidInstruction {
147 address: Address,
149 instruction: u32,
151 },
152 #[error("Custom error: {0}")]
154 Custom(Custom),
155}
156
157impl<Address, BI, Custom> ExecutionError<Address, BI, Custom> {
158 #[inline]
160 pub fn map_instruction<I>(self, map: fn(BI) -> I) -> ExecutionError<Address, I, Custom> {
161 match self {
162 Self::UnalignedInstructionFetch { address } => {
163 ExecutionError::UnalignedInstructionFetch { address }
164 }
165 Self::MemoryAccess(error) => ExecutionError::MemoryAccess(error),
166 Self::ProgramCounter(error) => ExecutionError::ProgramCounter(error),
167 Self::UnsupportedInstruction {
168 address,
169 instruction,
170 } => ExecutionError::UnsupportedInstruction {
171 address,
172 instruction: map(instruction),
173 },
174 Self::UnimpInstruction { address } => ExecutionError::UnimpInstruction { address },
175 Self::InvalidInstruction {
176 address,
177 instruction,
178 } => ExecutionError::InvalidInstruction {
179 address,
180 instruction,
181 },
182 Self::Custom(error) => ExecutionError::Custom(error),
183 }
184 }
185}
186
187#[derive(Debug, Copy, Clone)]
189pub enum FetchInstructionResult<Instruction> {
190 Instruction(Instruction),
192 ControlFlow(ControlFlow<()>),
194}
195
196pub trait InstructionFetcher<I, Memory, CustomError>
198where
199 Self: ProgramCounter<Address<I>, Memory, CustomError>,
200 I: Instruction,
201{
202 fn fetch_instruction(
204 &mut self,
205 memory: &mut Memory,
206 ) -> Result<FetchInstructionResult<I>, ExecutionError<Address<I>, I, CustomError>>;
207}
208
209#[derive(Debug, Copy, Clone)]
211pub struct BasicInstructionFetcher<I, CustomError>
212where
213 I: Instruction,
214{
215 return_trap_address: Address<I>,
216 pc: Address<I>,
217 _phantom: PhantomData<CustomError>,
218}
219
220impl<I, Memory, CustomError> ProgramCounter<Address<I>, Memory, CustomError>
221 for BasicInstructionFetcher<I, CustomError>
222where
223 I: Instruction,
224 Memory: VirtualMemory,
225{
226 #[inline(always)]
227 fn get_pc(&self) -> Address<I> {
228 self.pc
229 }
230
231 #[inline]
232 fn set_pc(
233 &mut self,
234 memory: &mut Memory,
235 pc: Address<I>,
236 ) -> Result<ControlFlow<()>, ProgramCounterError<Address<I>, CustomError>> {
237 if pc == self.return_trap_address {
238 return Ok(ControlFlow::Break(()));
239 }
240
241 if !pc.into().is_multiple_of(u64::from(I::alignment())) {
242 return Err(ProgramCounterError::UnalignedInstruction { address: pc });
243 }
244
245 memory.read::<u32>(pc.into())?;
246
247 self.pc = pc;
248
249 Ok(ControlFlow::Continue(()))
250 }
251}
252
253impl<I, Memory, CustomError> InstructionFetcher<I, Memory, CustomError>
254 for BasicInstructionFetcher<I, CustomError>
255where
256 I: Instruction,
257 Memory: VirtualMemory,
258{
259 #[inline]
260 fn fetch_instruction(
261 &mut self,
262 memory: &mut Memory,
263 ) -> Result<FetchInstructionResult<I>, ExecutionError<Address<I>, I, CustomError>> {
264 let instruction = unsafe { memory.read_unchecked(self.pc.into()) };
268 let instruction = unsafe { I::try_decode(instruction).unwrap_unchecked() };
270 self.pc += instruction.size().into();
271
272 Ok(FetchInstructionResult::Instruction(instruction))
273 }
274}
275
276impl<I, CustomError> BasicInstructionFetcher<I, CustomError>
277where
278 I: Instruction,
279{
280 #[inline(always)]
289 pub unsafe fn new(return_trap_address: Address<I>, pc: Address<I>) -> Self {
290 Self {
291 return_trap_address,
292 pc,
293 _phantom: PhantomData,
294 }
295 }
296}
297
298pub trait ExecutableInstruction<State, CustomError>
300where
301 Self: Instruction,
302{
303 fn execute(
305 self,
306 state: &mut State,
307 ) -> Result<ControlFlow<()>, ExecutionError<Address<Self>, Self, CustomError>>;
308}