You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
515 lines
16 KiB
515 lines
16 KiB
use crate::instr::{HLOp, Op};
|
|
use sexp::Sexp;
|
|
use crate::error::Error;
|
|
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 ExactSizeIterator<Item=Sexp> + Clone) -> Result<HLOp, Error> {
|
|
Ok(match keyword {
|
|
"j" => {
|
|
let dest = parse_label(arg_tokens.next())?;
|
|
if far {
|
|
HLOp::L(Op::FarJump(dest))
|
|
} else {
|
|
HLOp::Jump(dest)
|
|
}
|
|
}
|
|
|
|
"call" => {
|
|
let dest = RoutineName(expect_string_atom(arg_tokens.next())?);
|
|
|
|
let mut args = vec![];
|
|
for t in arg_tokens {
|
|
args.push(parse_rd(Some(t))?);
|
|
}
|
|
HLOp::L(Op::Call(dest, args))
|
|
}
|
|
|
|
"ret" => {
|
|
let mut args = vec![];
|
|
for t in arg_tokens {
|
|
args.push(parse_rd(Some(t))?);
|
|
}
|
|
HLOp::L(Op::Ret(args))
|
|
}
|
|
|
|
"routine" => {
|
|
let dest = RoutineName(expect_string_atom(arg_tokens.next())?);
|
|
HLOp::L(Op::Routine(dest))
|
|
}
|
|
|
|
"s" => {
|
|
HLOp::L(Op::Skip(parse_rd(arg_tokens.next())?))
|
|
}
|
|
|
|
"sif" => {
|
|
let cond = parse_cond(&expect_string_atom(arg_tokens.next())?)?;
|
|
let offs = parse_rd(arg_tokens.next())?;
|
|
HLOp::L(Op::SkipIf(cond, offs))
|
|
}
|
|
|
|
"jif" => {
|
|
let cond = parse_cond(&expect_string_atom(arg_tokens.next())?)?;
|
|
let dest = parse_label(arg_tokens.next())?;
|
|
HLOp::JumpIf(cond, dest)
|
|
}
|
|
|
|
"barrier" => {
|
|
HLOp::L(Op::Barrier(match arg_tokens.next() {
|
|
None => None,
|
|
Some(s) => Some(expect_string_atom(Some(s))?.into()),
|
|
}))
|
|
}
|
|
|
|
"fault" => {
|
|
HLOp::L(Op::Fault(match arg_tokens.next() {
|
|
None => None,
|
|
Some(s) => Some(expect_string_atom(Some(s))?.into()),
|
|
}))
|
|
}
|
|
|
|
"ld" => {
|
|
HLOp::L(Op::Move {
|
|
dst: parse_wr(arg_tokens.next())?,
|
|
src: parse_rd(arg_tokens.next())?,
|
|
})
|
|
}
|
|
|
|
"cmp" => {
|
|
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::Test { a: arg })
|
|
}
|
|
|
|
"inc" => {
|
|
let dst = parse_wr(arg_tokens.next())?;
|
|
HLOp::L(Op::Add {
|
|
dst,
|
|
a: dst.as_rd(),
|
|
b: Rd::immediate(1),
|
|
})
|
|
}
|
|
|
|
"dec" => {
|
|
let dst = parse_wr(arg_tokens.next())?;
|
|
HLOp::L(Op::Sub {
|
|
dst,
|
|
a: dst.as_rd(),
|
|
b: Rd::immediate(1),
|
|
})
|
|
}
|
|
|
|
"add" => {
|
|
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(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(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(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(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(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(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(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(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(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(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(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(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()));
|
|
}
|
|
})
|
|
}
|
|
|
|
other => {
|
|
if let Some(label) = other.strip_prefix(':') {
|
|
let label = Label::Named(label.to_string());
|
|
if far {
|
|
HLOp::L(Op::FarLabel(label))
|
|
} else {
|
|
HLOp::Label(label)
|
|
}
|
|
} else {
|
|
return Err(Error::Parse(format!("Unknown instruction: {}", other).into()));
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|