add explicit retval arg to all instrs (can be shortened), add Wr::discard()

pull/21/head
Ondřej Hruška 4 years ago
parent f652ff6669
commit 8e7689df48
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 1
      asm/src/data/literal.rs
  2. 22
      asm/src/data/mod.rs
  3. 9
      asm/src/instr/cond.rs
  4. 49
      asm/src/instr/op.rs
  5. 2
      asm/src/parse/parse_data.rs
  6. 4
      asm/src/parse/parse_instr.rs
  7. 453
      asm/src/parse/parse_op.rs
  8. 320
      runtime/src/exec/mod.rs
  9. 28
      runtime/src/fault.rs
  10. 89
      runtime/src/frame.rs
  11. 123
      runtime/src/frame/status.rs
  12. 4
      runtime/src/lib.rs
  13. 10
      runtime/src/run_thread.rs

@ -1,5 +1,4 @@
use std::fmt::{self, Display, Formatter}; use std::fmt::{self, Display, Formatter};
use std::convert::TryFrom;
use std::sync::atomic::AtomicU32; use std::sync::atomic::AtomicU32;
use std::borrow::Cow; use std::borrow::Cow;

@ -11,7 +11,7 @@ use literal::Addr;
use std::convert::TryFrom; 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::{Debug, Formatter, Display};
use std::fmt; use std::fmt;
@ -64,6 +64,7 @@ impl From<DstDisp> for DataDisp {
DstDisp::ImmediatePtr(x) => DataDisp::ImmediatePtr(x), DstDisp::ImmediatePtr(x) => DataDisp::ImmediatePtr(x),
DstDisp::Register(x) => DataDisp::Register(x), DstDisp::Register(x) => DataDisp::Register(x),
DstDisp::RegisterPtr(x) => DataDisp::RegisterPtr(x), DstDisp::RegisterPtr(x) => DataDisp::RegisterPtr(x),
DstDisp::Discard => DataDisp::Immediate(0),
} }
} }
} }
@ -103,6 +104,8 @@ pub enum DstDisp {
Register(Register), Register(Register),
/// Pointer into memory, stored in a numbered register /// Pointer into memory, stored in a numbered register
RegisterPtr(Register), RegisterPtr(Register),
/// Discard the written value
Discard,
} }
impl From<DstDisp> for SrcDisp { impl From<DstDisp> for SrcDisp {
@ -111,6 +114,7 @@ impl From<DstDisp> for SrcDisp {
DstDisp::ImmediatePtr(x) => SrcDisp::ImmediatePtr(x), DstDisp::ImmediatePtr(x) => SrcDisp::ImmediatePtr(x),
DstDisp::Register(x) => SrcDisp::Register(x), DstDisp::Register(x) => SrcDisp::Register(x),
DstDisp::RegisterPtr(x) => SrcDisp::RegisterPtr(x), DstDisp::RegisterPtr(x) => SrcDisp::RegisterPtr(x),
DstDisp::Discard => SrcDisp::Immediate(0),
} }
} }
} }
@ -142,6 +146,10 @@ impl Rd {
pub fn mask(self) -> Mask { pub fn mask(self) -> Mask {
self.1 self.1
} }
pub fn immediate(val : Value) -> Rd {
Rd(SrcDisp::Immediate(val), Mask::default())
}
} }
/// Data destination argument (read-write) /// Data destination argument (read-write)
@ -161,15 +169,19 @@ impl Wr {
pub fn as_rd(&self) -> Rd { pub fn as_rd(&self) -> Rd {
Rd(self.0.into(), self.1) Rd(self.0.into(), self.1)
} }
pub fn discard() -> Wr {
Wr(DstDisp::Discard, Mask::default())
}
} }
impl Debug for Rd { impl Debug for Rd {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "Rd(")?; write!(f, "Rd(")?;
let disp : DataDisp = self.0.into(); let disp : DataDisp = self.0.into();
write!(f, "{}", disp); write!(f, "{}", disp)?;
if !self.mask().is_default() { if !self.mask().is_default() {
write!(f, ",{:?}", self.mask()); write!(f, ",{:?}", self.mask())?;
} }
write!(f, ")") write!(f, ")")
} }
@ -179,9 +191,9 @@ impl Debug for Wr {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "Wr(")?; write!(f, "Wr(")?;
let disp : DataDisp = self.0.into(); let disp : DataDisp = self.0.into();
write!(f, "{}", disp); write!(f, "{}", disp)?;
if !self.mask().is_default() { if !self.mask().is_default() {
write!(f, ",{:?}", self.mask()); write!(f, ",{:?}", self.mask())?;
} }
write!(f, ")") write!(f, ")")
} }

