add explicit retval arg to all instrs (can be shortened), add Wr::discard()
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::convert::TryFrom;
|
||||
use std::sync::atomic::AtomicU32;
|
||||
use std::borrow::Cow;
|
||||
|
||||
|
||||
+17
-5
@@ -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<DstDisp> 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<DstDisp> for SrcDisp {
|
||||
@@ -111,6 +114,7 @@ impl From<DstDisp> 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, ")")
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+21
-28
@@ -46,36 +46,29 @@ pub enum Op {
|
||||
/// Generate a run-time fault with a debugger message
|
||||
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
|
||||
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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ pub fn parse_instructions(instrs: Vec<Sexp>) -> Result<Vec<Instr>, 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::<Vec<_>>();
|
||||
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<Sexp>) -> Result<Vec<Instr>, 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
|
||||
});
|
||||
}
|
||||
|
||||
+373
-82
@@ -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<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 {
|
||||
"j" => {
|
||||
let dest = parse_label(arg_tokens.next())?;
|
||||
@@ -71,142 +72,432 @@ pub fn parse_op(keyword: &str, far : bool, mut arg_tokens: impl Iterator<Item=Se
|
||||
}
|
||||
|
||||
"ld" => {
|
||||
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())?,
|
||||
}
|
||||
|
||||
"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_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()));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
"divr" => {
|
||||
HLOp::L(Op::DivRem(
|
||||
parse_wr(arg_tokens.next())?,
|
||||
parse_wr(arg_tokens.next())?,
|
||||
parse_rd(arg_tokens.next())?
|
||||
))
|
||||
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()));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
"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()));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
"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(':') {
|
||||
|
||||
+151
-197
@@ -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) => {
|
||||
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);
|
||||
let res = frame.read(*a)?;
|
||||
frame.status.update(res);
|
||||
}
|
||||
Op::Inc(reg) => {
|
||||
Op::Compare { a, b } => {
|
||||
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 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::Dec(reg) => {
|
||||
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)?;
|
||||
}
|
||||
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) {
|
||||
let (res, remainder, ov) = if let Some(v) = x.checked_div(d) {
|
||||
(v, x.rem(d), false)
|
||||
} else {
|
||||
(x.wrapping_div(d), x.wrapping_rem(d), true)
|
||||
};
|
||||
frame.status.update(res);
|
||||
frame.status.overflow = ov;
|
||||
frame.write(*dst, res)?;
|
||||
frame.write(*rem, remainder)?;
|
||||
}
|
||||
}
|
||||
Op::Mod { dst, a, div } => {
|
||||
frame.status.clear();
|
||||
let x = frame.read(*a)?;
|
||||
let d = frame.read(*div)?;
|
||||
if d == 0 {
|
||||
frame.status.invalid = true;
|
||||
} else {
|
||||
let (remainder, ov) = if let Some(v) = x.checked_rem(d) {
|
||||
(v, false)
|
||||
} else {
|
||||
(a.wrapping_div(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::Mod(dst, 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 ?
|
||||
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, a, b } => {
|
||||
frame.status.clear();
|
||||
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, a, b } => {
|
||||
frame.status.clear();
|
||||
let x = frame.read(*a)?;
|
||||
let y = frame.read(*b)?;
|
||||
let res = x ^ y;
|
||||
frame.status.update(res);
|
||||
frame.write(*dst, res)?;
|
||||
}
|
||||
Op::Cpl { dst, a } => {
|
||||
frame.status.clear();
|
||||
let x = frame.read(*a)?;
|
||||
let res = !x;
|
||||
frame.status.update(res);
|
||||
frame.write(*dst, res)?;
|
||||
}
|
||||
Op::Rol { dst, a, n } => {
|
||||
frame.status.clear();
|
||||
let x = frame.read(*a)?;
|
||||
let y = frame.read(*n)?;
|
||||
if y > u32::MAX as u64 {
|
||||
frame.status.invalid = true;
|
||||
} else {
|
||||
let (val, ov) = if let Some(v) = a.checked_rem(b) {
|
||||
(v, false)
|
||||
let res = x.rotate_left(y as u32);
|
||||
frame.status.update(res);
|
||||
frame.write(*dst, res)?;
|
||||
}
|
||||
}
|
||||
Op::Ror { dst, a, n } => {
|
||||
frame.status.clear();
|
||||
let x = frame.read(*a)?;
|
||||
let y = frame.read(*n)?;
|
||||
if y > u32::MAX as u64 {
|
||||
frame.status.invalid = true;
|
||||
} else {
|
||||
(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)?;
|
||||
let res = x.rotate_right(y as u32);
|
||||
frame.status.update(res);
|
||||
frame.write(*dst, res)?;
|
||||
}
|
||||
}
|
||||
Op::DivRem(dst, remptr, src) => {
|
||||
Op::Lsl { dst, a, n } => {
|
||||
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 y = frame.read(*n)?;
|
||||
let res = x << y;
|
||||
frame.status.update(res);
|
||||
frame.write(*dst, res)?;
|
||||
}
|
||||
Op::Lsr { dst, a, n } => {
|
||||
frame.status.clear();
|
||||
let x = frame.read(*a)?;
|
||||
let y = frame.read(*n)?;
|
||||
let res = x >> y;
|
||||
frame.status.update(res);
|
||||
frame.write(*dst, res)?;
|
||||
}
|
||||
Op::Asr { dst, a, n } => {
|
||||
frame.status.clear();
|
||||
let x = frame.read(*a)?;
|
||||
let y = frame.read(*n)?;
|
||||
if y > u32::MAX as u64 {
|
||||
frame.status.invalid = true;
|
||||
} 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 res = x.signed_shr(y as u32);
|
||||
frame.status.update(res);
|
||||
frame.write(*dst, res)?;
|
||||
}
|
||||
}
|
||||
Op::And(dst, src) => {
|
||||
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)?;
|
||||
Op::StoreStatus { dst } => {
|
||||
let packed = frame.status.store();
|
||||
frame.write(*dst, packed)?;
|
||||
}
|
||||
Op::Or(dst, src) => {
|
||||
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)?;
|
||||
}
|
||||
Op::Xor(dst, src) => {
|
||||
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)?;
|
||||
}
|
||||
Op::Cpl(dst) => {
|
||||
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)?;
|
||||
}
|
||||
Op::Rol(dst, num) => {
|
||||
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)?;
|
||||
}
|
||||
Op::Ror(dst, num) => {
|
||||
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)?;
|
||||
}
|
||||
Op::Lsl(dst, num) => {
|
||||
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)?;
|
||||
}
|
||||
Op::Lsr(dst, num) => {
|
||||
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)?;
|
||||
}
|
||||
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::LoadStatus { src } => {
|
||||
let x = frame.read(*src)?;
|
||||
frame.status.load(x);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+14
-14
@@ -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 {
|
||||
|
||||
+11
-84
@@ -1,92 +1,15 @@
|
||||
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;
|
||||
|
||||
|
||||
|
||||
|
||||
mod status;
|
||||
use status::StatusFlags;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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
|
||||
@@ -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() {
|
||||
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
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user