1#![feature(const_convert, const_trait_impl, control_flow_ok, widening_mul)]
2#![expect(incomplete_features, reason = "generic_const_exprs")]
3#![feature(generic_const_exprs)]
6#![no_std]
7
8pub mod rv64;
9
10use ab_riscv_primitives::instructions::Instruction;
11use ab_riscv_primitives::registers::general_purpose::Register;
12use core::marker::PhantomData;
13use core::ops::ControlFlow;
14
15type Address<I> = <<I as Instruction>::Reg as Register>::Type;
16
17#[derive(Debug, thiserror::Error)]
19pub enum VirtualMemoryError {
20 #[error("Out-of-bounds read at address {address}")]
22 OutOfBoundsRead {
23 address: u64,
25 },
26 #[error("Out-of-bounds write at address {address}")]
28 OutOfBoundsWrite {
29 address: u64,
31 },
32}
33
34mod private {
35 pub trait Sealed {}
36
37 impl Sealed for u8 {}
38 impl Sealed for u16 {}
39 impl Sealed for u32 {}
40 impl Sealed for u64 {}
41 impl Sealed for i8 {}
42 impl Sealed for i16 {}
43 impl Sealed for i32 {}
44 impl Sealed for i64 {}
45}
46
47pub trait BasicInt: Sized + Copy + private::Sealed {}
49
50impl BasicInt for u8 {}
51impl BasicInt for u16 {}
52impl BasicInt for u32 {}
53impl BasicInt for u64 {}
54impl BasicInt for i8 {}
55impl BasicInt for i16 {}
56impl BasicInt for i32 {}
57impl BasicInt for i64 {}
58
59pub trait VirtualMemory {
61 fn read<T>(&self, address: u64) -> Result<T, VirtualMemoryError>
63 where
64 T: BasicInt;
65
66 unsafe fn read_unchecked<T>(&self, address: u64) -> T
71 where
72 T: BasicInt;
73
74 fn write<T>(&mut self, address: u64, value: T) -> Result<(), VirtualMemoryError>
76 where
77 T: BasicInt;
78}
79
80#[derive(Debug, thiserror::Error)]
82pub enum ProgramCounterError<Address, Custom> {
83 #[error("Unaligned instruction at address {address}")]
85 UnalignedInstruction {
86 address: Address,
88 },
89 #[error("Memory access error: {0}")]
91 MemoryAccess(#[from] VirtualMemoryError),
92 #[error("Custom error: {0}")]
94 Custom(Custom),
95}
96
97pub trait ProgramCounter<Address, Memory, CustomError> {
99 fn get_pc(&self) -> Address;
101
102 fn set_pc(
104 &mut self,
105 memory: &mut Memory,
106 pc: Address,
107 ) -> Result<ControlFlow<()>, ProgramCounterError<Address, CustomError>>;
108}
109
110#[derive(Debug, thiserror::Error)]
112pub enum ExecutionError<Address, I, Custom> {
113 #[error("Unaligned instruction fetch at address {address}")]
115 UnalignedInstructionFetch {
116 address: Address,
118 },
119 #[error("Program counter error: {0}")]
121 ProgramCounter(#[from] ProgramCounterError<Address, Custom>),
122 #[error("Memory access error: {0}")]
124 MemoryAccess(#[from] VirtualMemoryError),
125 #[error("Unsupported instruction at address {address:#x}: {instruction}")]
127 UnsupportedInstruction {
128 address: Address,
130 instruction: I,
132 },
133 #[error("Unimplemented/illegal instruction at address {address:#x}")]
135 UnimpInstruction {
136 address: Address,
138 },
139 #[error("Invalid instruction at address {address:#x}: {instruction:#010x}")]
141 InvalidInstruction {
142 address: Address,
144 instruction: u32,
146 },
147 #[error("Custom error: {0}")]
149 Custom(Custom),
150}
151
152impl<Address, BI, Custom> ExecutionError<Address, BI, Custom> {
153 #[inline]
155 pub fn map_instruction<I>(self, map: fn(BI) -> I) -> ExecutionError<Address, I, Custom> {
156 match self {
157 Self::UnalignedInstructionFetch { address } => {
158 ExecutionError::UnalignedInstructionFetch { address }
159 }
160 Self::MemoryAccess(error) => ExecutionError::MemoryAccess(error),
161 Self::ProgramCounter(error) => ExecutionError::ProgramCounter(error),
162 Self::UnsupportedInstruction {
163 address,
164 instruction,
165 } => ExecutionError::UnsupportedInstruction {
166 address,
167 instruction: map(instruction),
168 },
169 Self::UnimpInstruction { address } => ExecutionError::UnimpInstruction { address },
170 Self::InvalidInstruction {
171 address,
172 instruction,
173 } => ExecutionError::InvalidInstruction {
174 address,
175 instruction,
176 },
177 Self::Custom(error) => ExecutionError::Custom(error),
178 }
179 }
180}
181
182#[derive(Debug, Copy, Clone)]
184pub enum FetchInstructionResult<Instruction> {
185 Instruction(Instruction),
187 ControlFlow(ControlFlow<()>),
189}
190
191pub trait InstructionFetcher<I, Memory, CustomError>
193where
194 Self: ProgramCounter<Address<I>, Memory, CustomError>,
195 I: Instruction,
196{
197 fn fetch_instruction(
199 &mut self,
200 memory: &mut Memory,
201 ) -> Result<FetchInstructionResult<I>, ExecutionError<Address<I>, I, CustomError>>;
202}
203
204#[derive(Debug, Copy, Clone)]
206pub struct BasicInstructionFetcher<I, CustomError>
207where
208 I: Instruction,
209{
210 return_trap_address: Address<I>,
211 pc: Address<I>,
212 _phantom: PhantomData<CustomError>,
213}
214
215impl<I, Memory, CustomError> ProgramCounter<Address<I>, Memory, CustomError>
216 for BasicInstructionFetcher<I, CustomError>
217where
218 I: Instruction,
219 Memory: VirtualMemory,
220{
221 #[inline(always)]
222 fn get_pc(&self) -> Address<I> {
223 self.pc
224 }
225
226 #[inline]
227 fn set_pc(
228 &mut self,
229 memory: &mut Memory,
230 pc: Address<I>,
231 ) -> Result<ControlFlow<()>, ProgramCounterError<Address<I>, CustomError>> {
232 if pc == self.return_trap_address {
233 return Ok(ControlFlow::Break(()));
234 }
235
236 if !pc.into().is_multiple_of(u64::from(I::alignment())) {
237 return Err(ProgramCounterError::UnalignedInstruction { address: pc });
238 }
239
240 memory.read::<u32>(pc.into())?;
241
242 self.pc = pc;
243
244 Ok(ControlFlow::Continue(()))
245 }
246}
247
248impl<I, Memory, CustomError> InstructionFetcher<I, Memory, CustomError>
249 for BasicInstructionFetcher<I, CustomError>
250where
251 I: Instruction,
252 Memory: VirtualMemory,
253{
254 #[inline]
255 fn fetch_instruction(
256 &mut self,
257 memory: &mut Memory,
258 ) -> Result<FetchInstructionResult<I>, ExecutionError<Address<I>, I, CustomError>> {
259 let instruction = unsafe { memory.read_unchecked(self.pc.into()) };
263 let instruction = unsafe { I::try_decode(instruction).unwrap_unchecked() };
265 self.pc += instruction.size().into();
266
267 Ok(FetchInstructionResult::Instruction(instruction))
268 }
269}
270
271impl<I, CustomError> BasicInstructionFetcher<I, CustomError>
272where
273 I: Instruction,
274{
275 #[inline(always)]
284 pub unsafe fn new(return_trap_address: Address<I>, pc: Address<I>) -> Self {
285 Self {
286 return_trap_address,
287 pc,
288 _phantom: PhantomData,
289 }
290 }
291}
292
293pub trait ExecutableInstruction<State, CustomError>
295where
296 Self: Instruction,
297{
298 fn execute(
300 self,
301 state: &mut State,
302 ) -> Result<ControlFlow<()>, ExecutionError<Address<Self>, Self, CustomError>>;
303}