@ -17,6 +17,8 @@ pub enum Cond {
NonNegative, NonNegative,
Overflow, Overflow,
NotOverflow, NotOverflow,
Invalid,
Valid,
Carry, Carry,
NotCarry, NotCarry,
} }
@ -37,9 +39,11 @@ impl Display for Cond {
Cond::NonPositive => "npos", Cond::NonPositive => "npos",
Cond::NonNegative => "nneg", Cond::NonNegative => "nneg",
Cond::Overflow => "ov", Cond::Overflow => "ov",
Cond::NotOverflow => "nov",
Cond::Carry => "c", Cond::Carry => "c",
Cond::NotCarry => "nc", 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::Greater => Cond::LowerOrEqual,
Cond::LowerOrEqual => Cond::Greater, Cond::LowerOrEqual => Cond::Greater,
Cond::GreaterOrEqual => Cond::Lower, Cond::GreaterOrEqual => Cond::Lower,
Cond::Invalid => Cond::Valid,
Cond::Valid => Cond::Invalid,
} }
} }
} }

@ -46,36 +46,29 @@ pub enum Op {
/// Generate a run-time fault with a debugger message /// Generate a run-time fault with a debugger message
Fault(Option<DebugMsg>), Fault(Option<DebugMsg>),
/* Arithmetic */ Move { dst: Wr, src: Rd },
Test { a: Rd },
Compare { a: Rd, b: Rd },
StoreStatus { dst: Wr },
LoadStatus { src: Rd },
/// Copy a value Add { dst: Wr, a: Rd, b: Rd },
Mov(Wr, Rd), Sub { dst: Wr, a: Rd, b: Rd },
/// Compare two values and set conditional flags. Mul { dst: Wr, a: Rd, b: Rd },
/// If the values are identical, evaluate if they are zero, positive, or negative (the "tst" op) Div { dst: Wr, rem: Wr, a: Rd, div: Rd },
Cmp(Rd, 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 And { dst: Wr, a: Rd, b: Rd },
Inc(Wr), Or { dst: Wr, a: Rd, b: Rd },
Dec(Wr), Xor { dst: Wr, a: Rd, b: Rd },
Add(Wr, Rd), Cpl { dst: Wr, a: Rd },
Sub(Wr, Rd), Rol { dst: Wr, a: Rd, n: Rd }, // Rotate (with wrap-around)
Mul(Wr, Rd), Ror { dst: Wr, a: Rd, n: Rd },
Div(Wr, Rd), Lsl { dst: Wr, a: Rd, n: Rd }, // Shift
Mod(Wr, Rd), Lsr { dst: Wr, a: Rd, n: Rd },
DivRem(Wr, /*rem*/Wr, Rd), Asr { dst: Wr, a: Rd, n: 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
} }
/// Make "into" work /// Make "into" work

@ -1,7 +1,7 @@
use sexp::{Sexp, Atom}; use sexp::{Sexp, Atom};
use crate::data::{DataDisp, Rd, Wr, DstDisp, SrcDisp, reg}; use crate::data::{DataDisp, Rd, Wr, DstDisp, SrcDisp, reg};
use crate::error::Error; use crate::error::Error;
use crate::data::literal::{Value, Addr, Label}; use crate::data::literal::{Addr, Label};
use std::convert::TryFrom; use std::convert::TryFrom;
use crate::parse::sexp_expect::expect_string_atom; use crate::parse::sexp_expect::expect_string_atom;

@ -24,7 +24,7 @@ pub fn parse_instructions(instrs: Vec<Sexp>) -> Result<Vec<Instr>, Error> {
false false
}; };
let arg_tokens = toki.clone().take_while(|e| e.is_atom()); let arg_tokens = toki.clone().take_while(|e| e.is_atom()).collect::<Vec<_>>();
let branch_tokens = toki let branch_tokens = toki
.skip_while(|e| e.is_atom()) .skip_while(|e| e.is_atom())
.take_while(|e| e.is_list()); .take_while(|e| e.is_list());
@ -42,7 +42,7 @@ pub fn parse_instructions(instrs: Vec<Sexp>) -> Result<Vec<Instr>, Error> {
}; };
parsed.push(Instr { parsed.push(Instr {
op: parse_op(name.as_str(), far, arg_tokens)?, op: parse_op(name.as_str(), far, arg_tokens.into_iter())?,
branches branches
}); });
} }

