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

@ -1,4 +1,5 @@
use std::fmt::{self, Display, Formatter}; use std::fmt::{self, Display, Formatter};
use crate::error::Error;
/// Register name /// Register name
#[derive(Debug, Clone, Copy, Eq, PartialEq)] #[derive(Debug, Clone, Copy, Eq, PartialEq)]
@ -8,7 +9,7 @@ pub enum Register {
/// Result register, read-only /// Result register, read-only
Res(u8), Res(u8),
/// General purpose register /// General purpose register
Gen(u8) Gen(u8),
} }
impl Display for Register { 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), ConditionalAlreadyUsed(Cond),
#[error("Label \"{0:?}\" not defined")] #[error("Label \"{0:?}\" not defined")]
LabelNotDefined(Label), LabelNotDefined(Label),
#[error("Bad register type: {0}")]
BadRegisterType(Register),
} }
/// Architectural error - the code is syntactically OK, but cannot run /// Architectural error - the code is syntactically OK, but cannot run

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

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

@ -6,37 +6,37 @@ use crate::data::{
}; };
use crate::instr::{Cond}; use crate::instr::{Cond};
/// A low level instruction /// A higher level simple opration
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub enum Op { pub enum HLOp {
/* Marker instructions */
/// Mark a jump target. /// Mark a jump target.
/// Is optimized out when jumps are replaced by relative skips
Label(Label), 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). /// Mark a far jump target (can be jumped to from another routine).
/// This label is preserved in optimized code. /// This label is preserved in optimized code.
FarLabel(Label), FarLabel(Label),
/* Control flow */
/// Jump to a label
Jump(Label),
/// Jump to a label that can be in another function /// Jump to a label that can be in another function
FarJump(Label), 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>), Call(RoutineName, Vec<Rd>),
/// Exit the current routine with return values /// Exit the current routine with return values
Ret(Vec<Rd>), Ret(Vec<Rd>),
/// Mark a routine entry point (call target).
/* Synthetic instructions */ /// Kept in the low level instruction file for position-independent code
/// Mark a routine entry point (call target)
Routine(RoutineName), Routine(RoutineName),
/// Skip backward or forward /// Skip backward or forward
Skip(Rd), Skip(Rd),
/// Jump to a label if a flag is set
JumpIf(Cond, Label),
/// Skip if a flag is set /// Skip if a flag is set
SkipIf(Cond, Rd), SkipIf(Cond, Rd),
/// Deny jumps, skips and run across this address, producing a run-time fault with a message. /// 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 // 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; pub mod data;
mod error; pub mod error;
mod instr; pub mod instr;
mod parse; pub mod parse;
mod patches; 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)] #[cfg(test)]
mod tests { mod tests {
use crate::parse; use crate::parse::{parse, parse_instructions};
use crate::instr::{Op, Flatten, Instr, jumps_to_skips}; use crate::instr::{HLOp, Op, Flatten, Instr, lower};
use crate::data::{Wr, DstDisp, Register, SrcDisp, Rd}; use crate::data::{Wr, DstDisp, Register, SrcDisp, Rd};
use crate::data::literal::{Value, Addr, Label}; use crate::data::literal::{Value, Addr, Label};
use std::sync::atomic::AtomicU32; use std::sync::atomic::AtomicU32;
@ -20,7 +26,7 @@ mod tests {
let parsed = parse(" let parsed = parse("
() ()
").unwrap(); ").unwrap();
assert_eq!(Vec::<Op>::new(), parsed); assert_eq!(Vec::<HLOp>::new(), parsed);
} }
#[test] #[test]
@ -31,8 +37,8 @@ mod tests {
) )
").unwrap(); ").unwrap();
assert_eq!(vec![ assert_eq!(vec![
Op::Routine("hello".into()), HLOp::L(Op::Routine("hello".into())),
Op::Barrier(Some("Routine \"hello\" overrun".into())) HLOp::L(Op::Barrier(Some("Routine \"hello\" overrun".into())))
], parsed); ], parsed);
let parsed = parse(" let parsed = parse("
@ -42,10 +48,10 @@ mod tests {
) )
").unwrap(); ").unwrap();
assert_eq!(vec![ assert_eq!(vec![
Op::Routine("hello".into()), HLOp::L(Op::Routine("hello".into())),
Op::Barrier(Some("Routine \"hello\" overrun".into())), HLOp::L(Op::Barrier(Some("Routine \"hello\" overrun".into()))),
Op::Routine("world".into()), HLOp::L(Op::Routine("world".into())),
Op::Barrier(Some("Routine \"world\" overrun".into())) HLOp::L(Op::Barrier(Some("Routine \"world\" overrun".into())))
], parsed); ], parsed);
} }
@ -71,81 +77,81 @@ mod tests {
) )
").unwrap(); ").unwrap();
assert_eq!(vec![ assert_eq!(vec![
Op::Routine("move".into()), HLOp::L(Op::Routine("move".into())),
// (mov r0 r1) // (mov r0 r1)
Op::Mov( HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(0))), Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(1))), Rd::new(SrcDisp::Register(Register::Gen(1))),
), )),
// (mov r15 7) // (mov r15 7)
Op::Mov( HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(15))), Wr::new(DstDisp::Register(Register::Gen(15))),
Rd::new(SrcDisp::Immediate(Value(7))), Rd::new(SrcDisp::Immediate(Value(7))),
), )),
// (mov r15 0xabcd) // (mov r15 0xabcd)
Op::Mov( HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(15))), Wr::new(DstDisp::Register(Register::Gen(15))),
Rd::new(SrcDisp::Immediate(Value(0xabcd))), Rd::new(SrcDisp::Immediate(Value(0xabcd))),
), )),
// (mov r7 0b11110000) // (mov r7 0b11110000)
Op::Mov( HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(7))), Wr::new(DstDisp::Register(Register::Gen(7))),
Rd::new(SrcDisp::Immediate(Value(0b11110000))), Rd::new(SrcDisp::Immediate(Value(0b11110000))),
), )),
// (mov r7 arg1) // (mov r7 arg1)
Op::Mov( HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(7))), Wr::new(DstDisp::Register(Register::Gen(7))),
Rd::new(SrcDisp::Register(Register::Arg(1))), Rd::new(SrcDisp::Register(Register::Arg(1))),
), )),
// (mov r255 arg255) // (mov r255 arg255)
Op::Mov( HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(255))), Wr::new(DstDisp::Register(Register::Gen(255))),
Rd::new(SrcDisp::Register(Register::Arg(255))), Rd::new(SrcDisp::Register(Register::Arg(255))),
), )),
// (mov r7 res0) // (mov r7 res0)
Op::Mov( HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(7))), Wr::new(DstDisp::Register(Register::Gen(7))),
Rd::new(SrcDisp::Register(Register::Res(0))), Rd::new(SrcDisp::Register(Register::Res(0))),
), )),
// (mov r7 res255) // (mov r7 res255)
Op::Mov( HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(7))), Wr::new(DstDisp::Register(Register::Gen(7))),
Rd::new(SrcDisp::Register(Register::Res(255))), Rd::new(SrcDisp::Register(Register::Res(255))),
), )),
// (mov @r0 @r0) // (mov @r0 @r0)
Op::Mov( HLOp::L(Op::Mov(
Wr::new(DstDisp::RegisterPtr(Register::Gen(0))), Wr::new(DstDisp::RegisterPtr(Register::Gen(0))),
Rd::new(SrcDisp::RegisterPtr(Register::Gen(0))), Rd::new(SrcDisp::RegisterPtr(Register::Gen(0))),
), )),
// (mov @r0 @arg0) // (mov @r0 @arg0)
Op::Mov( HLOp::L(Op::Mov(
Wr::new(DstDisp::RegisterPtr(Register::Gen(0))), Wr::new(DstDisp::RegisterPtr(Register::Gen(0))),
Rd::new(SrcDisp::RegisterPtr(Register::Arg(0))), Rd::new(SrcDisp::RegisterPtr(Register::Arg(0))),
), )),
// (mov @r0 @res0) // (mov @r0 @res0)
Op::Mov( HLOp::L(Op::Mov(
Wr::new(DstDisp::RegisterPtr(Register::Gen(0))), Wr::new(DstDisp::RegisterPtr(Register::Gen(0))),
Rd::new(SrcDisp::RegisterPtr(Register::Res(0))), Rd::new(SrcDisp::RegisterPtr(Register::Res(0))),
), )),
// (mov @123456 @0x123456) // (mov @123456 @0x123456)
Op::Mov( HLOp::L(Op::Mov(
Wr::new(DstDisp::ImmediatePtr(Addr(123456))), Wr::new(DstDisp::ImmediatePtr(Addr(123456))),
Rd::new(SrcDisp::ImmediatePtr(Addr(0x123456))), Rd::new(SrcDisp::ImmediatePtr(Addr(0x123456))),
), )),
// (mov @0b010101 @0b010101) // (mov @0b010101 @0b010101)
Op::Mov( HLOp::L(Op::Mov(
Wr::new(DstDisp::ImmediatePtr(Addr(0b010101))), Wr::new(DstDisp::ImmediatePtr(Addr(0b010101))),
Rd::new(SrcDisp::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); ], parsed);
} }
fn parse_single_instr(src : &str) -> anyhow::Result<Instr> { 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); let num = AtomicU32::new(0);
Ok(parse_single_instr(src)?.flatten(&num)?) Ok(parse_single_instr(src)?.flatten(&num)?)
} }
@ -154,10 +160,10 @@ mod tests {
fn test_parse_single() { fn test_parse_single() {
let parsed = parse_single_op("(mov r0 r1)").unwrap(); let parsed = parse_single_op("(mov r0 r1)").unwrap();
assert_eq!(vec![ assert_eq!(vec![
Op::Mov( HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(0))), Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(1))), Rd::new(SrcDisp::Register(Register::Gen(1))),
), )),
], parsed); ], parsed);
} }
@ -168,26 +174,26 @@ mod tests {
").unwrap(); ").unwrap();
assert_eq!( assert_eq!(
Instr { Instr {
op: Op::Cmp( op: HLOp::L(Op::Cmp(
Rd::new(SrcDisp::Register(Register::Gen(0))), Rd::new(SrcDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(1))), Rd::new(SrcDisp::Register(Register::Gen(1))),
), )),
branches: Some(vec![ branches: Some(vec![
( (
Cond::Equal, Cond::Equal,
vec![ vec![
Instr { Instr {
op: Op::Mov( op: HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(0))), Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(0))), Rd::new(SrcDisp::Register(Register::Gen(0))),
), )),
branches: None branches: None
}, },
Instr { Instr {
op: Op::Mov( op: HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(1))), Wr::new(DstDisp::Register(Register::Gen(1))),
Rd::new(SrcDisp::Register(Register::Gen(2))), Rd::new(SrcDisp::Register(Register::Gen(2))),
), )),
branches: None branches: None
} }
] ]
@ -196,17 +202,17 @@ mod tests {
Cond::Greater, Cond::Greater,
vec![ vec![
Instr { Instr {
op: Op::Mov( op: HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(0))), Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(0))), Rd::new(SrcDisp::Register(Register::Gen(0))),
), )),
branches: None branches: None
}, },
Instr { Instr {
op: Op::Mov( op: HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(1))), Wr::new(DstDisp::Register(Register::Gen(1))),
Rd::new(SrcDisp::Register(Register::Gen(1))), Rd::new(SrcDisp::Register(Register::Gen(1))),
), )),
branches: None branches: None
} }
] ]
@ -229,31 +235,31 @@ mod tests {
").unwrap(); ").unwrap();
assert_eq!( assert_eq!(
vec![ vec![
Op::Cmp( HLOp::L(Op::Cmp(
Rd::new(SrcDisp::Register(Register::Gen(0))), Rd::new(SrcDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(1))), Rd::new(SrcDisp::Register(Register::Gen(1))),
), )),
Op::JumpIf(Cond::NotEqual, Label::Numbered(1)), HLOp::JumpIf(Cond::NotEqual, Label::Numbered(1)),
Op::Mov( HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(0))), Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(0))), Rd::new(SrcDisp::Register(Register::Gen(0))),
), )),
Op::Mov( HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(1))), Wr::new(DstDisp::Register(Register::Gen(1))),
Rd::new(SrcDisp::Register(Register::Gen(2))), Rd::new(SrcDisp::Register(Register::Gen(2))),
), )),
Op::Jump(Label::Numbered(0)), HLOp::Jump(Label::Numbered(0)),
Op::Label(Label::Numbered(1)), HLOp::Label(Label::Numbered(1)),
Op::JumpIf(Cond::LessOrEqual, Label::Numbered(0)), HLOp::JumpIf(Cond::LessOrEqual, Label::Numbered(0)),
Op::Mov( HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(0))), Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(0))), Rd::new(SrcDisp::Register(Register::Gen(0))),
), )),
Op::Mov( HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(1))), Wr::new(DstDisp::Register(Register::Gen(1))),
Rd::new(SrcDisp::Register(Register::Gen(1))), Rd::new(SrcDisp::Register(Register::Gen(1))),
), )),
Op::Label(Label::Numbered(0)), HLOp::Label(Label::Numbered(0)),
], parsed); ], parsed);
} }
@ -277,32 +283,32 @@ mod tests {
assert_eq!( assert_eq!(
vec![ vec![
Op::Routine("foo".into()), Op::Routine("foo".into()).into(),
Op::Label(Label::Named("foo".to_string())), HLOp::Label(Label::Named("foo".to_string())),
Op::Label(Label::Named("unused".to_string())), HLOp::Label(Label::Named("unused".to_string())),
Op::Label(Label::Named("whatever".to_string())), HLOp::Label(Label::Named("whatever".to_string())),
Op::Mov( Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(0))), Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(0))), Rd::new(SrcDisp::Register(Register::Gen(0))),
), ).into(),
Op::Jump(Label::Named("foo".to_string())), HLOp::Jump(Label::Named("foo".to_string())),
Op::Jump(Label::Named("foo".to_string())), HLOp::Jump(Label::Named("foo".to_string())),
Op::Mov( Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(0))), Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(0))), Rd::new(SrcDisp::Register(Register::Gen(0))),
), ).into(),
Op::Mov( Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(0))), Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(0))), Rd::new(SrcDisp::Register(Register::Gen(0))),
), ).into(),
Op::Jump(Label::Named("whatever".to_string())), HLOp::Jump(Label::Named("whatever".to_string())),
Op::JumpIf(Cond::Equal, Label::Named("whatever".to_string())), HLOp::JumpIf(Cond::Equal, Label::Named("whatever".to_string())),
Op::Barrier(Some("Routine \"foo\" overrun".into())), Op::Barrier(Some("Routine \"foo\" overrun".into())).into(),
], parsed); ], parsed);
// Labels are removed and jumps become skips // Labels are removed and jumps become skips
let cleaned = jumps_to_skips(parsed).unwrap(); let cleaned = lower(parsed).unwrap();
assert_eq!( assert_eq!(
vec![ vec![

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

@ -1,10 +1,11 @@
use sexp::{Sexp, Atom}; 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::error::Error;
use crate::data::literal::{Value, Addr, Label}; use crate::data::literal::{Value, 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;
/// Parse a label
pub fn parse_label(name : Option<Sexp>) -> Result<Label, Error> { pub fn parse_label(name : Option<Sexp>) -> Result<Label, Error> {
let name = expect_string_atom(name)?; let name = expect_string_atom(name)?;
Ok(Label::Named(name.trim_start_matches(':').into())) 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)?; let val : u64 = parse_u64(reference)?;
Ok(DataDisp::ImmediatePtr(Addr(val))) Ok(DataDisp::ImmediatePtr(Addr(val)))
} else { } 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()) { } else if s.starts_with(|c : char| c.is_ascii_digit()) {
Ok(DataDisp::Immediate(Value(parse_i64(s)?))) Ok(DataDisp::Immediate(Value(parse_i64(s)?)))
} else { } 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> { pub fn parse_u64(literal : &str) -> anyhow::Result<u64> {
if let Some(hex) = literal.strip_prefix("0x") { if let Some(hex) = literal.strip_prefix("0x") {
Ok(u64::from_str_radix(hex, 16)?) 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> { 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> { 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 sexp::Sexp;
use crate::error::Error; use crate::error::Error;
use crate::data::literal::{RoutineName, Label}; 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_data::{parse_rd, parse_wr, parse_label};
use crate::parse::parse_cond::parse_cond; 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 { Ok(match keyword {
"jmp" | "j" => { "j" => {
let dest = parse_label(arg_tokens.next())?; let dest = parse_label(arg_tokens.next())?;
if far { if far {
Op::FarJump(dest) HLOp::L(Op::FarJump(dest))
} else { } 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 { for t in arg_tokens {
args.push(parse_rd(Some(t))?); args.push(parse_rd(Some(t))?);
} }
Op::Call(dest, args) HLOp::L(Op::Call(dest, args))
} }
"ret" => { "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 { for t in arg_tokens {
args.push(parse_rd(Some(t))?); 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())?); let dest = RoutineName(expect_string_atom(arg_tokens.next())?);
Op::Routine(dest) HLOp::L(Op::Routine(dest))
} }
"skip" => { "sk" => {
Op::Skip(parse_rd(arg_tokens.next())?) 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 cond = parse_cond(&expect_string_atom(arg_tokens.next())?)?;
let dest = parse_label(arg_tokens.next())?; let dest = parse_label(arg_tokens.next())?;
Op::JumpIf(cond, dest) HLOp::JumpIf(cond, dest)
} }
"barrier" => { "barrier" => {
Op::Barrier(match arg_tokens.next() { HLOp::L(Op::Barrier(match arg_tokens.next() {
None => None, None => None,
Some(s) => Some(expect_string_atom(Some(s))?.into()), Some(s) => Some(expect_string_atom(Some(s))?.into()),
}) }))
} }
"fault" => { "fault" => {
Op::Fault(match arg_tokens.next() { HLOp::L(Op::Fault(match arg_tokens.next() {
None => None, None => None,
Some(s) => Some(expect_string_atom(Some(s))?.into()), Some(s) => Some(expect_string_atom(Some(s))?.into()),
}) }))
} }
"mov" | "ld" | "mv" => { "ld" => {
Op::Mov( HLOp::L(Op::Mov(
parse_wr(arg_tokens.next())?, parse_wr(arg_tokens.next())?,
parse_rd(arg_tokens.next())? parse_rd(arg_tokens.next())?
) ))
} }
"cmp" => { "cmp" => {
Op::Cmp( HLOp::L(Op::Cmp(
parse_rd(arg_tokens.next())?, parse_rd(arg_tokens.next())?,
parse_rd(arg_tokens.next())? parse_rd(arg_tokens.next())?
) ))
} }
"inc" => { "inc" => {
Op::Inc( HLOp::L(Op::Inc(
parse_wr(arg_tokens.next())? parse_wr(arg_tokens.next())?
) ))
} }
"dec" => { "dec" => {
Op::Dec( HLOp::L(Op::Dec(
parse_wr(arg_tokens.next())? parse_wr(arg_tokens.next())?
) ))
} }
// 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());
if far { if far {
Op::FarLabel(label) HLOp::L(Op::FarLabel(label))
} else { } else {
Op::Label(label) HLOp::Label(label)
} }
} else { } else {
return Err(Error::Parse(format!("Unknown instruction: {}", other).into())); return Err(Error::Parse(format!("Unknown instruction: {}", other).into()));

Loading…
Cancel
Save