use status::StatusFlags; use crate::asm::data::{DstDisp, Rd, Register, SrcDisp, Wr}; use crate::asm::data::literal::{Addr, Value}; use super::fault::Fault; mod status; pub const REG_COUNT: usize = 8; pub type CallStack = Vec; #[derive(Default, Clone, Debug)] pub struct StackFrame { /// Program counter, address of the executed instruction pub pc: Addr, /// Status flags pub status: StatusFlags, /// Argument registers pub arg: [Value; REG_COUNT], /// Result registers pub res: [Value; REG_COUNT], /// General purpose registers pub gen: [Value; REG_COUNT], } impl StackFrame { /// Create a new stack frame at a given address pub fn new(addr: Addr, args: &[Value]) -> Self { let mut sf = StackFrame::default(); sf.pc = addr; for n in 0..(args.len().min(REG_COUNT)) { sf.arg[n] = args[n]; } sf } pub fn set_retvals(&mut self, vals: &[Value]) { for n in 0..(vals.len().min(REG_COUNT)) { self.res[n] = vals[n]; } } pub fn read(&mut self, rd: Rd) -> Result { match rd.d() { SrcDisp::Immediate(v) => Ok(v), SrcDisp::ImmediatePtr(_) => { unimplemented!("Immediate ptr") } SrcDisp::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.res[rn as usize]); Ok(self.res[rn as usize]) } } SrcDisp::Register(Register::Arg(rn)) => { if rn >= REG_COUNT as u8 { Err(Fault::RegisterNotExist { reg: Register::Arg(rn) }) } else { trace!("Rd {:?} = {}", rd, self.arg[rn as usize]); Ok(self.arg[rn as usize]) } } SrcDisp::Register(Register::Gen(rn)) => { if rn >= REG_COUNT as u8 { Err(Fault::RegisterNotExist { reg: Register::Gen(rn) }) } else { trace!("Rd {:?} = {}", rd, self.gen[rn as usize]); Ok(self.gen[rn as usize]) } } SrcDisp::RegisterPtr(_) => { unimplemented!("Register ptr") } } } pub fn write(&mut self, wr: Wr, val: Value) -> Result<(), Fault> { trace!("WR {:?} := {}", wr, val); match wr.d() { DstDisp::ImmediatePtr(_) => { unimplemented!("Immediate ptr") } DstDisp::Discard => { /* Discard */ Ok(()) } DstDisp::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) }) } } DstDisp::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) }) } } DstDisp::Register(Register::Gen(rn)) => { if rn >= REG_COUNT as u8 { Err(Fault::RegisterNotExist { reg: Register::Gen(rn) }) } else { self.gen[rn as usize] = val; Ok(()) } } DstDisp::RegisterPtr(_) => { unimplemented!("Register ptr") } } } }