add low level ops enum

pull/21/head
Ondřej Hruška 4 years ago
parent ab843c0c87
commit def2fc8db0
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 11
      csn_asm/src/data/mod.rs
  2. 18
      csn_asm/src/data/reg.rs
  3. 2
      csn_asm/src/error.rs
  4. 41
      csn_asm/src/instr/flatten.rs
  5. 5
      csn_asm/src/instr/mod.rs
  6. 41
      csn_asm/src/instr/op.rs
  7. 176
      csn_asm/src/lib.rs
  8. 4
      csn_asm/src/parse/mod.rs
  9. 26
      csn_asm/src/parse/parse_data.rs
  10. 64
      csn_asm/src/parse/parse_op.rs

@ -1,15 +1,14 @@
use super::error::AsmError;
pub(crate) mod literal;
mod reg;
mod mask;
pub mod literal;
pub mod reg;
pub mod mask;
pub use reg::Register;
pub use mask::Mask;
use literal::Addr;
use std::convert::TryFrom;
use crate::data::literal::Value;
@ -79,7 +78,7 @@ impl TryFrom<DataDisp> for DstDisp {
/// Data source argument (read-only)
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Rd(pub SrcDisp, pub Mask);
pub struct Rd(SrcDisp, Mask);
impl Rd {
pub fn new(src : SrcDisp) -> Self {
@ -89,7 +88,7 @@ impl Rd {
/// Data destination argument (read-write)
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Wr(pub DstDisp, pub Mask);
pub struct Wr(DstDisp, Mask);
impl Wr {
pub fn new(dst : DstDisp) -> Self {

@ -1,4 +1,5 @@
use std::fmt::{self, Display, Formatter};
use crate::error::Error;
/// Register name
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
@ -8,7 +9,7 @@ pub enum Register {
/// Result register, read-only
Res(u8),
/// General purpose register
Gen(u8)
Gen(u8),
}
impl Display for Register {
@ -20,3 +21,18 @@ impl Display for Register {
}
}
}
pub fn parse_reg(name : &str) -> anyhow::Result<Register> {
if let Some(rn) = name.strip_prefix("arg") {
let val : u8 = rn.parse()?;
Ok(Register::Arg(val))
} else if let Some(rn) = name.strip_prefix("res") {
let val : u8 = rn.parse()?;
Ok(Register::Res(val))
} else if let Some(rn) = name.strip_prefix("r") {
let val : u8 = rn.parse()?;
Ok(Register::Gen(val))
} else {
Err(Error::Parse(format!("Bad reg name: {}", name).into()))?
}
}

@ -37,6 +37,8 @@ pub enum AsmError {
ConditionalAlreadyUsed(Cond),
#[error("Label \"{0:?}\" not defined")]
LabelNotDefined(Label),
#[error("Bad register type: {0}")]
BadRegisterType(Register),
}
/// Architectural error - the code is syntactically OK, but cannot run

@ -1,18 +1,17 @@
use std::sync::atomic::AtomicU32;
use crate::instr::{Op, Instr, Cond, Routine};
use crate::instr::{HLOp, Instr, Cond, Routine, Op};
use crate::error::{Error, AsmError};
use std::collections::HashMap;
use crate::data::literal::{Label, Value};
use crate::instr::op::Op::{Skip, SkipIf};
use crate::data::{Rd, SrcDisp, Mask};
use crate::data::{Rd, SrcDisp};
/// A trait for something that can turn into multiple instructions
pub trait Flatten {
fn flatten(self, label_num: &AtomicU32) -> Result<Vec<Op>, Error>;
fn flatten(self, label_num: &AtomicU32) -> Result<Vec<HLOp>, Error>;
}
impl Flatten for Instr {
fn flatten(self, label_num: &AtomicU32) -> Result<Vec<Op>, Error> {
fn flatten(self, label_num: &AtomicU32) -> Result<Vec<HLOp>, Error> {
let mut ops = vec![self.op];
if let Some(branches) = self.branches {
@ -29,18 +28,18 @@ impl Flatten for Instr {
} else {
Label::unique(label_num)
};
ops.push(Op::JumpIf(!cond, next_lbl.clone()));
ops.push(HLOp::JumpIf(!cond, next_lbl.clone()));
for branch_instr in branch {
ops.extend(branch_instr.flatten(label_num)?);
}
if cnt != branch_count - 1 {
ops.push(Op::Jump(end_lbl.clone()));
ops.push(Op::Label(next_lbl));
ops.push(HLOp::Jump(end_lbl.clone()));
ops.push(HLOp::Label(next_lbl));
}
}
ops.push(Op::Label(end_lbl));
ops.push(HLOp::Label(end_lbl));
}
Ok(ops)
@ -48,25 +47,25 @@ impl Flatten for Instr {
}
impl Flatten for Routine {
fn flatten(self, label_num: &AtomicU32) -> Result<Vec<Op>, Error> {
fn flatten(self, label_num: &AtomicU32) -> Result<Vec<HLOp>, Error> {
let mut ops = vec![
Op::Routine(self.name.clone()),
Op::Routine(self.name.clone()).into(),
];
for instr in self.body {
ops.extend(instr.flatten(label_num)?);
}
ops.push(Op::Barrier(Some(format!("Routine \"{}\" overrun", self.name).into())));
ops.push(Op::Barrier(Some(format!("Routine \"{}\" overrun", self.name).into())).into());
Ok(ops)
}
}
/// Convert jumps to relative skips
pub fn jumps_to_skips(ops: Vec<Op>) -> Result<Vec<Op>, Error> {
pub fn lower(ops: Vec<HLOp>) -> Result<Vec<Op>, Error> {
let mut label_positions = HashMap::<Label, usize>::new();
for (n, op) in ops.iter().enumerate() {
if let Op::Label(name) = op {
if let HLOp::Label(name) = op {
label_positions.insert(name.clone(), n - label_positions.len());
}
}
@ -75,27 +74,27 @@ pub fn jumps_to_skips(ops: Vec<Op>) -> Result<Vec<Op>, Error> {
let mut skipped = 0;
for (n, op) in ops.into_iter().enumerate() {
match op {
Op::Label(_) => {
HLOp::Label(_) => {
skipped += 1;
}
Op::Jump(target) => {
HLOp::Jump(target) => {
if let Some(dest) = label_positions.get(&target) {
let skip = *dest as isize - n as isize + skipped;
cleaned.push(Skip(Rd(SrcDisp::Immediate(Value(skip as i64)), Mask::default())));
cleaned.push(Op::Skip(Rd::new(SrcDisp::Immediate(Value(skip as i64)))));
} else {
return Err(Error::Asm(AsmError::LabelNotDefined(target)));
}
}
Op::JumpIf(cond, target) => {
HLOp::JumpIf(cond, target) => {
if let Some(dest) = label_positions.get(&target) {
let skip = *dest as isize - n as isize + skipped;
cleaned.push(SkipIf(cond, Rd(SrcDisp::Immediate(Value(skip as i64)), Mask::default())));
cleaned.push(Op::SkipIf(cond, Rd::new(SrcDisp::Immediate(Value(skip as i64)))));
} else {
return Err(Error::Asm(AsmError::LabelNotDefined(target)));
}
}
other => {
cleaned.push(other);
HLOp::L(op) => {
cleaned.push(op);
}
}
}

@ -3,8 +3,9 @@ mod cond;
mod flatten;
pub use flatten::Flatten;
pub use flatten::jumps_to_skips;
pub use flatten::lower;
pub use op::HLOp;
pub use op::Op;
pub use cond::Cond;
use crate::data::literal::{RoutineName};
@ -15,7 +16,7 @@ use crate::data::literal::{RoutineName};
/// A higher-level instruction
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Instr {
pub op: Op,
pub op: HLOp,
pub branches: Option<Vec<(Cond, Vec<Instr>)>>,
}

@ -6,37 +6,37 @@ use crate::data::{
};
use crate::instr::{Cond};
/// A low level instruction
/// A higher level simple opration
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Op {
/* Marker instructions */
pub enum HLOp {
/// Mark a jump target.
/// Is optimized out when jumps are replaced by relative skips
Label(Label),
/// Jump to a label
Jump(Label),
/// Jump to a label if a flag is set
JumpIf(Cond, Label),
/// Low level op
L(Op),
}
/// A low level instruction
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Op {
/// Mark a far jump target (can be jumped to from another routine).
/// This label is preserved in optimized code.
FarLabel(Label),
/* Control flow */
/// Jump to a label
Jump(Label),
/// Jump to a label that can be in another function
FarJump(Label),
/// Call a routine with arguments
/// Call a routine with arguments.
/// The arguments are passed as argX. Return values are stored in resX registers.
Call(RoutineName, Vec<Rd>),
/// Exit the current routine with return values
Ret(Vec<Rd>),
/* Synthetic instructions */
/// Mark a routine entry point (call target)
/// Mark a routine entry point (call target).
/// Kept in the low level instruction file for position-independent code
Routine(RoutineName),
/// Skip backward or forward
Skip(Rd),
/// Jump to a label if a flag is set
JumpIf(Cond, Label),
/// Skip if a flag is set
SkipIf(Cond, Rd),
/// Deny jumps, skips and run across this address, producing a run-time fault with a message.
@ -57,3 +57,10 @@ pub enum Op {
// TODO arithmetics, bit manipulation, byte operations
}
/// Make "into" work
impl From<Op> for HLOp {
fn from(op: Op) -> Self {
HLOp::L(op)
}
}

@ -1,15 +1,21 @@
mod data;
mod error;
mod instr;
mod parse;
mod patches;
pub mod data;
pub mod error;
pub mod instr;
pub mod parse;
pub mod patches;
pub use parse::parse;
use crate::instr::{Op, lower};
/// Parse a program from string and assemble a low level instruction sequence from it.
pub fn assemble(source : &str) -> Result<Vec<Op>, error::Error> {
let parsed = parse::parse(source)?;
Ok(lower(parsed)?)
}
#[cfg(test)]
mod tests {
use crate::parse;
use crate::instr::{Op, Flatten, Instr, jumps_to_skips};
use crate::parse::{parse, parse_instructions};
use crate::instr::{HLOp, Op, Flatten, Instr, lower};
use crate::data::{Wr, DstDisp, Register, SrcDisp, Rd};
use crate::data::literal::{Value, Addr, Label};
use std::sync::atomic::AtomicU32;
@ -20,7 +26,7 @@ mod tests {
let parsed = parse("
()
").unwrap();
assert_eq!(Vec::<Op>::new(), parsed);
assert_eq!(Vec::<HLOp>::new(), parsed);
}
#[test]
@ -31,8 +37,8 @@ mod tests {
)
").unwrap();
assert_eq!(vec![
Op::Routine("hello".into()),
Op::Barrier(Some("Routine \"hello\" overrun".into()))
HLOp::L(Op::Routine("hello".into())),
HLOp::L(Op::Barrier(Some("Routine \"hello\" overrun".into())))
], parsed);
let parsed = parse("
@ -42,10 +48,10 @@ mod tests {
)
").unwrap();
assert_eq!(vec![
Op::Routine("hello".into()),
Op::Barrier(Some("Routine \"hello\" overrun".into())),
Op::Routine("world".into()),
Op::Barrier(Some("Routine \"world\" overrun".into()))
HLOp::L(Op::Routine("hello".into())),
HLOp::L(Op::Barrier(Some("Routine \"hello\" overrun".into()))),
HLOp::L(Op::Routine("world".into())),
HLOp::L(Op::Barrier(Some("Routine \"world\" overrun".into())))
], parsed);
}
@ -71,81 +77,81 @@ mod tests {
)
").unwrap();
assert_eq!(vec![
Op::Routine("move".into()),
HLOp::L(Op::Routine("move".into())),
// (mov r0 r1)
Op::Mov(
HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(1))),
),
)),
// (mov r15 7)
Op::Mov(
HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(15))),
Rd::new(SrcDisp::Immediate(Value(7))),
),
)),
// (mov r15 0xabcd)
Op::Mov(
HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(15))),
Rd::new(SrcDisp::Immediate(Value(0xabcd))),
),
)),
// (mov r7 0b11110000)
Op::Mov(
HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(7))),
Rd::new(SrcDisp::Immediate(Value(0b11110000))),
),
)),
// (mov r7 arg1)
Op::Mov(
HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(7))),
Rd::new(SrcDisp::Register(Register::Arg(1))),
),
)),
// (mov r255 arg255)
Op::Mov(
HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(255))),
Rd::new(SrcDisp::Register(Register::Arg(255))),
),
)),
// (mov r7 res0)
Op::Mov(
HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(7))),
Rd::new(SrcDisp::Register(Register::Res(0))),
),
)),
// (mov r7 res255)
Op::Mov(
HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(7))),
Rd::new(SrcDisp::Register(Register::Res(255))),
),
)),
// (mov @r0 @r0)
Op::Mov(
HLOp::L(Op::Mov(
Wr::new(DstDisp::RegisterPtr(Register::Gen(0))),
Rd::new(SrcDisp::RegisterPtr(Register::Gen(0))),
),
)),
// (mov @r0 @arg0)
Op::Mov(
HLOp::L(Op::Mov(
Wr::new(DstDisp::RegisterPtr(Register::Gen(0))),
Rd::new(SrcDisp::RegisterPtr(Register::Arg(0))),
),
)),
// (mov @r0 @res0)
Op::Mov(
HLOp::L(Op::Mov(
Wr::new(DstDisp::RegisterPtr(Register::Gen(0))),
Rd::new(SrcDisp::RegisterPtr(Register::Res(0))),
),
)),
// (mov @123456 @0x123456)
Op::Mov(
HLOp::L(Op::Mov(
Wr::new(DstDisp::ImmediatePtr(Addr(123456))),
Rd::new(SrcDisp::ImmediatePtr(Addr(0x123456))),
),
)),
// (mov @0b010101 @0b010101)
Op::Mov(
HLOp::L(Op::Mov(
Wr::new(DstDisp::ImmediatePtr(Addr(0b010101))),
Rd::new(SrcDisp::ImmediatePtr(Addr(0b010101))),
),
Op::Barrier(Some("Routine \"move\" overrun".into())),
)),
HLOp::L(Op::Barrier(Some("Routine \"move\" overrun".into()))),
], parsed);
}
fn parse_single_instr(src : &str) -> anyhow::Result<Instr> {
Ok(parse::parse_instructions(vec![sexp::parse(src)?])?.remove(0))
Ok(parse_instructions(vec![sexp::parse(src)?])?.remove(0))
}
fn parse_single_op(src : &str) -> anyhow::Result<Vec<Op>> {
fn parse_single_op(src : &str) -> anyhow::Result<Vec<HLOp>> {
let num = AtomicU32::new(0);
Ok(parse_single_instr(src)?.flatten(&num)?)
}
@ -154,10 +160,10 @@ mod tests {
fn test_parse_single() {
let parsed = parse_single_op("(mov r0 r1)").unwrap();
assert_eq!(vec![
Op::Mov(
HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(1))),
),
)),
], parsed);
}
@ -168,26 +174,26 @@ mod tests {
").unwrap();
assert_eq!(
Instr {
op: Op::Cmp(
op: HLOp::L(Op::Cmp(
Rd::new(SrcDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(1))),
),
)),
branches: Some(vec![
(
Cond::Equal,
vec![
Instr {
op: Op::Mov(
op: HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(0))),
),
)),
branches: None
},
Instr {
op: Op::Mov(
op: HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(1))),
Rd::new(SrcDisp::Register(Register::Gen(2))),
),
)),
branches: None
}
]
@ -196,17 +202,17 @@ mod tests {
Cond::Greater,
vec![
Instr {
op: Op::Mov(
op: HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(0))),
),
)),
branches: None
},
Instr {
op: Op::Mov(
op: HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(1))),
Rd::new(SrcDisp::Register(Register::Gen(1))),
),
)),
branches: None
}
]
@ -229,31 +235,31 @@ mod tests {
").unwrap();
assert_eq!(
vec![
Op::Cmp(
HLOp::L(Op::Cmp(
Rd::new(SrcDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(1))),
),
Op::JumpIf(Cond::NotEqual, Label::Numbered(1)),
Op::Mov(
)),
HLOp::JumpIf(Cond::NotEqual, Label::Numbered(1)),
HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(0))),
),
Op::Mov(
)),
HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(1))),
Rd::new(SrcDisp::Register(Register::Gen(2))),
),
Op::Jump(Label::Numbered(0)),
Op::Label(Label::Numbered(1)),
Op::JumpIf(Cond::LessOrEqual, Label::Numbered(0)),
Op::Mov(
)),
HLOp::Jump(Label::Numbered(0)),
HLOp::Label(Label::Numbered(1)),
HLOp::JumpIf(Cond::LessOrEqual, Label::Numbered(0)),
HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(0))),
),
Op::Mov(
)),
HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(1))),
Rd::new(SrcDisp::Register(Register::Gen(1))),
),
Op::Label(Label::Numbered(0)),
)),
HLOp::Label(Label::Numbered(0)),
], parsed);
}
@ -277,32 +283,32 @@ mod tests {
assert_eq!(
vec![
Op::Routine("foo".into()),
Op::Label(Label::Named("foo".to_string())),
Op::Label(Label::Named("unused".to_string())),
Op::Label(Label::Named("whatever".to_string())),
Op::Routine("foo".into()).into(),
HLOp::Label(Label::Named("foo".to_string())),
HLOp::Label(Label::Named("unused".to_string())),
HLOp::Label(Label::Named("whatever".to_string())),
Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(0))),
),
Op::Jump(Label::Named("foo".to_string())),
Op::Jump(Label::Named("foo".to_string())),
).into(),
HLOp::Jump(Label::Named("foo".to_string())),
HLOp::Jump(Label::Named("foo".to_string())),
Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(0))),
),
).into(),
Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(0))),
),
Op::Jump(Label::Named("whatever".to_string())),
Op::JumpIf(Cond::Equal, Label::Named("whatever".to_string())),
Op::Barrier(Some("Routine \"foo\" overrun".into())),
).into(),
HLOp::Jump(Label::Named("whatever".to_string())),
HLOp::JumpIf(Cond::Equal, Label::Named("whatever".to_string())),
Op::Barrier(Some("Routine \"foo\" overrun".into())).into(),
], parsed);
// Labels are removed and jumps become skips
let cleaned = jumps_to_skips(parsed).unwrap();
let cleaned = lower(parsed).unwrap();
assert_eq!(
vec![

@ -1,5 +1,5 @@
use crate::instr::{Routine, Op, Flatten};
use crate::instr::{Routine, HLOp, Flatten};
use crate::error::Error;
@ -16,7 +16,7 @@ mod parse_op;
use parse_routines::parse_routines;
pub use parse_instr::parse_instructions;
pub fn parse(source: &str) -> Result<Vec<Op>, Error> {
pub fn parse(source: &str) -> Result<Vec<HLOp>, Error> {
let root = sexp::parse(source)?;
let subs: Vec<Routine> = parse_routines(expect_list(Some(root), true)?)?;

@ -1,10 +1,11 @@
use sexp::{Sexp, Atom};
use crate::data::{DataDisp, Register, Rd, Mask, Wr, DstDisp, SrcDisp};
use crate::data::{DataDisp, Rd, Wr, DstDisp, SrcDisp, reg};
use crate::error::Error;
use crate::data::literal::{Value, Addr, Label};
use std::convert::TryFrom;
use crate::parse::sexp_expect::expect_string_atom;
/// Parse a label
pub fn parse_label(name : Option<Sexp>) -> Result<Label, Error> {
let name = expect_string_atom(name)?;
Ok(Label::Named(name.trim_start_matches(':').into()))
@ -30,12 +31,12 @@ pub fn parse_data_disp(tok: Option<Sexp>) -> Result<DataDisp, Error> {
let val : u64 = parse_u64(reference)?;
Ok(DataDisp::ImmediatePtr(Addr(val)))
} else {
Ok(DataDisp::RegisterPtr(parse_reg(reference)?))
Ok(DataDisp::RegisterPtr(reg::parse_reg(reference)?))
}
} else if s.starts_with(|c : char| c.is_ascii_digit()) {
Ok(DataDisp::Immediate(Value(parse_i64(s)?)))
} else {
Ok(DataDisp::Register(parse_reg(s)?))
Ok(DataDisp::Register(reg::parse_reg(s)?))
}
},
_ => {
@ -44,21 +45,6 @@ pub fn parse_data_disp(tok: Option<Sexp>) -> Result<DataDisp, Error> {
}
}
pub fn parse_reg(name : &str) -> anyhow::Result<Register> {
if let Some(rn) = name.strip_prefix("arg") {
let val : u8 = rn.parse()?;
Ok(Register::Arg(val))
} else if let Some(rn) = name.strip_prefix("res") {
let val : u8 = rn.parse()?;
Ok(Register::Res(val))
} else if let Some(rn) = name.strip_prefix("r") {
let val : u8 = rn.parse()?;
Ok(Register::Gen(val))
} else {
Err(Error::Parse(format!("Bad reg name: {}", name).into()))?
}
}
pub fn parse_u64(literal : &str) -> anyhow::Result<u64> {
if let Some(hex) = literal.strip_prefix("0x") {
Ok(u64::from_str_radix(hex, 16)?)
@ -78,9 +64,9 @@ pub fn parse_i64(literal : &str) -> anyhow::Result<i64> {
}
pub fn parse_rd(tok: Option<Sexp>) -> anyhow::Result<Rd> {
Ok(Rd(SrcDisp::try_from(parse_data_disp(tok)?)?, Mask::default()))
Ok(Rd::new(SrcDisp::try_from(parse_data_disp(tok)?)?))
}
pub fn parse_wr(tok: Option<Sexp>) -> anyhow::Result<Wr> {
Ok(Wr(DstDisp::try_from(parse_data_disp(tok)?)?, Mask::default()))
Ok(Wr::new(DstDisp::try_from(parse_data_disp(tok)?)?))
}

@ -1,4 +1,4 @@
use crate::instr::Op;
use crate::instr::{HLOp, Op};
use sexp::Sexp;
use crate::error::Error;
use crate::data::literal::{RoutineName, Label};
@ -6,14 +6,14 @@ 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;
pub fn parse_op(keyword: &str, far : bool, mut arg_tokens: impl Iterator<Item=Sexp>) -> Result<Op, Error> {
pub fn parse_op(keyword: &str, far : bool, mut arg_tokens: impl Iterator<Item=Sexp>) -> Result<HLOp, Error> {
Ok(match keyword {
"jmp" | "j" => {
"j" => {
let dest = parse_label(arg_tokens.next())?;
if far {
Op::FarJump(dest)
HLOp::L(Op::FarJump(dest))
} else {
Op::Jump(dest)
HLOp::Jump(dest)
}
}
@ -24,7 +24,7 @@ pub fn parse_op(keyword: &str, far : bool, mut arg_tokens: impl Iterator<Item=Se
for t in arg_tokens {
args.push(parse_rd(Some(t))?);
}
Op::Call(dest, args)
HLOp::L(Op::Call(dest, args))
}
"ret" => {
@ -32,71 +32,79 @@ pub fn parse_op(keyword: &str, far : bool, mut arg_tokens: impl Iterator<Item=Se
for t in arg_tokens {
args.push(parse_rd(Some(t))?);
}
Op::Ret(args)
HLOp::L(Op::Ret(args))
}
"rtn" | "fn" => {
"routine" => {
let dest = RoutineName(expect_string_atom(arg_tokens.next())?);
Op::Routine(dest)
HLOp::L(Op::Routine(dest))
}
"skip" => {
Op::Skip(parse_rd(arg_tokens.next())?)
"sk" => {
HLOp::L(Op::Skip(parse_rd(arg_tokens.next())?))
}
"jmp.if" | "j.if" => {
"csk" => {
let cond = parse_cond(&expect_string_atom(arg_tokens.next())?)?;
let offs = parse_rd(arg_tokens.next())?;
HLOp::L(Op::SkipIf(cond, offs))
}
"cj" => {
let cond = parse_cond(&expect_string_atom(arg_tokens.next())?)?;
let dest = parse_label(arg_tokens.next())?;
Op::JumpIf(cond, dest)
HLOp::JumpIf(cond, dest)
}
"barrier" => {
Op::Barrier(match arg_tokens.next() {
HLOp::L(Op::Barrier(match arg_tokens.next() {
None => None,
Some(s) => Some(expect_string_atom(Some(s))?.into()),
})
}))
}
"fault" => {
Op::Fault(match arg_tokens.next() {
HLOp::L(Op::Fault(match arg_tokens.next() {
None => None,
Some(s) => Some(expect_string_atom(Some(s))?.into()),
})
}))
}
"mov" | "ld" | "mv" => {
Op::Mov(
"ld" => {
HLOp::L(Op::Mov(
parse_wr(arg_tokens.next())?,
parse_rd(arg_tokens.next())?
)
))
}
"cmp" => {
Op::Cmp(
HLOp::L(Op::Cmp(
parse_rd(arg_tokens.next())?,
parse_rd(arg_tokens.next())?
)
))
}
"inc" => {
Op::Inc(
HLOp::L(Op::Inc(
parse_wr(arg_tokens.next())?
)
))
}
"dec" => {
Op::Dec(
HLOp::L(Op::Dec(
parse_wr(arg_tokens.next())?
)
))
}
// TODO more instructions
other => {
if let Some(label) = other.strip_prefix(':') {
let label = Label::Named(label.to_string());
if far {
Op::FarLabel(label)
HLOp::L(Op::FarLabel(label))
} else {
Op::Label(label)
HLOp::Label(label)
}
} else {
return Err(Error::Parse(format!("Unknown instruction: {}", other).into()));

Loading…
Cancel
Save