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

This commit is contained in:
2020-09-25 22:45:57 +02:00
parent f652ff6669
commit 8e7689df48
13 changed files with 726 additions and 420 deletions
-1
View File
@@ -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
View File
@@ -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, ")")
}
+8 -1
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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;
+2 -2
View File
@@ -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
});
}
+375 -84
View File
@@ -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,143 +72,433 @@ 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())?
))
}
"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())?
))
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()));
}
})
}
"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(':') {
let label = Label::Named(label.to_string());