From 88a4d77b8fd721528fb0b9534682ed932eea55b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Thu, 24 Sep 2020 23:55:25 +0200 Subject: [PATCH] implement call, ret, far jumps, add, sub --- asm/src/data/literal.rs | 8 ++- asm/src/instr/op.rs | 20 ++++++- asm/src/parse/parse_op.rs | 98 ++++++++++++++++++++++++++++++ crsn/src/main.rs | 20 ++++++- runtime/src/exec/mod.rs | 122 ++++++++++++++++++++++++++++++++++++-- runtime/src/fault.rs | 20 ++++++- runtime/src/frame.rs | 6 ++ runtime/src/program.rs | 69 +++++++++++++++++++-- 8 files changed, 350 insertions(+), 13 deletions(-) diff --git a/asm/src/data/literal.rs b/asm/src/data/literal.rs index 35b7bb8..00d95bf 100644 --- a/asm/src/data/literal.rs +++ b/asm/src/data/literal.rs @@ -50,6 +50,12 @@ impl From for Addr { } } +impl From for Addr { + fn from(n: usize) -> Self { + Self(n as u64) + } +} + impl From for u64 { fn from(addr: Addr) -> Self { addr.0 @@ -92,7 +98,7 @@ impl From for Label { } /// Routine name -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct RoutineName(pub String); impl Display for RoutineName { diff --git a/asm/src/instr/op.rs b/asm/src/instr/op.rs index fe0705b..2f624cf 100644 --- a/asm/src/instr/op.rs +++ b/asm/src/instr/op.rs @@ -53,10 +53,26 @@ pub enum Op { /// Compare two values and set conditional flags. /// If the values are identical, evaluate if they are zero, positive, or negative (the "tst" op) Cmp(Rd, Rd), - // Increment a value + + // Arithmetic Inc(Wr), - // Decrement a value Dec(Wr), + Add(Wr, Rd), + Sub(Wr, Rd), + Mul(Wr, Rd), + Div(Wr, Rd), + Mod(Wr, /*rem*/Wr, Rd), + + // /// Bitwise + And(Wr, Rd), + Or(Wr, Rd), + Xor(Wr, Rd), + Cpl(Wr), + Rol(Wr, Rd), // Rotate (with wrap-around) + Ror(Wr, Rd), + Lsl(Wr, Rd), // Shift + Lsr(Wr, Rd), + Asr(Wr, Rd), // TODO arithmetics, bit manipulation, byte operations } diff --git a/asm/src/parse/parse_op.rs b/asm/src/parse/parse_op.rs index 64e9b87..535a4f6 100644 --- a/asm/src/parse/parse_op.rs +++ b/asm/src/parse/parse_op.rs @@ -101,6 +101,104 @@ pub fn parse_op(keyword: &str, far : bool, mut arg_tokens: impl Iterator { + HLOp::L(Op::Add( + parse_wr(arg_tokens.next())?, + parse_rd(arg_tokens.next())? + )) + } + + "sub" => { + HLOp::L(Op::Sub( + parse_wr(arg_tokens.next())?, + parse_rd(arg_tokens.next())? + )) + } + + "mul" => { + HLOp::L(Op::Mul( + parse_wr(arg_tokens.next())?, + parse_rd(arg_tokens.next())? + )) + } + + "div" => { + HLOp::L(Op::Div( + parse_wr(arg_tokens.next())?, + parse_rd(arg_tokens.next())? + )) + } + + "mod" => { + HLOp::L(Op::Mod( + parse_wr(arg_tokens.next())?, + parse_wr(arg_tokens.next())?, + parse_rd(arg_tokens.next())? + )) + } + + "and" => { + HLOp::L(Op::And( + parse_wr(arg_tokens.next())?, + parse_rd(arg_tokens.next())? + )) + } + + "or" => { + HLOp::L(Op::Or( + parse_wr(arg_tokens.next())?, + parse_rd(arg_tokens.next())? + )) + } + + "xor" => { + HLOp::L(Op::Xor( + parse_wr(arg_tokens.next())?, + parse_rd(arg_tokens.next())? + )) + } + + "cpl" => { + HLOp::L(Op::Cpl( + parse_wr(arg_tokens.next())? + )) + } + + "rol" => { + HLOp::L(Op::Rol( + parse_wr(arg_tokens.next())?, + parse_rd(arg_tokens.next())? + )) + } + + "ror" => { + HLOp::L(Op::Ror( + parse_wr(arg_tokens.next())?, + parse_rd(arg_tokens.next())? + )) + } + + "lsl" | "asl" => { + HLOp::L(Op::Lsl( + parse_wr(arg_tokens.next())?, + parse_rd(arg_tokens.next())? + )) + } + + "lsr" => { + HLOp::L(Op::Lsr( + parse_wr(arg_tokens.next())?, + parse_rd(arg_tokens.next())? + )) + } + + "asr" => { + HLOp::L(Op::Asr( + parse_wr(arg_tokens.next())?, + parse_rd(arg_tokens.next())? + )) + } + // TODO more instructions other => { diff --git a/crsn/src/main.rs b/crsn/src/main.rs index 5d57aff..3612ca3 100644 --- a/crsn/src/main.rs +++ b/crsn/src/main.rs @@ -10,7 +10,7 @@ fn main() { SimpleLogger::new().init().unwrap(); // ;(dec r0 (z? (ret))) - let program = " + /*let program = " ( (main (ld r0 2) @@ -20,6 +20,24 @@ fn main() { (fault \"that's it\") ) ) + ";*/ + + let program = " + ( + (main + (ld r0 2) + (call add2x r0 15) + (ld r0 res0) + (fault \"that's it\") + ) + (add2x + (ld r0 arg0) + (ld r1 arg1) + (add r0 r1) + (add r0 r1) + (ret r0) + ) + ) "; let parsed = asm::assemble(program).unwrap(); diff --git a/runtime/src/exec/mod.rs b/runtime/src/exec/mod.rs index e17d7a3..f68881d 100644 --- a/runtime/src/exec/mod.rs +++ b/runtime/src/exec/mod.rs @@ -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 { diff --git a/runtime/src/fault.rs b/runtime/src/fault.rs index 46a373b..2fc2b26 100644 --- a/runtime/src/fault.rs +++ b/runtime/src/fault.rs @@ -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)] diff --git a/runtime/src/frame.rs b/runtime/src/frame.rs index a2033b8..dea8922 100644 --- a/runtime/src/frame.rs +++ b/runtime/src/frame.rs @@ -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 { match rd.d() { SrcDisp::Immediate(v) => Ok(v), diff --git a/runtime/src/program.rs b/runtime/src/program.rs index bf8d1d7..1f90435 100644 --- a/runtime/src/program.rs +++ b/runtime/src/program.rs @@ -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, + routines: HashMap, + far_labels: HashMap, + barriers: Vec, } impl Program { - pub fn new(ops : Vec) -> Self { - Self { + pub fn new(ops: Vec) -> 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 { + 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 { + self.far_labels.get(name).copied() + .ok_or_else(|| Fault::NoSuchFarLabel { label: name.clone() }) + } }