use std::any::{Any, TypeId}; use std::collections::HashMap; use crate::asm::data::{Rd, RdData, RdObj, Register, Wr, WrData}; 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>, } 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(&mut self) -> &mut T { if !self.ext_data.contains_key(&TypeId::of::()) { self.ext_data.insert(TypeId::of::(), Box::new(T::default())); } self.ext_data.get_mut(&TypeId::of::()).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 { self.read(Rd::new(RdData::Register(rdo.reg()))) } /// Read a `Rd` value pub fn read(&mut self, rd: Rd) -> Result { 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") } } } }