|
|
|
use asm::data::literal::{Addr, Value};
|
|
|
|
use asm::data::{Rd, SrcDisp, Register, Wr, DstDisp};
|
|
|
|
use crate::fault::Fault;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mod status;
|
|
|
|
use status::StatusFlags;
|
|
|
|
|
|
|
|
pub const REG_COUNT: usize = 8;
|
|
|
|
|
|
|
|
#[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<Value, Fault> {
|
|
|
|
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::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")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|