|
|
|
use std::any::{Any, TypeId};
|
|
|
|
use std::collections::HashMap;
|
|
|
|
|
|
|
|
use crate::asm::data::{WrData, Rd, Register, RdData, Wr, RdObj};
|
|
|
|
use crate::asm::data::literal::{Addr, Value};
|
|
|
|
use crate::asm::instr::Cond;
|
|
|
|
use crate::runtime::fault::Fault;
|
|
|
|
use crate::runtime::frame::{CallStack, REG_COUNT, StackFrame};
|
|
|
|
|
|
|
|
pub struct RunState {
|
|
|
|
/// Active stack frame
|
|
|
|
pub frame: StackFrame,
|
|
|
|
/// Call stack
|
|
|
|
pub call_stack: CallStack,
|
|
|
|
/// Extension data
|
|
|
|
pub ext_data: HashMap<TypeId, Box<dyn Any + Send>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RunState {
|
|
|
|
/// Get an extension's persistent data object for mutation.
|
|
|
|
/// It will be created using Default if not present before.
|
|
|
|
pub fn ext_mut<T: Send + Default + 'static>(&mut self) -> &mut T {
|
|
|
|
if !self.ext_data.contains_key(&TypeId::of::<T>()) {
|
|
|
|
self.ext_data.insert(TypeId::of::<T>(), Box::new(T::default()));
|
|
|
|
}
|
|
|
|
|
|
|
|
self.ext_data.get_mut(&TypeId::of::<T>()).unwrap()
|
|
|
|
.downcast_mut().unwrap()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Set a status flag. Only supports simple, positive conds (i.e. not GreaterOrEqual)
|
|
|
|
pub fn set_flag(&mut self, cond: Cond, set: bool) {
|
|
|
|
if set {
|
|
|
|
self.frame.status.set(cond);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Check status flags for a condition
|
|
|
|
pub fn test_cond(&self, cond: Cond) -> bool {
|
|
|
|
self.frame.status.test(cond)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Set program counter - address of the next instruction to run
|
|
|
|
pub fn set_pc(&mut self, pc: Addr) {
|
|
|
|
self.frame.pc = pc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get program counter - address of the next instruction to run
|
|
|
|
pub fn get_pc(&self) -> Addr {
|
|
|
|
self.frame.pc
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Clear status flags
|
|
|
|
pub fn clear_status(&mut self) {
|
|
|
|
self.frame.status.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Update status flags using a variable.
|
|
|
|
/// The update is additive - call `clear_status()` first if desired!
|
|
|
|
pub fn update_status(&mut self, val: Value) {
|
|
|
|
self.frame.status.update(val);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Read object handle value
|
|
|
|
pub fn read_obj(&mut self, rdo: RdObj) -> Result<Value, Fault> {
|
|
|
|
self.read(Rd::new(RdData::Register(rdo.reg())))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Read a `Rd` value
|
|
|
|
pub fn read(&mut self, rd: Rd) -> Result<Value, Fault> {
|
|
|
|
match rd.data() {
|
|
|
|
RdData::Immediate(v) => Ok(v),
|
|
|
|
RdData::Register(Register::Res(rn)) => {
|
|
|
|
if rn >= REG_COUNT as u8 {
|
|
|
|
Err(Fault::RegisterNotExist { reg: Register::Res(rn) }) // TODO use match after @ when stabilized https://github.com/rust-lang/rust/issues/65490
|
|
|
|
} else {
|
|
|
|
trace!("Rd {:?} = {}", rd, self.frame.res[rn as usize]);
|
|
|
|
Ok(self.frame.res[rn as usize])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
RdData::Register(Register::Arg(rn)) => {
|
|
|
|
if rn >= REG_COUNT as u8 {
|
|
|
|
Err(Fault::RegisterNotExist { reg: Register::Arg(rn) })
|
|
|
|
} else {
|
|
|
|
trace!("Rd {:?} = {}", rd, self.frame.arg[rn as usize]);
|
|
|
|
Ok(self.frame.arg[rn as usize])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
RdData::Register(Register::Gen(rn)) => {
|
|
|
|
if rn >= REG_COUNT as u8 {
|
|
|
|
Err(Fault::RegisterNotExist { reg: Register::Gen(rn) })
|
|
|
|
} else {
|
|
|
|
trace!("Rd {:?} = {}", rd, self.frame.gen[rn as usize]);
|
|
|
|
Ok(self.frame.gen[rn as usize])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
RdData::ObjectPtr(_) => {
|
|
|
|
unimplemented!("Read object ptr")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Write a value to a `Wr` location
|
|
|
|
pub fn write(&mut self, wr: Wr, val: Value) -> Result<(), Fault> {
|
|
|
|
trace!("WR {:?} := {}", wr, val);
|
|
|
|
|
|
|
|
match wr.d() {
|
|
|
|
WrData::Discard => {
|
|
|
|
/* Discard */
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
WrData::Register(Register::Res(rn)) => {
|
|
|
|
if rn >= REG_COUNT as u8 {
|
|
|
|
Err(Fault::RegisterNotExist { reg: Register::Res(rn) }) // TODO use match after @ when stabilized https://github.com/rust-lang/rust/issues/65490
|
|
|
|
} else {
|
|
|
|
Err(Fault::RegisterNotWritable { reg: Register::Res(rn) })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
WrData::Register(Register::Arg(rn)) => {
|
|
|
|
if rn >= REG_COUNT as u8 {
|
|
|
|
Err(Fault::RegisterNotExist { reg: Register::Arg(rn) })
|
|
|
|
} else {
|
|
|
|
Err(Fault::RegisterNotWritable { reg: Register::Res(rn) })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
WrData::Register(Register::Gen(rn)) => {
|
|
|
|
if rn >= REG_COUNT as u8 {
|
|
|
|
Err(Fault::RegisterNotExist { reg: Register::Gen(rn) })
|
|
|
|
} else {
|
|
|
|
self.frame.gen[rn as usize] = val;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
WrData::ObjectPtr(_) => {
|
|
|
|
unimplemented!("Write object ptr")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|