#[cfg(test)]
mod tests;
use crate::{
Address, CustomErrorPlaceholder, ExecutionError, FetchInstructionResult, InstructionFetcher,
ProgramCounter, ProgramCounterError, RegisterFile, VirtualMemory,
};
use ab_riscv_primitives::prelude::*;
use core::marker::PhantomData;
use core::ops::ControlFlow;
pub const unsafe trait BasicRegister
where
Self: [const] Register,
{
const N: usize;
fn offset(self) -> u8;
}
unsafe impl<Type> const BasicRegister for EReg<Type>
where
Self: [const] Register,
{
const N: usize = 16;
#[inline(always)]
fn offset(self) -> u8 {
unsafe { core::mem::transmute::<Self, u8>(self) }
}
}
unsafe impl<Type> const BasicRegister for Reg<Type>
where
Self: [const] Register,
{
const N: usize = 32;
#[inline(always)]
fn offset(self) -> u8 {
unsafe { core::mem::transmute::<Self, u8>(self) }
}
}
#[derive(Debug, Clone, Copy)]
#[repr(align(16))]
pub struct BasicRegisters<Reg>
where
Reg: BasicRegister,
[(); Reg::N]:,
{
regs: [Reg::Type; Reg::N],
}
impl<Reg> Default for BasicRegisters<Reg>
where
Reg: BasicRegister,
[(); Reg::N]:,
{
#[inline(always)]
fn default() -> Self {
Self {
regs: [Reg::Type::default(); Reg::N],
}
}
}
impl<Reg> const RegisterFile<Reg> for BasicRegisters<Reg>
where
Reg: [const] BasicRegister,
[(); Reg::N]:,
{
#[inline(always)]
fn read(&self, reg: Reg) -> Reg::Type {
if reg == Reg::ZERO {
return Reg::Type::default();
}
*unsafe { self.regs.get_unchecked(usize::from(reg.offset())) }
}
#[inline(always)]
fn write(&mut self, reg: Reg, value: Reg::Type) {
if reg == Reg::ZERO {
return;
}
*unsafe { self.regs.get_unchecked_mut(usize::from(reg.offset())) } = value;
}
}
#[derive(Debug)]
pub struct BasicInterpreterState<Regs, ExtState, Memory, IF, InstructionHandler> {
pub regs: Regs,
pub ext_state: ExtState,
pub memory: Memory,
pub instruction_fetcher: IF,
pub system_instruction_handler: InstructionHandler,
}
#[derive(Debug, Copy, Clone)]
pub struct BasicInstructionFetcher<I, CustomError = CustomErrorPlaceholder>
where
I: Instruction,
{
return_trap_address: Address<I>,
pc: Address<I>,
_phantom: PhantomData<CustomError>,
}
impl<I, Memory, CustomError> ProgramCounter<Address<I>, Memory, CustomError>
for BasicInstructionFetcher<I, CustomError>
where
I: Instruction,
Memory: VirtualMemory,
{
#[inline(always)]
fn get_pc(&self) -> Address<I> {
self.pc
}
#[inline]
fn set_pc(
&mut self,
_memory: &Memory,
pc: Address<I>,
) -> Result<ControlFlow<()>, ProgramCounterError<Address<I>, CustomError>> {
if pc == self.return_trap_address {
return Ok(ControlFlow::Break(()));
}
if !pc.as_u64().is_multiple_of(u64::from(I::alignment())) {
return Err(ProgramCounterError::UnalignedInstruction { address: pc });
}
self.pc = pc;
Ok(ControlFlow::Continue(()))
}
}
impl<I, Memory, CustomError> InstructionFetcher<I, Memory, CustomError>
for BasicInstructionFetcher<I, CustomError>
where
I: Instruction,
Memory: VirtualMemory,
{
#[inline]
fn fetch_instruction(
&mut self,
memory: &Memory,
) -> Result<FetchInstructionResult<I>, ExecutionError<Address<I>, CustomError>> {
let instruction = memory.read(self.pc.as_u64()).or_else(|error| {
if let Ok(instruction) = memory.read::<u16>(self.pc.as_u64())
&& (instruction & 0b11) != 0b11
{
return Ok(u32::from(instruction));
}
Err(error)
})?;
let instruction = I::try_decode(instruction)
.ok_or(ExecutionError::IllegalInstruction { address: self.pc })?;
self.pc += instruction.size().into();
Ok(FetchInstructionResult::Instruction(instruction))
}
}
impl<I, CustomError> BasicInstructionFetcher<I, CustomError>
where
I: Instruction,
{
#[inline(always)]
pub fn new(return_trap_address: Address<I>, pc: Address<I>) -> Self {
Self {
return_trap_address,
pc,
_phantom: PhantomData,
}
}
}