diff --git a/asm/src/data/literal.rs b/asm/src/data/literal.rs index 00d95bf..e59e33a 100644 --- a/asm/src/data/literal.rs +++ b/asm/src/data/literal.rs @@ -1,5 +1,4 @@ use std::fmt::{self, Display, Formatter}; -use std::convert::TryFrom; use std::sync::atomic::AtomicU32; use std::borrow::Cow; diff --git a/asm/src/data/mod.rs b/asm/src/data/mod.rs index ace7e70..15b2d6c 100644 --- a/asm/src/data/mod.rs +++ b/asm/src/data/mod.rs @@ -11,7 +11,7 @@ use literal::Addr; use std::convert::TryFrom; -use crate::data::literal::{Value, is_negative, as_signed}; +use crate::data::literal::{Value, as_signed}; use std::fmt::{Debug, Formatter, Display}; use std::fmt; @@ -64,6 +64,7 @@ impl From for DataDisp { DstDisp::ImmediatePtr(x) => DataDisp::ImmediatePtr(x), DstDisp::Register(x) => DataDisp::Register(x), DstDisp::RegisterPtr(x) => DataDisp::RegisterPtr(x), + DstDisp::Discard => DataDisp::Immediate(0), } } } @@ -103,6 +104,8 @@ pub enum DstDisp { Register(Register), /// Pointer into memory, stored in a numbered register RegisterPtr(Register), + /// Discard the written value + Discard, } impl From for SrcDisp { @@ -111,6 +114,7 @@ impl From for SrcDisp { DstDisp::ImmediatePtr(x) => SrcDisp::ImmediatePtr(x), DstDisp::Register(x) => SrcDisp::Register(x), DstDisp::RegisterPtr(x) => SrcDisp::RegisterPtr(x), + DstDisp::Discard => SrcDisp::Immediate(0), } } } @@ -142,6 +146,10 @@ impl Rd { pub fn mask(self) -> Mask { self.1 } + + pub fn immediate(val : Value) -> Rd { + Rd(SrcDisp::Immediate(val), Mask::default()) + } } /// Data destination argument (read-write) @@ -161,15 +169,19 @@ impl Wr { pub fn as_rd(&self) -> Rd { Rd(self.0.into(), self.1) } + + pub fn discard() -> Wr { + Wr(DstDisp::Discard, Mask::default()) + } } impl Debug for Rd { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "Rd(")?; let disp : DataDisp = self.0.into(); - write!(f, "{}", disp); + write!(f, "{}", disp)?; if !self.mask().is_default() { - write!(f, ",{:?}", self.mask()); + write!(f, ",{:?}", self.mask())?; } write!(f, ")") } @@ -179,9 +191,9 @@ impl Debug for Wr { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "Wr(")?; let disp : DataDisp = self.0.into(); - write!(f, "{}", disp); + write!(f, "{}", disp)?; if !self.mask().is_default() { - write!(f, ",{:?}", self.mask()); + write!(f, ",{:?}", self.mask())?; } write!(f, ")") } diff --git a/asm/src/instr/cond.rs b/asm/src/instr/cond.rs index 46b06aa..161ce0e 100644 --- a/asm/src/instr/cond.rs +++ b/asm/src/instr/cond.rs @@ -17,6 +17,8 @@ pub enum Cond { NonNegative, Overflow, NotOverflow, + Invalid, + Valid, Carry, NotCarry, } @@ -37,9 +39,11 @@ impl Display for Cond { Cond::NonPositive => "npos", Cond::NonNegative => "nneg", Cond::Overflow => "ov", + Cond::NotOverflow => "nov", Cond::Carry => "c", Cond::NotCarry => "nc", - Cond::NotOverflow => "nov" + Cond::Invalid => "inval", + Cond::Valid => "ok", }) } } @@ -68,6 +72,9 @@ impl Not for Cond { Cond::Greater => Cond::LowerOrEqual, Cond::LowerOrEqual => Cond::Greater, Cond::GreaterOrEqual => Cond::Lower, + + Cond::Invalid => Cond::Valid, + Cond::Valid => Cond::Invalid, } } } diff --git a/asm/src/instr/op.rs b/asm/src/instr/op.rs index 7ca52a3..bb6a0bc 100644 --- a/asm/src/instr/op.rs +++ b/asm/src/instr/op.rs @@ -46,36 +46,29 @@ pub enum Op { /// Generate a run-time fault with a debugger message Fault(Option), - /* Arithmetic */ + Move { dst: Wr, src: Rd }, + Test { a: Rd }, + Compare { a: Rd, b: Rd }, + StoreStatus { dst: Wr }, + LoadStatus { src: Rd }, - /// Copy a value - Mov(Wr, Rd), - /// 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), + Add { dst: Wr, a: Rd, b: Rd }, + Sub { dst: Wr, a: Rd, b: Rd }, + Mul { dst: Wr, a: Rd, b: Rd }, + Div { dst: Wr, rem: Wr, a: Rd, div: Rd }, + // "Mod" is functionally equivalent to "Div" with the result discarded, + // but status flags are updated by the remainder + Mod { dst: Wr, a: Rd, div: Rd }, - // Arithmetic - Inc(Wr), - Dec(Wr), - Add(Wr, Rd), - Sub(Wr, Rd), - Mul(Wr, Rd), - Div(Wr, Rd), - Mod(Wr, Rd), - DivRem(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 + And { dst: Wr, a: Rd, b: Rd }, + Or { dst: Wr, a: Rd, b: Rd }, + Xor { dst: Wr, a: Rd, b: Rd }, + Cpl { dst: Wr, a: Rd }, + Rol { dst: Wr, a: Rd, n: Rd }, // Rotate (with wrap-around) + Ror { dst: Wr, a: Rd, n: Rd }, + Lsl { dst: Wr, a: Rd, n: Rd }, // Shift + Lsr { dst: Wr, a: Rd, n: Rd }, + Asr { dst: Wr, a: Rd, n: Rd }, } /// Make "into" work diff --git a/asm/src/parse/parse_data.rs b/asm/src/parse/parse_data.rs index 88ab4a9..6c443cc 100644 --- a/asm/src/parse/parse_data.rs +++ b/asm/src/parse/parse_data.rs @@ -1,7 +1,7 @@ use sexp::{Sexp, Atom}; use crate::data::{DataDisp, Rd, Wr, DstDisp, SrcDisp, reg}; use crate::error::Error; -use crate::data::literal::{Value, Addr, Label}; +use crate::data::literal::{Addr, Label}; use std::convert::TryFrom; use crate::parse::sexp_expect::expect_string_atom; diff --git a/asm/src/parse/parse_instr.rs b/asm/src/parse/parse_instr.rs index fa3b5c3..c51e83a 100644 --- a/asm/src/parse/parse_instr.rs +++ b/asm/src/parse/parse_instr.rs @@ -24,7 +24,7 @@ pub fn parse_instructions(instrs: Vec) -> Result, Error> { false }; - let arg_tokens = toki.clone().take_while(|e| e.is_atom()); + let arg_tokens = toki.clone().take_while(|e| e.is_atom()).collect::>(); let branch_tokens = toki .skip_while(|e| e.is_atom()) .take_while(|e| e.is_list()); @@ -42,7 +42,7 @@ pub fn parse_instructions(instrs: Vec) -> Result, Error> { }; parsed.push(Instr { - op: parse_op(name.as_str(), far, arg_tokens)?, + op: parse_op(name.as_str(), far, arg_tokens.into_iter())?, branches }); } diff --git a/asm/src/parse/parse_op.rs b/asm/src/parse/parse_op.rs index dba3154..ceb3483 100644 --- a/asm/src/parse/parse_op.rs +++ b/asm/src/parse/parse_op.rs @@ -5,8 +5,9 @@ use crate::data::literal::{RoutineName, Label}; use crate::parse::sexp_expect::expect_string_atom; use crate::parse::parse_data::{parse_rd, parse_wr, parse_label}; use crate::parse::parse_cond::parse_cond; +use crate::data::{Rd, Wr}; -pub fn parse_op(keyword: &str, far : bool, mut arg_tokens: impl Iterator) -> Result { +pub fn parse_op(keyword: &str, far: bool, mut arg_tokens: impl ExactSizeIterator + Clone) -> Result { Ok(match keyword { "j" => { let dest = parse_label(arg_tokens.next())?; @@ -71,143 +72,433 @@ pub fn parse_op(keyword: &str, far : bool, mut arg_tokens: impl Iterator { - HLOp::L(Op::Mov( - parse_wr(arg_tokens.next())?, - parse_rd(arg_tokens.next())? - )) + HLOp::L(Op::Move { + dst: parse_wr(arg_tokens.next())?, + src: parse_rd(arg_tokens.next())?, + }) } "cmp" => { - HLOp::L(Op::Cmp( - parse_rd(arg_tokens.next())?, - parse_rd(arg_tokens.next())? - )) + HLOp::L(Op::Compare { + a: parse_rd(arg_tokens.next())?, + b: parse_rd(arg_tokens.next())?, + }) } "tst" => { let arg = parse_rd(arg_tokens.next())?; - HLOp::L(Op::Cmp(arg, arg)) + HLOp::L(Op::Test { a: arg }) } "inc" => { - HLOp::L(Op::Inc( - parse_wr(arg_tokens.next())? - )) + let dst = parse_wr(arg_tokens.next())?; + HLOp::L(Op::Add { + dst, + a: dst.as_rd(), + b: Rd::immediate(1), + }) } "dec" => { - HLOp::L(Op::Dec( - parse_wr(arg_tokens.next())? - )) + let dst = parse_wr(arg_tokens.next())?; + HLOp::L(Op::Sub { + dst, + a: dst.as_rd(), + b: Rd::immediate(1), + }) } "add" => { - HLOp::L(Op::Add( - parse_wr(arg_tokens.next())?, - parse_rd(arg_tokens.next())? - )) + HLOp::L(match arg_tokens.len() { + 3 => { + Op::Add { + dst: parse_wr(arg_tokens.next())?, + a: parse_rd(arg_tokens.next())?, + b: parse_rd(arg_tokens.next())?, + } + } + 2 => { + let dst = parse_wr(arg_tokens.next())?; + Op::Add { + dst, + a: dst.as_rd(), + b: parse_rd(arg_tokens.next())?, + } + } + _ => { + return Err(Error::Parse("Add requires 2 or 3 arguments".into())); + } + }) } "sub" => { - HLOp::L(Op::Sub( - parse_wr(arg_tokens.next())?, - parse_rd(arg_tokens.next())? - )) + HLOp::L(match arg_tokens.len() { + 3 => { + Op::Sub { + dst: parse_wr(arg_tokens.next())?, + a: parse_rd(arg_tokens.next())?, + b: parse_rd(arg_tokens.next())?, + } + } + 2 => { + let dst = parse_wr(arg_tokens.next())?; + Op::Sub { + dst, + a: dst.as_rd(), + b: parse_rd(arg_tokens.next())?, + } + } + _ => { + return Err(Error::Parse("Sub requires 2 or 3 arguments".into())); + } + }) } "mul" => { - HLOp::L(Op::Mul( - parse_wr(arg_tokens.next())?, - parse_rd(arg_tokens.next())? - )) + HLOp::L(match arg_tokens.len() { + 3 => { + Op::Mul { + dst: parse_wr(arg_tokens.next())?, + a: parse_rd(arg_tokens.next())?, + b: parse_rd(arg_tokens.next())?, + } + } + 2 => { + let dst = parse_wr(arg_tokens.next())?; + Op::Mul { + dst, + a: dst.as_rd(), + b: parse_rd(arg_tokens.next())?, + } + } + _ => { + return Err(Error::Parse("Mul requires 2 or 3 arguments".into())); + } + }) } - "div" => { - HLOp::L(Op::Div( - parse_wr(arg_tokens.next())?, - parse_rd(arg_tokens.next())? - )) + "divr" => { + HLOp::L(match arg_tokens.len() { + 3 => { + let dst = parse_wr(arg_tokens.next())?; + let rem = parse_wr(arg_tokens.next())?; + let div = parse_rd(arg_tokens.next())?; + Op::Div { + dst, + rem, + a: dst.as_rd(), + div, + } + } + 4 => { + Op::Div { + dst: parse_wr(arg_tokens.next())?, + rem : parse_wr(arg_tokens.next())?, + a: parse_rd(arg_tokens.next())?, + div: parse_rd(arg_tokens.next())?, + } + } + _ => { + return Err(Error::Parse("DivR requires 3 or 4 arguments".into())); + } + }) } - "mod" => { - HLOp::L(Op::Mod( - parse_wr(arg_tokens.next())?, - parse_rd(arg_tokens.next())? - )) + "div" => { + HLOp::L(match arg_tokens.len() { + 3 => { + Op::Div { + dst: parse_wr(arg_tokens.next())?, + rem: Wr::discard(), + a: parse_rd(arg_tokens.next())?, + div: parse_rd(arg_tokens.next())?, + } + } + 2 => { + let dst = parse_wr(arg_tokens.next())?; + let div = parse_rd(arg_tokens.next())?; + Op::Div { + dst, + rem: Wr::discard(), + a: dst.as_rd(), + div, + } + } + _ => { + return Err(Error::Parse("Div requires 2 or 3 arguments".into())); + } + }) } - "divr" => { - HLOp::L(Op::DivRem( - parse_wr(arg_tokens.next())?, - parse_wr(arg_tokens.next())?, - parse_rd(arg_tokens.next())? - )) + "mod" => { + HLOp::L(match arg_tokens.len() { + 3 => { + Op::Mod { + dst: parse_wr(arg_tokens.next())?, + a: parse_rd(arg_tokens.next())?, + div: parse_rd(arg_tokens.next())?, + } + } + 2 => { + let dst = parse_wr(arg_tokens.next())?; + let div = parse_rd(arg_tokens.next())?; + Op::Mod { + dst, + a: dst.as_rd(), + div, + } + } + _ => { + return Err(Error::Parse("Mod requires 2 or 3 arguments".into())); + } + }) } "and" => { - HLOp::L(Op::And( - parse_wr(arg_tokens.next())?, - parse_rd(arg_tokens.next())? - )) + HLOp::L(match arg_tokens.len() { + 3 => { + Op::And { + dst: parse_wr(arg_tokens.next())?, + a: parse_rd(arg_tokens.next())?, + b: parse_rd(arg_tokens.next())?, + } + } + 2 => { + let dst = parse_wr(arg_tokens.next())?; + Op::And { + dst, + a: dst.as_rd(), + b: parse_rd(arg_tokens.next())?, + } + } + _ => { + return Err(Error::Parse("And requires 2 or 3 arguments".into())); + } + }) } "or" => { - HLOp::L(Op::Or( - parse_wr(arg_tokens.next())?, - parse_rd(arg_tokens.next())? - )) + HLOp::L(match arg_tokens.len() { + 3 => { + Op::Or { + dst: parse_wr(arg_tokens.next())?, + a: parse_rd(arg_tokens.next())?, + b: parse_rd(arg_tokens.next())?, + } + } + 2 => { + let dst = parse_wr(arg_tokens.next())?; + Op::Or { + dst, + a: dst.as_rd(), + b: parse_rd(arg_tokens.next())?, + } + } + _ => { + return Err(Error::Parse("Or requires 2 or 3 arguments".into())); + } + }) } "xor" => { - HLOp::L(Op::Xor( - parse_wr(arg_tokens.next())?, - parse_rd(arg_tokens.next())? - )) + HLOp::L(match arg_tokens.len() { + 3 => { + Op::Xor { + dst: parse_wr(arg_tokens.next())?, + a: parse_rd(arg_tokens.next())?, + b: parse_rd(arg_tokens.next())?, + } + } + 2 => { + let dst = parse_wr(arg_tokens.next())?; + Op::Xor { + dst, + a: dst.as_rd(), + b: parse_rd(arg_tokens.next())?, + } + } + _ => { + return Err(Error::Parse("Xor requires 2 or 3 arguments".into())); + } + }) } "cpl" => { - HLOp::L(Op::Cpl( - parse_wr(arg_tokens.next())? - )) + HLOp::L(match arg_tokens.len() { + 2 => { + Op::Cpl { + dst: parse_wr(arg_tokens.next())?, + a: parse_rd(arg_tokens.next())?, + } + } + 1 => { + let dst = parse_wr(arg_tokens.next())?; + Op::Cpl { + dst, + a: dst.as_rd(), + } + } + _ => { + return Err(Error::Parse("Cpl requires 1 or 2 arguments".into())); + } + }) } "rol" => { - HLOp::L(Op::Rol( - parse_wr(arg_tokens.next())?, - parse_rd(arg_tokens.next())? - )) + HLOp::L(match arg_tokens.len() { + 3 => { + Op::Rol { + dst: parse_wr(arg_tokens.next())?, + a: parse_rd(arg_tokens.next())?, + n: parse_rd(arg_tokens.next())?, + } + } + 2 => { + let dst = parse_wr(arg_tokens.next())?; + Op::Rol { + dst, + a: dst.as_rd(), + n: parse_rd(arg_tokens.next())?, + } + } + 1 => { + let dst = parse_wr(arg_tokens.next())?; + Op::Rol { + dst, + a: dst.as_rd(), + n: Rd::immediate(1), + } + } + _ => { + return Err(Error::Parse("Rol requires 1, 2 or 3 arguments".into())); + } + }) } "ror" => { - HLOp::L(Op::Ror( - parse_wr(arg_tokens.next())?, - parse_rd(arg_tokens.next())? - )) + HLOp::L(match arg_tokens.len() { + 3 => { + Op::Ror { + dst: parse_wr(arg_tokens.next())?, + a: parse_rd(arg_tokens.next())?, + n: parse_rd(arg_tokens.next())?, + } + } + 2 => { + let dst = parse_wr(arg_tokens.next())?; + Op::Ror { + dst, + a: dst.as_rd(), + n: parse_rd(arg_tokens.next())?, + } + } + 1 => { + let dst = parse_wr(arg_tokens.next())?; + Op::Ror { + dst, + a: dst.as_rd(), + n: Rd::immediate(1), + } + } + _ => { + return Err(Error::Parse("Ror requires 1, 2 or 3 arguments".into())); + } + }) } "lsl" | "asl" => { - HLOp::L(Op::Lsl( - parse_wr(arg_tokens.next())?, - parse_rd(arg_tokens.next())? - )) + HLOp::L(match arg_tokens.len() { + 3 => { + Op::Lsl { + dst: parse_wr(arg_tokens.next())?, + a: parse_rd(arg_tokens.next())?, + n: parse_rd(arg_tokens.next())?, + } + } + 2 => { + let dst = parse_wr(arg_tokens.next())?; + Op::Lsl { + dst, + a: dst.as_rd(), + n: parse_rd(arg_tokens.next())?, + } + } + 1 => { + let dst = parse_wr(arg_tokens.next())?; + Op::Lsl { + dst, + a: dst.as_rd(), + n: Rd::immediate(1), + } + } + _ => { + return Err(Error::Parse("Lsl requires 1, 2 or 3 arguments".into())); + } + }) } "lsr" => { - HLOp::L(Op::Lsr( - parse_wr(arg_tokens.next())?, - parse_rd(arg_tokens.next())? - )) + HLOp::L(match arg_tokens.len() { + 3 => { + Op::Lsr { + dst: parse_wr(arg_tokens.next())?, + a: parse_rd(arg_tokens.next())?, + n: parse_rd(arg_tokens.next())?, + } + } + 2 => { + let dst = parse_wr(arg_tokens.next())?; + Op::Lsr { + dst, + a: dst.as_rd(), + n: parse_rd(arg_tokens.next())?, + } + } + 1 => { + let dst = parse_wr(arg_tokens.next())?; + Op::Lsr { + dst, + a: dst.as_rd(), + n: Rd::immediate(1), + } + } + _ => { + return Err(Error::Parse("Lsr requires 1, 2 or 3 arguments".into())); + } + }) } "asr" => { - HLOp::L(Op::Asr( - parse_wr(arg_tokens.next())?, - parse_rd(arg_tokens.next())? - )) + HLOp::L(match arg_tokens.len() { + 3 => { + Op::Asr { + dst: parse_wr(arg_tokens.next())?, + a: parse_rd(arg_tokens.next())?, + n: parse_rd(arg_tokens.next())?, + } + } + 2 => { + let dst = parse_wr(arg_tokens.next())?; + Op::Asr { + dst, + a: dst.as_rd(), + n: parse_rd(arg_tokens.next())?, + } + } + 1 => { + let dst = parse_wr(arg_tokens.next())?; + Op::Asr { + dst, + a: dst.as_rd(), + n: Rd::immediate(1), + } + } + _ => { + return Err(Error::Parse("Asr requires 1, 2 or 3 arguments".into())); + } + }) } - // TODO more instructions - other => { if let Some(label) = other.strip_prefix(':') { let label = Label::Named(label.to_string()); diff --git a/runtime/src/exec/mod.rs b/runtime/src/exec/mod.rs index e5684d3..5335d01 100644 --- a/runtime/src/exec/mod.rs +++ b/runtime/src/exec/mod.rs @@ -1,9 +1,9 @@ -use crate::run_thread::{ThreadToken, RunThread}; -use asm::instr::{Op, Cond}; +use crate::run_thread::{RunThread}; +use asm::instr::{Op}; use crate::fault::Fault; use crate::frame::StackFrame; -use asm::data::literal::{Value, is_positive, is_negative, Addr}; -use std::ops::{Rem, BitXor, Shl}; +use asm::data::literal::{Addr}; +use std::ops::{Rem}; use num_traits::PrimInt; pub type CyclesSpent = usize; @@ -38,12 +38,12 @@ impl RunThread { Op::Barrier(msg) => { return Err(Fault::Barrier { msg: msg.clone().unwrap_or_else(|| "No msg".into()) - }) + }); } Op::Fault(msg) => { return Err(Fault::FaultInstr { msg: msg.clone().unwrap_or_else(|| "No msg".into()) - }) + }); } Op::FarJump(name) => { debug!("Far jump to {}", name); @@ -56,7 +56,7 @@ impl RunThread { return Err(e); } } - }, + } Op::Call(name, args) => { debug!("Call routine {}", name); match self.program.find_routine(name) { @@ -77,7 +77,7 @@ impl RunThread { return Err(e); } } - }, + } Op::Ret(retvals) => { match self.call_stack.pop() { Some(previous) => { @@ -93,7 +93,7 @@ impl RunThread { return Err(Fault::CallStackUnderflow); } } - }, + } Op::Skip(val) => { let steps = frame.read(*val)?; advance = i64::from_ne_bytes(steps.to_ne_bytes()); @@ -106,239 +106,193 @@ impl RunThread { self.program.validate_jump(frame.pc, Addr((frame.pc.0 as i64 + advance) as u64))?; } } - Op::Mov(dst, src) => { + Op::Move { 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.status.update(val); frame.write(*dst, val)?; } - Op::Cmp(a, b) => { - frame.status.clear(); - let a = frame.read(*a)?; - let b = frame.read(*b)?; - frame.status.equal = a == b; - frame.status.zero = a == 0 && b == 0; - frame.status.lower = a < b; - frame.status.greater = a > b; - frame.status.positive = is_positive(a) && is_positive(b); - frame.status.negative = is_negative(a) && is_negative(b); - } - Op::Inc(reg) => { + Op::Test { a } => { frame.status.clear(); - let mut val = frame.read(reg.as_rd())?; - val = val.wrapping_add(1); - frame.status.overflow = (val == 0); - frame.status.zero = (val == 0); - frame.status.positive = is_positive(val); - frame.status.negative = is_negative(val); - frame.write(*reg, val)?; + let res = frame.read(*a)?; + frame.status.update(res); } - Op::Dec(reg) => { + Op::Compare { a, b } => { frame.status.clear(); - let mut val = frame.read(reg.as_rd())?; - frame.status.overflow = (val == 0); // will overflow - val = val.wrapping_sub(1); - frame.status.zero = (val == 0); - frame.status.positive = is_positive(val); - frame.status.negative = is_negative(val); - frame.write(*reg, val)?; + let x = frame.read(*a)?; + let y = frame.read(*b)?; + frame.status.equal = x == y; + frame.status.lower = x < y; + frame.status.greater = x > y; + // Test flags are set when both arguments have the property + if x == y { + frame.status.update(x); + } } - Op::Add(dst, src) => { + Op::Add { dst, a, b } => { frame.status.clear(); - let mut a = frame.read(dst.as_rd())?; - let mut b = frame.read(*src)?; - let (val, ov) = if let Some(v) = a.checked_add(b) { + let x = frame.read(*a)?; + let y = frame.read(*b)?; + let (res, ov) = if let Some(v) = x.checked_add(y) { (v, false) } else { - (a.wrapping_add(b), true) + (x.wrapping_add(y), true) }; - frame.status.zero = (val == 0); - frame.status.positive = is_positive(val); - frame.status.negative = is_negative(val); + frame.status.update(res); frame.status.overflow = ov; - frame.write(*dst, val)?; + frame.write(*dst, res)?; } - Op::Sub(dst, src) => { + Op::Sub { dst, a, b } => { frame.status.clear(); - let mut a = frame.read(dst.as_rd())?; - let mut b = frame.read(*src)?; - let (val, ov) = if let Some(v) = a.checked_sub(b) { + let x = frame.read(*a)?; + let y = frame.read(*b)?; + let (res, ov) = if let Some(v) = x.checked_sub(y) { (v, false) } else { - (a.wrapping_sub(b), true) + (x.wrapping_sub(y), true) }; - frame.status.zero = (val == 0); - frame.status.positive = is_positive(val); - frame.status.negative = is_negative(val); + frame.status.update(res); frame.status.overflow = ov; - frame.write(*dst, val)?; + frame.write(*dst, res)?; } - Op::Mul(dst, src) => { + Op::Mul { dst, a, b } => { frame.status.clear(); - let mut a = frame.read(dst.as_rd())?; - let mut b = frame.read(*src)?; - let (val, ov) = if let Some(v) = a.checked_mul(b) { + let x = frame.read(*a)?; + let y = frame.read(*b)?; + let (res, ov) = if let Some(v) = x.checked_mul(y) { (v, false) } else { - (a.wrapping_mul(b), true) + (x.wrapping_mul(y), true) }; - frame.status.zero = (val == 0); - frame.status.positive = is_positive(val); - frame.status.negative = is_negative(val); + frame.status.update(res); frame.status.overflow = ov; - frame.write(*dst, val)?; + frame.write(*dst, res)?; } - Op::Div(dst, src) => { + Op::Div { dst, rem, a, div } => { frame.status.clear(); - let mut a = frame.read(dst.as_rd())?; - let mut b = frame.read(*src)?; - if b == 0 { - frame.status.overflow = true; - // TODO ? + let x = frame.read(*a)?; + let d = frame.read(*div)?; + if d == 0 { + frame.status.invalid = true; } else { - let (val, ov) = if let Some(v) = a.checked_div(b) { - (v, false) + let (res, remainder, ov) = if let Some(v) = x.checked_div(d) { + (v, x.rem(d), false) } else { - (a.wrapping_div(b), true) + (x.wrapping_div(d), x.wrapping_rem(d), true) }; - frame.status.zero = (val == 0); - frame.status.positive = is_positive(val); - frame.status.negative = is_negative(val); + frame.status.update(res); frame.status.overflow = ov; - frame.write(*dst, val)?; + frame.write(*dst, res)?; + frame.write(*rem, remainder)?; } } - Op::Mod(dst, src) => { + Op::Mod { dst, a, div } => { frame.status.clear(); - let mut a = frame.read(dst.as_rd())?; - let mut b = frame.read(*src)?; - if b == 0 { - frame.status.overflow = true; - // TODO ? + let x = frame.read(*a)?; + let d = frame.read(*div)?; + if d == 0 { + frame.status.invalid = true; } else { - let (val, ov) = if let Some(v) = a.checked_rem(b) { + let (remainder, ov) = if let Some(v) = x.checked_rem(d) { (v, false) } else { - (a.wrapping_rem(b), true) + (x.wrapping_rem(d), true) }; - frame.status.zero = (val == 0); - frame.status.positive = is_positive(val); - frame.status.negative = is_negative(val); + frame.status.update(remainder); frame.status.overflow = ov; - frame.write(*dst, val)?; + frame.write(*dst, remainder)?; } } - Op::DivRem(dst, remptr, src) => { + Op::And { dst, a, b } => { frame.status.clear(); - let mut a = frame.read(dst.as_rd())?; - let mut b = frame.read(*src)?; - if b == 0 { - frame.status.overflow = true; - // TODO ? - } else { - let (val, rem, ov) = if let Some(v) = a.checked_div(b) { - (v, a.rem(b), false) - } else { - (a.wrapping_div(b), a.wrapping_rem(b), true) - }; - frame.status.zero = (val == 0); - frame.status.positive = is_positive(val); - frame.status.negative = is_negative(val); - frame.status.overflow = ov; - frame.write(*dst, val)?; - frame.write(*remptr, rem)?; - } + let x = frame.read(*a)?; + let y = frame.read(*b)?; + let res = x & y; + frame.status.update(res); + frame.write(*dst, res)?; } - Op::And(dst, src) => { + Op::Or { dst, a, b } => { frame.status.clear(); - let mut val = frame.read(dst.as_rd())?; - let mut b = frame.read(*src)?; - val &= b; - frame.status.zero = (val == 0); - frame.status.positive = is_positive(val); - frame.status.negative = is_negative(val); - frame.write(*dst, val)?; + let x = frame.read(*a)?; + let y = frame.read(*b)?; + let res = x | y; + frame.status.update(res); + frame.write(*dst, res)?; } - Op::Or(dst, src) => { + Op::Xor { dst, a, b } => { frame.status.clear(); - let mut val = frame.read(dst.as_rd())?; - let mut b = frame.read(*src)?; - val |= b; - frame.status.zero = (val == 0); - frame.status.positive = is_positive(val); - frame.status.negative = is_negative(val); - frame.write(*dst, val)?; + let x = frame.read(*a)?; + let y = frame.read(*b)?; + let res = x ^ y; + frame.status.update(res); + frame.write(*dst, res)?; } - Op::Xor(dst, src) => { + Op::Cpl { dst, a } => { frame.status.clear(); - let mut val = frame.read(dst.as_rd())?; - let mut b = frame.read(*src)?; - val ^= b; - frame.status.zero = (val == 0); - frame.status.positive = is_positive(val); - frame.status.negative = is_negative(val); - frame.write(*dst, val)?; + let x = frame.read(*a)?; + let res = !x; + frame.status.update(res); + frame.write(*dst, res)?; } - Op::Cpl(dst) => { + Op::Rol { dst, a, n } => { frame.status.clear(); - let mut val = frame.read(dst.as_rd())?; - val = !val; - frame.status.zero = (val == 0); - frame.status.positive = is_positive(val); - frame.status.negative = is_negative(val); - frame.write(*dst, val)?; + let x = frame.read(*a)?; + let y = frame.read(*n)?; + if y > u32::MAX as u64 { + frame.status.invalid = true; + } else { + let res = x.rotate_left(y as u32); + frame.status.update(res); + frame.write(*dst, res)?; + } } - Op::Rol(dst, num) => { + Op::Ror { dst, a, n } => { frame.status.clear(); - let mut val = frame.read(dst.as_rd())?; - let mut b = frame.read(*num)?; - val = val.rotate_left(b as u32); // FIXME check overflow - frame.status.zero = (val == 0); - frame.status.positive = is_positive(val); - frame.status.negative = is_negative(val); - frame.write(*dst, val)?; + let x = frame.read(*a)?; + let y = frame.read(*n)?; + if y > u32::MAX as u64 { + frame.status.invalid = true; + } else { + let res = x.rotate_right(y as u32); + frame.status.update(res); + frame.write(*dst, res)?; + } } - Op::Ror(dst, num) => { + Op::Lsl { dst, a, n } => { frame.status.clear(); - let mut val = frame.read(dst.as_rd())?; - let mut b = frame.read(*num)?; - val = val.rotate_right(b as u32); // FIXME check overflow - frame.status.zero = (val == 0); - frame.status.positive = is_positive(val); - frame.status.negative = is_negative(val); - frame.write(*dst, val)?; + let x = frame.read(*a)?; + let y = frame.read(*n)?; + let res = x << y; + frame.status.update(res); + frame.write(*dst, res)?; } - Op::Lsl(dst, num) => { + Op::Lsr { dst, a, n } => { frame.status.clear(); - let mut val = frame.read(dst.as_rd())?; - let mut b = frame.read(*num)?; - val = val << b; - frame.status.zero = (val == 0); - frame.status.positive = is_positive(val); - frame.status.negative = is_negative(val); - frame.write(*dst, val)?; + let x = frame.read(*a)?; + let y = frame.read(*n)?; + let res = x >> y; + frame.status.update(res); + frame.write(*dst, res)?; } - Op::Lsr(dst, num) => { + Op::Asr { dst, a, n } => { frame.status.clear(); - let mut val = frame.read(dst.as_rd())?; - let mut b = frame.read(*num)?; - val = val >> b; - frame.status.zero = (val == 0); - frame.status.positive = is_positive(val); - frame.status.negative = is_negative(val); - frame.write(*dst, val)?; + let x = frame.read(*a)?; + let y = frame.read(*n)?; + if y > u32::MAX as u64 { + frame.status.invalid = true; + } else { + let res = x.signed_shr(y as u32); + frame.status.update(res); + frame.write(*dst, res)?; + } } - Op::Asr(dst, num) => { - frame.status.clear(); - let mut val = frame.read(dst.as_rd())?; - let mut b = frame.read(*num)?; - val = val.signed_shr(b as u32); // FIXME check overflow - frame.status.zero = (val == 0); - frame.status.positive = is_positive(val); - frame.status.negative = is_negative(val); - frame.write(*dst, val)?; + Op::StoreStatus { dst } => { + let packed = frame.status.store(); + frame.write(*dst, packed)?; + } + Op::LoadStatus { src } => { + let x = frame.read(*src)?; + frame.status.load(x); } } diff --git a/runtime/src/fault.rs b/runtime/src/fault.rs index 2fc2b26..14b9c6b 100644 --- a/runtime/src/fault.rs +++ b/runtime/src/fault.rs @@ -1,7 +1,7 @@ use thiserror::Error; -use super::span::MemorySpan; -use crate::run_thread::ThreadToken; -use crate::mlock::ClaimId; +// use super::span::MemorySpan; +// use crate::run_thread::ThreadToken; +// use crate::mlock::ClaimId; use asm::data::literal::{DebugMsg, RoutineName, Label}; use asm::data::Register; @@ -23,17 +23,17 @@ pub enum Fault { msg: DebugMsg, }, - #[error("Memory region {area:?} is locked by thread {owner:?}")] - MemoryLocked { - area: MemorySpan, - owner: ThreadToken - }, - - #[error("Memory claim {claim:?} owned by thread {owner:?} does not exist")] - ClaimNotExist { - claim: ClaimId, - owner: ThreadToken - }, + // #[error("Memory region {area:?} is locked by thread {owner:?}")] + // MemoryLocked { + // area: MemorySpan, + // owner: ThreadToken + // }, + // + // #[error("Memory claim {claim:?} owned by thread {owner:?} does not exist")] + // ClaimNotExist { + // claim: ClaimId, + // owner: ThreadToken + // }, #[error("Register does not exist: {reg:?}")] RegisterNotExist { diff --git a/runtime/src/frame.rs b/runtime/src/frame.rs index f4fae0c..8ba6538 100644 --- a/runtime/src/frame.rs +++ b/runtime/src/frame.rs @@ -1,91 +1,14 @@ use asm::data::literal::{Addr, Value}; use asm::data::{Rd, SrcDisp, Register, Wr, DstDisp}; use crate::fault::Fault; -use asm::instr::Cond; -use std::fmt::{Display, Formatter, Write}; -use std::fmt; -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 Display for StatusFlags { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.write_str("[")?; - if self.equal { - f.write_str(" E")?; - } - if self.zero { - f.write_str(" Z")?; - } - if self.lower { - f.write_str(" L")?; - } - if self.greater { - f.write_str(" G")?; - } - if self.positive { - f.write_str(" P")?; - } - if self.negative { - f.write_str(" N")?; - } - if self.overflow { - f.write_str(" V")?; - } - if self.carry { - f.write_str(" C")?; - } - f.write_str(" ]")?; - Ok(()) - } -} -impl StatusFlags { - pub fn clear(&mut self) { - *self = Self::default(); - } +mod status; +use status::StatusFlags; - 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 - } - } -} +pub const REG_COUNT: usize = 8; #[derive(Default, Clone, Debug)] pub struct StackFrame { @@ -118,7 +41,7 @@ impl StackFrame { } } - pub fn read(&mut self, rd: Rd) -> Result { + pub fn read(&mut self, rd: Rd) -> Result { match rd.d() { SrcDisp::Immediate(v) => Ok(v), SrcDisp::ImmediatePtr(_) => { @@ -161,6 +84,10 @@ impl StackFrame { 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 diff --git a/runtime/src/frame/status.rs b/runtime/src/frame/status.rs new file mode 100644 index 0000000..d3d4f9e --- /dev/null +++ b/runtime/src/frame/status.rs @@ -0,0 +1,123 @@ +use std::fmt::{Display, Formatter}; +use std::fmt; +use asm::data::literal::{Value, is_positive, is_negative}; +use asm::instr::Cond; + +#[derive(Default, Clone, Debug)] +pub struct StatusFlags { + /// Arguments are equal + pub equal: bool, + /// A < B + pub lower: bool, + /// A > B + pub greater: bool, + /// Register is zero + pub zero: bool, + /// Register is positive + pub positive: bool, + /// Register is negative + pub negative: bool, + /// Overflow (multiplication etc.) + pub overflow: bool, + /// Invalid flag + pub invalid: bool, + /// Arithmetic carry + pub carry: bool, +} + +impl StatusFlags { + pub fn clear(&mut self) { + *self = Self::default(); + } + + pub fn store(&self) -> Value { + let mut val = 0u64; + if self.equal { val |= 0x01; } + if self.lower { val |= 0x02; } + if self.greater { val |= 0x04; } + if self.zero { val |= 0x08; } + if self.positive { val |= 0x10; } + if self.negative { val |= 0x20; } + if self.overflow { val |= 0x40; } + if self.invalid { val |= 0x80; } + if self.carry { val |= 0x100; } + val + } + + pub fn load(&mut self, val : Value) { + if val & 0x01 != 0 { self.equal = true; } + if val & 0x02 != 0 { self.lower = true; } + if val & 0x04 != 0 { self.greater = true; } + if val & 0x08 != 0 { self.zero = true; } + if val & 0x10 != 0 { self.positive = true; } + if val & 0x20 != 0 { self.negative = true; } + if val & 0x40 != 0 { self.overflow = true; } + if val & 0x80 != 0 { self.invalid = true; } + if val & 0x100 != 0 { self.carry = true; } + } + + pub fn update(&mut self, val: Value) { + self.zero = val == 0; + self.positive = is_positive(val); + self.negative = is_negative(val); + } + + 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::Invalid => self.invalid, + Cond::Valid => !self.invalid, + Cond::Carry => self.carry, + Cond::NotCarry => !self.carry + } + } +} + +impl Display for StatusFlags { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str("[")?; + if self.equal { + f.write_str(" E")?; + } + if self.zero { + f.write_str(" Z")?; + } + if self.lower { + f.write_str(" L")?; + } + if self.greater { + f.write_str(" G")?; + } + if self.positive { + f.write_str(" P")?; + } + if self.negative { + f.write_str(" N")?; + } + if self.overflow { + f.write_str(" V")?; + } + if self.invalid { + f.write_str(" X")?; + } + if self.carry { + f.write_str(" C")?; + } + f.write_str(" ]")?; + + Ok(()) + } +} diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 88cdcb1..927b4b8 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1,8 +1,8 @@ #[macro_use] extern crate log; pub mod run_thread; -pub mod mlock; -pub mod sparse; +// pub mod mlock; +// pub mod sparse; pub mod fault; pub mod span; pub mod exec; diff --git a/runtime/src/run_thread.rs b/runtime/src/run_thread.rs index 40386c5..072b23e 100644 --- a/runtime/src/run_thread.rs +++ b/runtime/src/run_thread.rs @@ -1,11 +1,11 @@ use std::time::Duration; use std::thread::JoinHandle; -use asm::data::literal::{Addr, Value}; -use asm::instr::Op; -use crate::exec; -use asm::data::{Rd, SrcDisp, reg::Register, Wr, DstDisp}; -use crate::fault::Fault; +use asm::data::literal::{Addr}; + + + + use crate::frame::StackFrame; use crate::program::Program; use crate::exec::EvalRes;