@ -5,8 +5,9 @@ use crate::data::literal::{RoutineName, Label};
use crate::parse::sexp_expect::expect_string_atom; use crate::parse::sexp_expect::expect_string_atom;
use crate::parse::parse_data::{parse_rd, parse_wr, parse_label}; use crate::parse::parse_data::{parse_rd, parse_wr, parse_label};
use crate::parse::parse_cond::parse_cond; 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<Item=Sexp>) -> Result<HLOp, Error> { pub fn parse_op(keyword: &str, far: bool, mut arg_tokens: impl ExactSizeIterator<Item=Sexp> + Clone) -> Result<HLOp, Error> {
Ok(match keyword { Ok(match keyword {
"j" => { "j" => {
let dest = parse_label(arg_tokens.next())?; let dest = parse_label(arg_tokens.next())?;
@ -71,143 +72,433 @@ pub fn parse_op(keyword: &str, far : bool, mut arg_tokens: impl Iterator<Item=Se
} }
"ld" => { "ld" => {
HLOp::L(Op::Mov( HLOp::L(Op::Move {
parse_wr(arg_tokens.next())?, dst: parse_wr(arg_tokens.next())?,
parse_rd(arg_tokens.next())? src: parse_rd(arg_tokens.next())?,
)) })
} }
"cmp" => { "cmp" => {
HLOp::L(Op::Cmp( HLOp::L(Op::Compare {
parse_rd(arg_tokens.next())?, a: parse_rd(arg_tokens.next())?,
parse_rd(arg_tokens.next())? b: parse_rd(arg_tokens.next())?,
)) })
} }
"tst" => { "tst" => {
let arg = parse_rd(arg_tokens.next())?; let arg = parse_rd(arg_tokens.next())?;
HLOp::L(Op::Cmp(arg, arg)) HLOp::L(Op::Test { a: arg })
} }
"inc" => { "inc" => {
HLOp::L(Op::Inc( let dst = parse_wr(arg_tokens.next())?;
parse_wr(arg_tokens.next())? HLOp::L(Op::Add {
)) dst,
a: dst.as_rd(),
b: Rd::immediate(1),
})
} }
"dec" => { "dec" => {
HLOp::L(Op::Dec( let dst = parse_wr(arg_tokens.next())?;
parse_wr(arg_tokens.next())? HLOp::L(Op::Sub {
)) dst,
a: dst.as_rd(),
b: Rd::immediate(1),
})
} }
"add" => { "add" => {
HLOp::L(Op::Add( HLOp::L(match arg_tokens.len() {
parse_wr(arg_tokens.next())?, 3 => {
parse_rd(arg_tokens.next())? 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" => { "sub" => {
HLOp::L(Op::Sub( HLOp::L(match arg_tokens.len() {
parse_wr(arg_tokens.next())?, 3 => {
parse_rd(arg_tokens.next())? 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" => { "mul" => {
HLOp::L(Op::Mul( HLOp::L(match arg_tokens.len() {
parse_wr(arg_tokens.next())?, 3 => {
parse_rd(arg_tokens.next())? 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" => { "divr" => {
HLOp::L(Op::Div( HLOp::L(match arg_tokens.len() {
parse_wr(arg_tokens.next())?, 3 => {
parse_rd(arg_tokens.next())? 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" => { "div" => {
HLOp::L(Op::Mod( HLOp::L(match arg_tokens.len() {
parse_wr(arg_tokens.next())?, 3 => {
parse_rd(arg_tokens.next())? 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" => { "mod" => {
HLOp::L(Op::DivRem( HLOp::L(match arg_tokens.len() {
parse_wr(arg_tokens.next())?, 3 => {
parse_wr(arg_tokens.next())?, Op::Mod {
parse_rd(arg_tokens.next())? 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" => { "and" => {
HLOp::L(Op::And( HLOp::L(match arg_tokens.len() {
parse_wr(arg_tokens.next())?, 3 => {
parse_rd(arg_tokens.next())? 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" => { "or" => {
HLOp::L(Op::Or( HLOp::L(match arg_tokens.len() {
parse_wr(arg_tokens.next())?, 3 => {
parse_rd(arg_tokens.next())? 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" => { "xor" => {
HLOp::L(Op::Xor( HLOp::L(match arg_tokens.len() {
parse_wr(arg_tokens.next())?, 3 => {
parse_rd(arg_tokens.next())? 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" => { "cpl" => {
HLOp::L(Op::Cpl( HLOp::L(match arg_tokens.len() {
parse_wr(arg_tokens.next())? 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" => { "rol" => {
HLOp::L(Op::Rol( HLOp::L(match arg_tokens.len() {
parse_wr(arg_tokens.next())?, 3 => {
parse_rd(arg_tokens.next())? 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" => { "ror" => {
HLOp::L(Op::Ror( HLOp::L(match arg_tokens.len() {
parse_wr(arg_tokens.next())?, 3 => {
parse_rd(arg_tokens.next())? 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" => { "lsl" | "asl" => {
HLOp::L(Op::Lsl( HLOp::L(match arg_tokens.len() {
parse_wr(arg_tokens.next())?, 3 => {
parse_rd(arg_tokens.next())? 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" => { "lsr" => {
HLOp::L(Op::Lsr( HLOp::L(match arg_tokens.len() {
parse_wr(arg_tokens.next())?, 3 => {
parse_rd(arg_tokens.next())? 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" => { "asr" => {
HLOp::L(Op::Asr( HLOp::L(match arg_tokens.len() {
parse_wr(arg_tokens.next())?, 3 => {
parse_rd(arg_tokens.next())? 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 => { other => {
if let Some(label) = other.strip_prefix(':') { if let Some(label) = other.strip_prefix(':') {
let label = Label::Named(label.to_string()); let label = Label::Named(label.to_string());

@ -1,9 +1,9 @@
use crate::run_thread::{ThreadToken, RunThread}; use crate::run_thread::{RunThread};
use asm::instr::{Op, Cond}; use asm::instr::{Op};
use crate::fault::Fault; use crate::fault::Fault;
use crate::frame::StackFrame; use crate::frame::StackFrame;
use asm::data::literal::{Value, is_positive, is_negative, Addr}; use asm::data::literal::{Addr};
use std::ops::{Rem, BitXor, Shl}; use std::ops::{Rem};
use num_traits::PrimInt; use num_traits::PrimInt;
pub type CyclesSpent = usize; pub type CyclesSpent = usize;
@ -38,12 +38,12 @@ impl RunThread {
Op::Barrier(msg) => { Op::Barrier(msg) => {
return Err(Fault::Barrier { return Err(Fault::Barrier {
msg: msg.clone().unwrap_or_else(|| "No msg".into()) msg: msg.clone().unwrap_or_else(|| "No msg".into())
}) });
} }
Op::Fault(msg) => { Op::Fault(msg) => {
return Err(Fault::FaultInstr { return Err(Fault::FaultInstr {
msg: msg.clone().unwrap_or_else(|| "No msg".into()) msg: msg.clone().unwrap_or_else(|| "No msg".into())
}) });
} }
Op::FarJump(name) => { Op::FarJump(name) => {
debug!("Far jump to {}", name); debug!("Far jump to {}", name);
@ -56,7 +56,7 @@ impl RunThread {
return Err(e); return Err(e);
} }
} }
}, }
Op::Call(name, args) => { Op::Call(name, args) => {
debug!("Call routine {}", name); debug!("Call routine {}", name);
match self.program.find_routine(name) { match self.program.find_routine(name) {
@ -77,7 +77,7 @@ impl RunThread {
return Err(e); return Err(e);
} }
} }
}, }
Op::Ret(retvals) => { Op::Ret(retvals) => {
match self.call_stack.pop() { match self.call_stack.pop() {
Some(previous) => { Some(previous) => {
@ -93,7 +93,7 @@ impl RunThread {
return Err(Fault::CallStackUnderflow); return Err(Fault::CallStackUnderflow);
} }
} }
}, }
Op::Skip(val) => { Op::Skip(val) => {
let steps = frame.read(*val)?; let steps = frame.read(*val)?;
advance = i64::from_ne_bytes(steps.to_ne_bytes()); 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))?; 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(); frame.status.clear();
let val = frame.read(*src)?; let val = frame.read(*src)?;
frame.status.zero = (val == 0); frame.status.update(val);
frame.status.positive = is_positive(val);
frame.status.negative = is_negative(val);
frame.write(*dst, val)?; frame.write(*dst, val)?;
} }
Op::Cmp(a, b) => { Op::Test { a } => {
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) => {
frame.status.clear(); frame.status.clear();
let mut val = frame.read(reg.as_rd())?; let res = frame.read(*a)?;
val = val.wrapping_add(1); frame.status.update(res);
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)?;
} }
Op::Dec(reg) => { Op::Compare { a, b } => {
frame.status.clear(); frame.status.clear();
let mut val = frame.read(reg.as_rd())?; let x = frame.read(*a)?;
frame.status.overflow = (val == 0); // will overflow let y = frame.read(*b)?;
val = val.wrapping_sub(1); frame.status.equal = x == y;
frame.status.zero = (val == 0); frame.status.lower = x < y;
frame.status.positive = is_positive(val); frame.status.greater = x > y;
frame.status.negative = is_negative(val); // Test flags are set when both arguments have the property
frame.write(*reg, val)?; if x == y {
frame.status.update(x);
}
} }
Op::Add(dst, src) => { Op::Add { dst, a, b } => {
frame.status.clear(); frame.status.clear();
let mut a = frame.read(dst.as_rd())?; let x = frame.read(*a)?;
let mut b = frame.read(*src)?; let y = frame.read(*b)?;
let (val, ov) = if let Some(v) = a.checked_add(b) { let (res, ov) = if let Some(v) = x.checked_add(y) {
(v, false) (v, false)
} else { } else {
(a.wrapping_add(b), true) (x.wrapping_add(y), true)
}; };
frame.status.zero = (val == 0); frame.status.update(res);
frame.status.positive = is_positive(val);
frame.status.negative = is_negative(val);
frame.status.overflow = ov; frame.status.overflow = ov;
frame.write(*dst, val)?; frame.write(*dst, res)?;
} }
Op::Sub(dst, src) => { Op::Sub { dst, a, b } => {
frame.status.clear(); frame.status.clear();
let mut a = frame.read(dst.as_rd())?; let x = frame.read(*a)?;
let mut b = frame.read(*src)?; let y = frame.read(*b)?;
let (val, ov) = if let Some(v) = a.checked_sub(b) { let (res, ov) = if let Some(v) = x.checked_sub(y) {
(v, false) (v, false)
} else { } else {
(a.wrapping_sub(b), true) (x.wrapping_sub(y), true)
}; };
frame.status.zero = (val == 0); frame.status.update(res);
frame.status.positive = is_positive(val);
frame.status.negative = is_negative(val);
frame.status.overflow = ov; frame.status.overflow = ov;
frame.write(*dst, val)?; frame.write(*dst, res)?;
} }
Op::Mul(dst, src) => { Op::Mul { dst, a, b } => {
frame.status.clear(); frame.status.clear();
let mut a = frame.read(dst.as_rd())?; let x = frame.read(*a)?;
let mut b = frame.read(*src)?; let y = frame.read(*b)?;
let (val, ov) = if let Some(v) = a.checked_mul(b) { let (res, ov) = if let Some(v) = x.checked_mul(y) {
(v, false) (v, false)
} else { } else {
(a.wrapping_mul(b), true) (x.wrapping_mul(y), true)
}; };
frame.status.zero = (val == 0); frame.status.update(res);
frame.status.positive = is_positive(val);
frame.status.negative = is_negative(val);
frame.status.overflow = ov; 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(); frame.status.clear();
let mut a = frame.read(dst.as_rd())?; let x = frame.read(*a)?;
let mut b = frame.read(*src)?; let d = frame.read(*div)?;
if b == 0 { if d == 0 {
frame.status.overflow = true; frame.status.invalid = true;
// TODO ?
} else { } else {
let (val, ov) = if let Some(v) = a.checked_div(b) { let (res, remainder, ov) = if let Some(v) = x.checked_div(d) {
(v, false) (v, x.rem(d), false)
} else { } else {
(a.wrapping_div(b), true) (x.wrapping_div(d), x.wrapping_rem(d), true)
}; };
frame.status.zero = (val == 0); frame.status.update(res);
frame.status.positive = is_positive(val);
frame.status.negative = is_negative(val);
frame.status.overflow = ov; 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(); frame.status.clear();
let mut a = frame.read(dst.as_rd())?; let x = frame.read(*a)?;
let mut b = frame.read(*src)?; let d = frame.read(*div)?;
if b == 0 { if d == 0 {
frame.status.overflow = true; frame.status.invalid = true;
// TODO ?
} else { } 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) (v, false)
} else { } else {
(a.wrapping_rem(b), true) (x.wrapping_rem(d), true)
}; };
frame.status.zero = (val == 0); frame.status.update(remainder);
frame.status.positive = is_positive(val);
frame.status.negative = is_negative(val);
frame.status.overflow = ov; 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(); frame.status.clear();
let mut a = frame.read(dst.as_rd())?; let x = frame.read(*a)?;
let mut b = frame.read(*src)?; let y = frame.read(*b)?;
if b == 0 { let res = x & y;
frame.status.overflow = true; frame.status.update(res);
// TODO ? frame.write(*dst, res)?;
} 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)?;
}
} }
Op::And(dst, src) => { Op::Or { dst, a, b } => {
frame.status.clear(); frame.status.clear();
let mut val = frame.read(dst.as_rd())?; let x = frame.read(*a)?;
let mut b = frame.read(*src)?; let y = frame.read(*b)?;
val &= b; let res = x | y;
frame.status.zero = (val == 0); frame.status.update(res);
frame.status.positive = is_positive(val); frame.write(*dst, res)?;
frame.status.negative = is_negative(val);
frame.write(*dst, val)?;
} }
Op::Or(dst, src) => { Op::Xor { dst, a, b } => {
frame.status.clear(); frame.status.clear();
let mut val = frame.read(dst.as_rd())?; let x = frame.read(*a)?;
let mut b = frame.read(*src)?; let y = frame.read(*b)?;
val |= b; let res = x ^ y;
frame.status.zero = (val == 0); frame.status.update(res);
frame.status.positive = is_positive(val); frame.write(*dst, res)?;
frame.status.negative = is_negative(val);
frame.write(*dst, val)?;
} }
Op::Xor(dst, src) => { Op::Cpl { dst, a } => {
frame.status.clear(); frame.status.clear();
let mut val = frame.read(dst.as_rd())?; let x = frame.read(*a)?;
let mut b = frame.read(*src)?; let res = !x;
val ^= b; frame.status.update(res);
frame.status.zero = (val == 0); frame.write(*dst, res)?;
frame.status.positive = is_positive(val);
frame.status.negative = is_negative(val);
frame.write(*dst, val)?;
} }
Op::Cpl(dst) => { Op::Rol { dst, a, n } => {
frame.status.clear(); frame.status.clear();
let mut val = frame.read(dst.as_rd())?; let x = frame.read(*a)?;
val = !val; let y = frame.read(*n)?;
frame.status.zero = (val == 0); if y > u32::MAX as u64 {
frame.status.positive = is_positive(val); frame.status.invalid = true;
frame.status.negative = is_negative(val); } else {
frame.write(*dst, val)?; 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(); frame.status.clear();
let mut val = frame.read(dst.as_rd())?; let x = frame.read(*a)?;
let mut b = frame.read(*num)?; let y = frame.read(*n)?;
val = val.rotate_left(b as u32); // FIXME check overflow if y > u32::MAX as u64 {
frame.status.zero = (val == 0); frame.status.invalid = true;
frame.status.positive = is_positive(val); } else {
frame.status.negative = is_negative(val); let res = x.rotate_right(y as u32);
frame.write(*dst, val)?; frame.status.update(res);
frame.write(*dst, res)?;
}
} }
Op::Ror(dst, num) => { Op::Lsl { dst, a, n } => {
frame.status.clear(); frame.status.clear();
let mut val = frame.read(dst.as_rd())?; let x = frame.read(*a)?;
let mut b = frame.read(*num)?; let y = frame.read(*n)?;
val = val.rotate_right(b as u32); // FIXME check overflow let res = x << y;
frame.status.zero = (val == 0); frame.status.update(res);
frame.status.positive = is_positive(val); frame.write(*dst, res)?;
frame.status.negative = is_negative(val);
frame.write(*dst, val)?;
} }
Op::Lsl(dst, num) => { Op::Lsr { dst, a, n } => {
frame.status.clear(); frame.status.clear();
let mut val = frame.read(dst.as_rd())?; let x = frame.read(*a)?;
let mut b = frame.read(*num)?; let y = frame.read(*n)?;
val = val << b; let res = x >> y;
frame.status.zero = (val == 0); frame.status.update(res);
frame.status.positive = is_positive(val); frame.write(*dst, res)?;
frame.status.negative = is_negative(val);
frame.write(*dst, val)?;
} }
Op::Lsr(dst, num) => { Op::Asr { dst, a, n } => {
frame.status.clear(); frame.status.clear();
let mut val = frame.read(dst.as_rd())?; let x = frame.read(*a)?;
let mut b = frame.read(*num)?; let y = frame.read(*n)?;
val = val >> b; if y > u32::MAX as u64 {
frame.status.zero = (val == 0); frame.status.invalid = true;
frame.status.positive = is_positive(val); } else {
frame.status.negative = is_negative(val); let res = x.signed_shr(y as u32);
frame.write(*dst, val)?; frame.status.update(res);
frame.write(*dst, res)?;
}
} }
Op::Asr(dst, num) => { Op::StoreStatus { dst } => {
frame.status.clear(); let packed = frame.status.store();
let mut val = frame.read(dst.as_rd())?; frame.write(*dst, packed)?;
let mut b = frame.read(*num)?; }
val = val.signed_shr(b as u32); // FIXME check overflow Op::LoadStatus { src } => {
frame.status.zero = (val == 0); let x = frame.read(*src)?;
frame.status.positive = is_positive(val); frame.status.load(x);
frame.status.negative = is_negative(val);
frame.write(*dst, val)?;
} }
} }

@ -1,7 +1,7 @@
use thiserror::Error; use thiserror::Error;
use super::span::MemorySpan; // use super::span::MemorySpan;
use crate::run_thread::ThreadToken; // use crate::run_thread::ThreadToken;
use crate::mlock::ClaimId; // use crate::mlock::ClaimId;
use asm::data::literal::{DebugMsg, RoutineName, Label}; use asm::data::literal::{DebugMsg, RoutineName, Label};
use asm::data::Register; use asm::data::Register;
@ -23,17 +23,17 @@ pub enum Fault {
msg: DebugMsg, msg: DebugMsg,
}, },
#[error("Memory region {area:?} is locked by thread {owner:?}")] // #[error("Memory region {area:?} is locked by thread {owner:?}")]
MemoryLocked { // MemoryLocked {
area: MemorySpan, // area: MemorySpan,
owner: ThreadToken // owner: ThreadToken
}, // },
//
#[error("Memory claim {claim:?} owned by thread {owner:?} does not exist")] // #[error("Memory claim {claim:?} owned by thread {owner:?} does not exist")]
ClaimNotExist { // ClaimNotExist {
claim: ClaimId, // claim: ClaimId,
owner: ThreadToken // owner: ThreadToken
}, // },
#[error("Register does not exist: {reg:?}")] #[error("Register does not exist: {reg:?}")]
RegisterNotExist { RegisterNotExist {

@ -1,91 +1,14 @@
use asm::data::literal::{Addr, Value}; use asm::data::literal::{Addr, Value};
use asm::data::{Rd, SrcDisp, Register, Wr, DstDisp}; use asm::data::{Rd, SrcDisp, Register, Wr, DstDisp};
use crate::fault::Fault; 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 { mod status;
pub fn clear(&mut self) { use status::StatusFlags;
*self = Self::default();
}
pub fn test(&self, cond: Cond) -> bool { pub const REG_COUNT: usize = 8;
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)] #[derive(Default, Clone, Debug)]
pub struct StackFrame { pub struct StackFrame {
@ -118,7 +41,7 @@ impl StackFrame {
} }
} }
pub fn read(&mut self, rd: Rd) -> Result<u64, Fault> { pub fn read(&mut self, rd: Rd) -> Result<Value, Fault> {
match rd.d() { match rd.d() {
SrcDisp::Immediate(v) => Ok(v), SrcDisp::Immediate(v) => Ok(v),
SrcDisp::ImmediatePtr(_) => { SrcDisp::ImmediatePtr(_) => {
@ -161,6 +84,10 @@ impl StackFrame {
DstDisp::ImmediatePtr(_) => { DstDisp::ImmediatePtr(_) => {
unimplemented!("Immediate ptr") unimplemented!("Immediate ptr")
} }
DstDisp::Discard => {
/* Discard */
Ok(())
}
DstDisp::Register(Register::Res(rn)) => { DstDisp::Register(Register::Res(rn)) => {
if rn >= REG_COUNT as u8 { 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 Err(Fault::RegisterNotExist { reg: Register::Res(rn) }) // TODO use match after @ when stabilized https://github.com/rust-lang/rust/issues/65490

@ -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(())
}
}

@ -1,8 +1,8 @@
#[macro_use] extern crate log; #[macro_use] extern crate log;
pub mod run_thread; pub mod run_thread;
pub mod mlock; // pub mod mlock;
pub mod sparse; // pub mod sparse;
pub mod fault; pub mod fault;
pub mod span; pub mod span;
pub mod exec; pub mod exec;

@ -1,11 +1,11 @@
use std::time::Duration; use std::time::Duration;
use std::thread::JoinHandle; use std::thread::JoinHandle;
use asm::data::literal::{Addr, Value}; use asm::data::literal::{Addr};
use asm::instr::Op;
use crate::exec;
use asm::data::{Rd, SrcDisp, reg::Register, Wr, DstDisp};
use crate::fault::Fault;
use crate::frame::StackFrame; use crate::frame::StackFrame;
use crate::program::Program; use crate::program::Program;
use crate::exec::EvalRes; use crate::exec::EvalRes;

Loading…
Cancel
Save