1#![feature(widening_mul)]
20#![expect(incomplete_features, reason = "generic_const_exprs")]
21#![feature(generic_const_exprs)]
24#![no_std]
25
26pub mod rv64;
27
28use ab_riscv_primitives::instructions::Instruction;
29use ab_riscv_primitives::registers::general_purpose::Register;
30use core::marker::PhantomData;
31use core::ops::ControlFlow;
32
33type Address<I> = <<I as Instruction>::Reg as Register>::Type;
34
35#[derive(Debug, thiserror::Error)]
37pub enum VirtualMemoryError {
38 #[error("Out-of-bounds read at address {address}")]
40 OutOfBoundsRead {
41 address: u64,
43 },
44 #[error("Out-of-bounds write at address {address}")]
46 OutOfBoundsWrite {
47 address: u64,
49 },
50}
51
52mod private {
53 pub trait Sealed {}
54
55 impl Sealed for u8 {}
56 impl Sealed for u16 {}
57 impl Sealed for u32 {}
58 impl Sealed for u64 {}
59 impl Sealed for i8 {}
60 impl Sealed for i16 {}
61 impl Sealed for i32 {}
62 impl Sealed for i64 {}
63}
64
65pub trait BasicInt: Sized + Copy + private::Sealed {}
67
68impl BasicInt for u8 {}
69impl BasicInt for u16 {}
70impl BasicInt for u32 {}
71impl BasicInt for u64 {}
72impl BasicInt for i8 {}
73impl BasicInt for i16 {}
74impl BasicInt for i32 {}
75impl BasicInt for i64 {}
76
77pub trait VirtualMemory {
79 fn read<T>(&self, address: u64) -> Result<T, VirtualMemoryError>
81 where
82 T: BasicInt;
83
84 unsafe fn read_unchecked<T>(&self, address: u64) -> T
89 where
90 T: BasicInt;
91
92 fn write<T>(&mut self, address: u64, value: T) -> Result<(), VirtualMemoryError>
94 where
95 T: BasicInt;
96}
97
98#[derive(Debug, thiserror::Error)]
100pub enum ProgramCounterError<Address, Custom> {
101 #[error("Unaligned instruction at address {address}")]
103 UnalignedInstruction {
104 address: Address,
106 },
107 #[error("Memory access error: {0}")]
109 MemoryAccess(#[from] VirtualMemoryError),
110 #[error("Custom error: {0}")]
112 Custom(Custom),
113}
114
115pub trait ProgramCounter<Address, Memory, CustomError> {
117 fn get_pc(&self) -> Address;
119
120 fn set_pc(
122 &mut self,
123 memory: &mut Memory,
124 pc: Address,
125 ) -> Result<ControlFlow<()>, ProgramCounterError<Address, CustomError>>;
126}
127
128#[derive(Debug, thiserror::Error)]
130pub enum ExecutionError<Address, I, Custom> {
131 #[error("Unaligned instruction fetch at address {address}")]
133 UnalignedInstructionFetch {
134 address: Address,
136 },
137 #[error("Program counter error: {0}")]
139 ProgramCounter(#[from] ProgramCounterError<Address, Custom>),
140 #[error("Memory access error: {0}")]
142 MemoryAccess(#[from] VirtualMemoryError),
143 #[error("Unsupported instruction at address {address:#x}: {instruction}")]
145 UnsupportedInstruction {
146 address: Address,
148 instruction: I,
150 },
151 #[error("Unimplemented/illegal instruction at address {address:#x}")]
153 UnimpInstruction {
154 address: Address,
156 },
157 #[error("Invalid instruction at address {address:#x}: {instruction:#010x}")]
159 InvalidInstruction {
160 address: Address,
162 instruction: u32,
164 },
165 #[error("Custom error: {0}")]
167 Custom(Custom),
168}
169
170impl<Address, BI, Custom> ExecutionError<Address, BI, Custom> {
171 #[inline]
173 pub fn map_instruction<I>(self, map: fn(BI) -> I) -> ExecutionError<Address, I, Custom> {
174 match self {
175 Self::UnalignedInstructionFetch { address } => {
176 ExecutionError::UnalignedInstructionFetch { address }
177 }
178 Self::MemoryAccess(error) => ExecutionError::MemoryAccess(error),
179 Self::ProgramCounter(error) => ExecutionError::ProgramCounter(error),
180 Self::UnsupportedInstruction {
181 address,
182 instruction,
183 } => ExecutionError::UnsupportedInstruction {
184 address,
185 instruction: map(instruction),
186 },
187 Self::UnimpInstruction { address } => ExecutionError::UnimpInstruction { address },
188 Self::InvalidInstruction {
189 address,
190 instruction,
191 } => ExecutionError::InvalidInstruction {
192 address,
193 instruction,
194 },
195 Self::Custom(error) => ExecutionError::Custom(error),
196 }
197 }
198}
199
200#[derive(Debug, Copy, Clone)]
202pub enum FetchInstructionResult<Instruction> {
203 Instruction(Instruction),
205 ControlFlow(ControlFlow<()>),
207}
208
209pub trait InstructionFetcher<I, Memory, CustomError>
211where
212 Self: ProgramCounter<Address<I>, Memory, CustomError>,
213 I: Instruction,
214{
215 fn fetch_instruction(
217 &mut self,
218 memory: &mut Memory,
219 ) -> Result<FetchInstructionResult<I>, ExecutionError<Address<I>, I, CustomError>>;
220}
221
222#[derive(Debug, Copy, Clone)]
224pub struct BasicInstructionFetcher<I, CustomError>
225where
226 I: Instruction,
227{
228 return_trap_address: Address<I>,
229 pc: Address<I>,
230 _phantom: PhantomData<CustomError>,
231}
232
233impl<I, Memory, CustomError> ProgramCounter<Address<I>, Memory, CustomError>
234 for BasicInstructionFetcher<I, CustomError>
235where
236 I: Instruction,
237 Memory: VirtualMemory,
238{
239 #[inline(always)]
240 fn get_pc(&self) -> Address<I> {
241 self.pc
242 }
243
244 #[inline]
245 fn set_pc(
246 &mut self,
247 memory: &mut Memory,
248 pc: Address<I>,
249 ) -> Result<ControlFlow<()>, ProgramCounterError<Address<I>, CustomError>> {
250 if pc == self.return_trap_address {
251 return Ok(ControlFlow::Break(()));
252 }
253
254 if !pc.into().is_multiple_of(u64::from(I::alignment())) {
255 return Err(ProgramCounterError::UnalignedInstruction { address: pc });
256 }
257
258 memory.read::<u32>(pc.into())?;
259
260 self.pc = pc;
261
262 Ok(ControlFlow::Continue(()))
263 }
264}
265
266impl<I, Memory, CustomError> InstructionFetcher<I, Memory, CustomError>
267 for BasicInstructionFetcher<I, CustomError>
268where
269 I: Instruction,
270 Memory: VirtualMemory,
271{
272 #[inline]
273 fn fetch_instruction(
274 &mut self,
275 memory: &mut Memory,
276 ) -> Result<FetchInstructionResult<I>, ExecutionError<Address<I>, I, CustomError>> {
277 let instruction = unsafe { memory.read_unchecked(self.pc.into()) };
281 let instruction = unsafe { I::try_decode(instruction).unwrap_unchecked() };
283 self.pc += instruction.size().into();
284
285 Ok(FetchInstructionResult::Instruction(instruction))
286 }
287}
288
289impl<I, CustomError> BasicInstructionFetcher<I, CustomError>
290where
291 I: Instruction,
292{
293 #[inline(always)]
302 pub unsafe fn new(return_trap_address: Address<I>, pc: Address<I>) -> Self {
303 Self {
304 return_trap_address,
305 pc,
306 _phantom: PhantomData,
307 }
308 }
309}
310
311pub trait ExecutableInstruction<State, CustomError>
313where
314 Self: Instruction,
315{
316 fn execute(
318 self,
319 state: &mut State,
320 ) -> Result<ControlFlow<()>, ExecutionError<Address<Self>, Self, CustomError>>;
321}