implement call, ret, far jumps, add, sub

This commit is contained in:
2020-09-24 23:55:25 +02:00
parent 5f4fd0e806
commit 88a4d77b8f
8 changed files with 350 additions and 13 deletions
+118 -4
View File
@@ -2,7 +2,7 @@ use crate::run_thread::{ThreadToken, RunThread};
use asm::instr::{Op, Cond};
use crate::fault::Fault;
use crate::frame::StackFrame;
use asm::data::literal::{Value, is_positive, is_negative};
use asm::data::literal::{Value, is_positive, is_negative, Addr};
pub type CyclesSpent = usize;
@@ -40,21 +40,73 @@ impl RunThread {
msg: msg.clone().unwrap_or_else(|| "No msg".into())
})
}
Op::FarJump(_) => unimplemented!(),
Op::Call(_, _) => unimplemented!(),
Op::Ret(_) => unimplemented!(),
Op::FarJump(name) => {
debug!("Far jump to {}", name);
match self.program.find_far_label(name) {
Ok(pos) => {
debug!("label is at {}", pos);
self.frame.pc = pos;
}
Err(e) => {
return Err(e);
}
}
},
Op::Call(name, args) => {
debug!("Call routine {}", name);
match self.program.find_routine(name) {
Ok(pos) => {
debug!("routine is at {}", pos);
let mut values = Vec::with_capacity(args.len());
for arg in args {
values.push(self.frame.read(*arg)?);
}
let mut frame2 = StackFrame::new(pos, &values);
std::mem::swap(&mut self.frame, &mut frame2);
self.call_stack.push(frame2);
advance = 0;
}
Err(e) => {
return Err(e);
}
}
},
Op::Ret(retvals) => {
match self.call_stack.pop() {
Some(previous) => {
let mut values = Vec::with_capacity(retvals.len());
for arg in retvals {
values.push(frame.read(*arg)?);
}
*frame = previous;
frame.set_retvals(&values);
advance = 1; // advance past the call
}
None => {
return Err(Fault::CallStackUnderflow);
}
}
},
Op::Skip(val) => {
let steps = frame.read(*val)?;
advance = i64::from_ne_bytes(steps.to_ne_bytes());
self.program.validate_jump(frame.pc, Addr((frame.pc.0 as i64 + advance) as u64))?;
}
Op::SkipIf(cond, val) => {
if frame.status.test(*cond) {
let steps = frame.read(*val)?;
advance = i64::from_ne_bytes(steps.to_ne_bytes());
self.program.validate_jump(frame.pc, Addr((frame.pc.0 as i64 + advance) as u64))?;
}
}
Op::Mov(dst, src) => {
frame.status.clear();
let val = frame.read(*src)?;
frame.status.zero = (val == 0);
frame.status.positive = is_positive(val);
frame.status.negative = is_negative(val);
frame.write(*dst, val)?;
}
Op::Cmp(a, b) => {
@@ -88,6 +140,68 @@ impl RunThread {
frame.status.negative = is_negative(val);
frame.write(*reg, val)?;
}
Op::Add(dst, src) => {
frame.status.clear();
let mut a = frame.read(dst.as_rd())?;
let mut b = frame.read(*src)?;
let val = a.wrapping_add(b);
frame.status.zero = (val == 0);
frame.status.positive = is_positive(val);
frame.status.negative = is_negative(val);
frame.status.overflow = b > Value::MAX - a; // TODO check
// TODO carry?
frame.write(*dst, val)?;
}
Op::Sub(dst, src) => {
frame.status.clear();
let mut a = frame.read(dst.as_rd())?;
let mut b = frame.read(*src)?;
let val = a.wrapping_sub(b);
frame.status.zero = (val == 0);
frame.status.positive = is_positive(val);
frame.status.negative = is_negative(val);
frame.status.overflow = b > a;
// TODO carry?
frame.write(*dst, val)?;
}
Op::Mul(_, _) => {
unimplemented!()
}
Op::Div(_, _) => {
unimplemented!()
}
Op::Mod(_, _, _) => {
unimplemented!()
}
Op::And(_, _) => {
unimplemented!()
}
Op::Or(_, _) => {
unimplemented!()
}
Op::Xor(_, _) => {
unimplemented!()
}
Op::Cpl(_) => {
unimplemented!()
}
Op::Rol(_, _) => {
unimplemented!()
}
Op::Ror(_, _) => {
unimplemented!()
}
Op::Lsl(_, _) => {
unimplemented!()
}
Op::Lsr(_, _) => {
unimplemented!()
}
Op::Asr(_, _) => {
unimplemented!()
}
}
Ok(EvalRes {
+19 -1
View File
@@ -2,7 +2,7 @@ use thiserror::Error;
use super::span::MemorySpan;
use crate::run_thread::ThreadToken;
use crate::mlock::ClaimId;
use asm::data::literal::DebugMsg;
use asm::data::literal::{DebugMsg, RoutineName, Label};
use asm::data::Register;
#[derive(Error,Debug)]
@@ -44,6 +44,24 @@ pub enum Fault {
RegisterNotWritable {
reg: Register,
},
#[error("Called undefined routine: {routine}")]
NoSuchRoutine {
routine: RoutineName,
},
#[error("Jump to undefined far label: {label}")]
NoSuchFarLabel {
label: Label,
},
#[error("Crossed a barrier: {msg}")]
JumpThroughBarrier {
msg: DebugMsg,
},
#[error("Call stack underflow")]
CallStackUnderflow,
}
#[derive(Error,Debug)]
+6
View File
@@ -77,6 +77,12 @@ impl StackFrame {
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<u64, Fault> {
match rd.d() {
SrcDisp::Immediate(v) => Ok(v),
+65 -4
View File
@@ -1,18 +1,47 @@
use asm::instr::Op;
use asm::data::literal::Addr;
use asm::instr::{Op};
use asm::data::literal::{Addr, RoutineName, Label};
use crate::fault::Fault;
use std::collections::HashMap;
#[derive(Clone, Debug)]
pub struct Program {
ops: Vec<Op>,
routines: HashMap<RoutineName, Addr>,
far_labels: HashMap<Label, Addr>,
barriers: Vec<Addr>,
}
impl Program {
pub fn new(ops : Vec<Op>) -> Self {
Self {
pub fn new(ops: Vec<Op>) -> Self {
let mut p = Self {
ops,
routines: Default::default(),
far_labels: Default::default(),
barriers: Default::default(),
};
p.scan();
p
}
/// Find all the named things
fn scan(&mut self) {
for (pos, op) in self.ops.iter().enumerate() {
match op {
Op::FarLabel(name) => {
self.far_labels.insert(name.clone(), pos.into());
}
Op::Routine(name) => {
self.routines.insert(name.clone(), pos.into());
}
Op::Barrier(_) => {
self.barriers.push(pos.into());
}
_ => {}
}
}
}
/// Read a program instruction at address
pub fn read(&self, addr: Addr) -> &Op {
if addr.0 >= self.ops.len() as u64 {
&Op::Nop
@@ -20,5 +49,37 @@ impl Program {
&self.ops[addr.0 as usize]
}
}
/// Return error if any barrier is crossed during a jump / skip
pub fn validate_jump(&self, mut from: Addr, mut to: Addr) -> Result<(), Fault> {
if from > to {
std::mem::swap(&mut from, &mut to);
}
for b in &self.barriers {
if *b >= from && *b <= to {
if let Op::Barrier(msg) = self.read(*b) {
return Err(Fault::JumpThroughBarrier {
msg: msg.clone().unwrap_or("No msg".into())
});
} else {
unreachable!();
}
}
}
Ok(())
}
/// Find routine by name
pub fn find_routine(&self, name: &RoutineName) -> Result<Addr, Fault> {
self.routines.get(name).copied()
.ok_or_else(|| Fault::NoSuchRoutine { routine: name.clone() })
}
/// Find far label by name
pub fn find_far_label(&self, name: &Label) -> Result<Addr, Fault> {
self.far_labels.get(name).copied()
.ok_or_else(|| Fault::NoSuchFarLabel { label: name.clone() })
}
}