Croissant Runtime
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
crsn/runtime/src/frame.rs

150 lines
4.9 KiB

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<u64, 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::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")
}
}
}
}