use asm::data::literal::{Addr, Value}; use asm::data::{Rd, SrcDisp, Register, Wr, DstDisp}; use crate::fault::Fault; use asm::instr::Cond; pub const REG_COUNT: usize = 8; #[derive(Default, Clone, Debug)] pub struct StatusFlags { /// Arguments are equal pub equal: bool, /// Register is zero pub zero: bool, /// A < B pub lower: bool, /// A > B pub greater: bool, /// Register is positive pub positive: bool, /// Register is negative pub negative: bool, /// Overflow (multiplication etc.) pub overflow: bool, /// Arithmetic carry pub carry: bool, } impl StatusFlags { pub fn clear(&mut self) { *self = Self::default(); } pub fn test(&self, cond: Cond) -> bool { match cond { Cond::Equal => self.equal, Cond::NotEqual => !self.equal, Cond::Zero => self.zero, Cond::NotZero => !self.zero, Cond::Lower => self.lower, Cond::LowerOrEqual => self.lower || self.equal, Cond::Greater => self.greater, Cond::GreaterOrEqual => self.greater || self.equal, Cond::Positive => self.positive, Cond::NonPositive => !self.positive, Cond::Negative => self.negative, Cond::NonNegative => !self.negative, Cond::Overflow => self.overflow, Cond::NotOverflow => !self.overflow, Cond::Carry => self.carry, Cond::NotCarry => !self.carry } } } #[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 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 { debug!("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 { debug!("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 { debug!("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> { debug!("WR {:?} := {}", wr, val); match wr.d() { DstDisp::ImmediatePtr(_) => { unimplemented!("Immediate ptr") } 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") } } } }