|
|
|
@ -1,5 +1,5 @@ |
|
|
|
|
use crate::asm::instr::{lower, Op}; |
|
|
|
|
use crate::asm::instr::op::OpParser; |
|
|
|
|
use crate::asm::instr::op::AsmModule; |
|
|
|
|
|
|
|
|
|
pub mod data; |
|
|
|
|
pub mod error; |
|
|
|
@ -8,7 +8,7 @@ pub mod parse; |
|
|
|
|
pub mod patches; |
|
|
|
|
|
|
|
|
|
/// Parse a program from string and assemble a low level instruction sequence from it.
|
|
|
|
|
pub fn assemble(source: &str, parsers: &[Box<dyn OpParser>]) -> Result<Vec<Op>, error::Error> { |
|
|
|
|
pub fn assemble(source: &str, parsers: &[Box<dyn AsmModule>]) -> Result<Vec<Op>, error::Error> { |
|
|
|
|
let parsed = parse::parse(source, parsers)?; |
|
|
|
|
Ok(lower(parsed)?) |
|
|
|
|
} |
|
|
|
@ -19,7 +19,7 @@ mod tests { |
|
|
|
|
|
|
|
|
|
use crate::asm::data::{DstDisp, Rd, Register, SrcDisp, Wr}; |
|
|
|
|
use crate::asm::data::literal::{Addr, Label}; |
|
|
|
|
use crate::asm::instr::{Flatten, HLOp, Instr, lower, Op}; |
|
|
|
|
use crate::asm::instr::{Flatten, OpWrapper, Instr, lower, Op}; |
|
|
|
|
use crate::asm::instr::Cond; |
|
|
|
|
use crate::asm::parse::{parse, parse_instructions}; |
|
|
|
|
|
|
|
|
@ -28,7 +28,7 @@ mod tests { |
|
|
|
|
let parsed = parse(" |
|
|
|
|
() |
|
|
|
|
").unwrap(); |
|
|
|
|
assert_eq!(Vec::<HLOp>::new(), parsed); |
|
|
|
|
assert_eq!(Vec::<OpWrapper>::new(), parsed); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
@ -39,8 +39,8 @@ mod tests { |
|
|
|
|
) |
|
|
|
|
").unwrap(); |
|
|
|
|
assert_eq!(vec![ |
|
|
|
|
HLOp::L(Op::Routine("hello".into())), |
|
|
|
|
HLOp::L(Op::Barrier(Some("Routine \"hello\" overrun".into()))) |
|
|
|
|
OpWrapper::Op(Op::Routine("hello".into())), |
|
|
|
|
OpWrapper::Op(Op::Barrier(Some("Routine \"hello\" overrun".into()))) |
|
|
|
|
], parsed); |
|
|
|
|
|
|
|
|
|
let parsed = parse(" |
|
|
|
@ -50,10 +50,10 @@ mod tests { |
|
|
|
|
) |
|
|
|
|
").unwrap(); |
|
|
|
|
assert_eq!(vec![ |
|
|
|
|
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()))) |
|
|
|
|
OpWrapper::Op(Op::Routine("hello".into())), |
|
|
|
|
OpWrapper::Op(Op::Barrier(Some("Routine \"hello\" overrun".into()))), |
|
|
|
|
OpWrapper::Op(Op::Routine("world".into())), |
|
|
|
|
OpWrapper::Op(Op::Barrier(Some("Routine \"world\" overrun".into()))) |
|
|
|
|
], parsed); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -79,73 +79,73 @@ mod tests { |
|
|
|
|
) |
|
|
|
|
").unwrap(); |
|
|
|
|
assert_eq!(vec![ |
|
|
|
|
HLOp::L(Op::Routine("move".into())), |
|
|
|
|
OpWrapper::Op(Op::Routine("move".into())), |
|
|
|
|
// (mov r0 r1)
|
|
|
|
|
HLOp::L(Op::Mov( |
|
|
|
|
OpWrapper::Op(Op::Mov( |
|
|
|
|
Wr::new(DstDisp::Register(Register::Gen(0))), |
|
|
|
|
Rd::new(SrcDisp::Register(Register::Gen(1))), |
|
|
|
|
)), |
|
|
|
|
// (mov r15 7)
|
|
|
|
|
HLOp::L(Op::Mov( |
|
|
|
|
OpWrapper::Op(Op::Mov( |
|
|
|
|
Wr::new(DstDisp::Register(Register::Gen(15))), |
|
|
|
|
Rd::new(SrcDisp::Immediate(7)), |
|
|
|
|
)), |
|
|
|
|
// (mov r15 0xabcd)
|
|
|
|
|
HLOp::L(Op::Mov( |
|
|
|
|
OpWrapper::Op(Op::Mov( |
|
|
|
|
Wr::new(DstDisp::Register(Register::Gen(15))), |
|
|
|
|
Rd::new(SrcDisp::Immediate(0xabcd)), |
|
|
|
|
)), |
|
|
|
|
// (mov r7 0b11110000)
|
|
|
|
|
HLOp::L(Op::Mov( |
|
|
|
|
OpWrapper::Op(Op::Mov( |
|
|
|
|
Wr::new(DstDisp::Register(Register::Gen(7))), |
|
|
|
|
Rd::new(SrcDisp::Immediate(0b11110000)), |
|
|
|
|
)), |
|
|
|
|
// (mov r7 arg1)
|
|
|
|
|
HLOp::L(Op::Mov( |
|
|
|
|
OpWrapper::Op(Op::Mov( |
|
|
|
|
Wr::new(DstDisp::Register(Register::Gen(7))), |
|
|
|
|
Rd::new(SrcDisp::Register(Register::Arg(1))), |
|
|
|
|
)), |
|
|
|
|
// (mov r255 arg255)
|
|
|
|
|
HLOp::L(Op::Mov( |
|
|
|
|
OpWrapper::Op(Op::Mov( |
|
|
|
|
Wr::new(DstDisp::Register(Register::Gen(255))), |
|
|
|
|
Rd::new(SrcDisp::Register(Register::Arg(255))), |
|
|
|
|
)), |
|
|
|
|
// (mov r7 res0)
|
|
|
|
|
HLOp::L(Op::Mov( |
|
|
|
|
OpWrapper::Op(Op::Mov( |
|
|
|
|
Wr::new(DstDisp::Register(Register::Gen(7))), |
|
|
|
|
Rd::new(SrcDisp::Register(Register::Res(0))), |
|
|
|
|
)), |
|
|
|
|
// (mov r7 res255)
|
|
|
|
|
HLOp::L(Op::Mov( |
|
|
|
|
OpWrapper::Op(Op::Mov( |
|
|
|
|
Wr::new(DstDisp::Register(Register::Gen(7))), |
|
|
|
|
Rd::new(SrcDisp::Register(Register::Res(255))), |
|
|
|
|
)), |
|
|
|
|
// (mov @r0 @r0)
|
|
|
|
|
HLOp::L(Op::Mov( |
|
|
|
|
OpWrapper::Op(Op::Mov( |
|
|
|
|
Wr::new(DstDisp::RegisterPtr(Register::Gen(0))), |
|
|
|
|
Rd::new(SrcDisp::RegisterPtr(Register::Gen(0))), |
|
|
|
|
)), |
|
|
|
|
// (mov @r0 @arg0)
|
|
|
|
|
HLOp::L(Op::Mov( |
|
|
|
|
OpWrapper::Op(Op::Mov( |
|
|
|
|
Wr::new(DstDisp::RegisterPtr(Register::Gen(0))), |
|
|
|
|
Rd::new(SrcDisp::RegisterPtr(Register::Arg(0))), |
|
|
|
|
)), |
|
|
|
|
// (mov @r0 @res0)
|
|
|
|
|
HLOp::L(Op::Mov( |
|
|
|
|
OpWrapper::Op(Op::Mov( |
|
|
|
|
Wr::new(DstDisp::RegisterPtr(Register::Gen(0))), |
|
|
|
|
Rd::new(SrcDisp::RegisterPtr(Register::Res(0))), |
|
|
|
|
)), |
|
|
|
|
// (mov @123456 @0x123456)
|
|
|
|
|
HLOp::L(Op::Mov( |
|
|
|
|
OpWrapper::Op(Op::Mov( |
|
|
|
|
Wr::new(DstDisp::ImmediatePtr(Addr(123456))), |
|
|
|
|
Rd::new(SrcDisp::ImmediatePtr(Addr(0x123456))), |
|
|
|
|
)), |
|
|
|
|
// (mov @0b010101 @0b010101)
|
|
|
|
|
HLOp::L(Op::Mov( |
|
|
|
|
OpWrapper::Op(Op::Mov( |
|
|
|
|
Wr::new(DstDisp::ImmediatePtr(Addr(0b010101))), |
|
|
|
|
Rd::new(SrcDisp::ImmediatePtr(Addr(0b010101))), |
|
|
|
|
)), |
|
|
|
|
HLOp::L(Op::Barrier(Some("Routine \"move\" overrun".into()))), |
|
|
|
|
OpWrapper::Op(Op::Barrier(Some("Routine \"move\" overrun".into()))), |
|
|
|
|
], parsed); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -153,7 +153,7 @@ mod tests { |
|
|
|
|
Ok(parse_instructions(vec![sexp::parse(src)?])?.remove(0)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn parse_single_op(src: &str) -> anyhow::Result<Vec<HLOp>> { |
|
|
|
|
fn parse_single_op(src: &str) -> anyhow::Result<Vec<OpWrapper>> { |
|
|
|
|
let num = AtomicU32::new(0); |
|
|
|
|
Ok(parse_single_instr(src)?.flatten(&num)?) |
|
|
|
|
} |
|
|
|
@ -162,7 +162,7 @@ mod tests { |
|
|
|
|
fn test_parse_single() { |
|
|
|
|
let parsed = parse_single_op("(mov r0 r1)").unwrap(); |
|
|
|
|
assert_eq!(vec![ |
|
|
|
|
HLOp::L(Op::Mov( |
|
|
|
|
OpWrapper::Op(Op::Mov( |
|
|
|
|
Wr::new(DstDisp::Register(Register::Gen(0))), |
|
|
|
|
Rd::new(SrcDisp::Register(Register::Gen(1))), |
|
|
|
|
)), |
|
|
|
@ -176,7 +176,7 @@ mod tests { |
|
|
|
|
").unwrap(); |
|
|
|
|
assert_eq!( |
|
|
|
|
Instr { |
|
|
|
|
op: HLOp::L(Op::Cmp( |
|
|
|
|
op: OpWrapper::Op(Op::Cmp( |
|
|
|
|
Rd::new(SrcDisp::Register(Register::Gen(0))), |
|
|
|
|
Rd::new(SrcDisp::Register(Register::Gen(1))), |
|
|
|
|
)), |
|
|
|
@ -185,14 +185,14 @@ mod tests { |
|
|
|
|
Cond::Equal, |
|
|
|
|
vec![ |
|
|
|
|
Instr { |
|
|
|
|
op: HLOp::L(Op::Mov( |
|
|
|
|
op: OpWrapper::Op(Op::Mov( |
|
|
|
|
Wr::new(DstDisp::Register(Register::Gen(0))), |
|
|
|
|
Rd::new(SrcDisp::Register(Register::Gen(0))), |
|
|
|
|
)), |
|
|
|
|
branches: None, |
|
|
|
|
}, |
|
|
|
|
Instr { |
|
|
|
|
op: HLOp::L(Op::Mov( |
|
|
|
|
op: OpWrapper::Op(Op::Mov( |
|
|
|
|
Wr::new(DstDisp::Register(Register::Gen(1))), |
|
|
|
|
Rd::new(SrcDisp::Register(Register::Gen(2))), |
|
|
|
|
)), |
|
|
|
@ -204,14 +204,14 @@ mod tests { |
|
|
|
|
Cond::Greater, |
|
|
|
|
vec![ |
|
|
|
|
Instr { |
|
|
|
|
op: HLOp::L(Op::Mov( |
|
|
|
|
op: OpWrapper::Op(Op::Mov( |
|
|
|
|
Wr::new(DstDisp::Register(Register::Gen(0))), |
|
|
|
|
Rd::new(SrcDisp::Register(Register::Gen(0))), |
|
|
|
|
)), |
|
|
|
|
branches: None, |
|
|
|
|
}, |
|
|
|
|
Instr { |
|
|
|
|
op: HLOp::L(Op::Mov( |
|
|
|
|
op: OpWrapper::Op(Op::Mov( |
|
|
|
|
Wr::new(DstDisp::Register(Register::Gen(1))), |
|
|
|
|
Rd::new(SrcDisp::Register(Register::Gen(1))), |
|
|
|
|
)), |
|
|
|
@ -237,31 +237,31 @@ mod tests { |
|
|
|
|
").unwrap(); |
|
|
|
|
assert_eq!( |
|
|
|
|
vec![ |
|
|
|
|
HLOp::L(Op::Cmp( |
|
|
|
|
OpWrapper::Op(Op::Cmp( |
|
|
|
|
Rd::new(SrcDisp::Register(Register::Gen(0))), |
|
|
|
|
Rd::new(SrcDisp::Register(Register::Gen(1))), |
|
|
|
|
)), |
|
|
|
|
HLOp::JumpIf(Cond::NotEqual, Label::Numbered(1)), |
|
|
|
|
HLOp::L(Op::Mov( |
|
|
|
|
OpWrapper::JumpIf(Cond::NotEqual, Label::Numbered(1)), |
|
|
|
|
OpWrapper::Op(Op::Mov( |
|
|
|
|
Wr::new(DstDisp::Register(Register::Gen(0))), |
|
|
|
|
Rd::new(SrcDisp::Register(Register::Gen(0))), |
|
|
|
|
)), |
|
|
|
|
HLOp::L(Op::Mov( |
|
|
|
|
OpWrapper::Op(Op::Mov( |
|
|
|
|
Wr::new(DstDisp::Register(Register::Gen(1))), |
|
|
|
|
Rd::new(SrcDisp::Register(Register::Gen(2))), |
|
|
|
|
)), |
|
|
|
|
HLOp::Jump(Label::Numbered(0)), |
|
|
|
|
HLOp::Label(Label::Numbered(1)), |
|
|
|
|
HLOp::JumpIf(Cond::LowerOrEqual, Label::Numbered(0)), |
|
|
|
|
HLOp::L(Op::Mov( |
|
|
|
|
OpWrapper::Jump(Label::Numbered(0)), |
|
|
|
|
OpWrapper::Label(Label::Numbered(1)), |
|
|
|
|
OpWrapper::JumpIf(Cond::LowerOrEqual, Label::Numbered(0)), |
|
|
|
|
OpWrapper::Op(Op::Mov( |
|
|
|
|
Wr::new(DstDisp::Register(Register::Gen(0))), |
|
|
|
|
Rd::new(SrcDisp::Register(Register::Gen(0))), |
|
|
|
|
)), |
|
|
|
|
HLOp::L(Op::Mov( |
|
|
|
|
OpWrapper::Op(Op::Mov( |
|
|
|
|
Wr::new(DstDisp::Register(Register::Gen(1))), |
|
|
|
|
Rd::new(SrcDisp::Register(Register::Gen(1))), |
|
|
|
|
)), |
|
|
|
|
HLOp::Label(Label::Numbered(0)), |
|
|
|
|
OpWrapper::Label(Label::Numbered(0)), |
|
|
|
|
], parsed); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -286,15 +286,15 @@ mod tests { |
|
|
|
|
assert_eq!( |
|
|
|
|
vec![ |
|
|
|
|
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())), |
|
|
|
|
OpWrapper::Label(Label::Named("foo".to_string())), |
|
|
|
|
OpWrapper::Label(Label::Named("unused".to_string())), |
|
|
|
|
OpWrapper::Label(Label::Named("whatever".to_string())), |
|
|
|
|
Op::Mov( |
|
|
|
|
Wr::new(DstDisp::Register(Register::Gen(0))), |
|
|
|
|
Rd::new(SrcDisp::Register(Register::Gen(0))), |
|
|
|
|
).into(), |
|
|
|
|
HLOp::Jump(Label::Named("foo".to_string())), |
|
|
|
|
HLOp::Jump(Label::Named("foo".to_string())), |
|
|
|
|
OpWrapper::Jump(Label::Named("foo".to_string())), |
|
|
|
|
OpWrapper::Jump(Label::Named("foo".to_string())), |
|
|
|
|
Op::Mov( |
|
|
|
|
Wr::new(DstDisp::Register(Register::Gen(0))), |
|
|
|
|
Rd::new(SrcDisp::Register(Register::Gen(0))), |
|
|
|
@ -303,8 +303,8 @@ mod tests { |
|
|
|
|
Wr::new(DstDisp::Register(Register::Gen(0))), |
|
|
|
|
Rd::new(SrcDisp::Register(Register::Gen(0))), |
|
|
|
|
).into(), |
|
|
|
|
HLOp::Jump(Label::Named("whatever".to_string())), |
|
|
|
|
HLOp::JumpIf(Cond::Equal, Label::Named("whatever".to_string())), |
|
|
|
|
OpWrapper::Jump(Label::Named("whatever".to_string())), |
|
|
|
|
OpWrapper::JumpIf(Cond::Equal, Label::Named("whatever".to_string())), |
|
|
|
|
Op::Barrier(Some("Routine \"foo\" overrun".into())).into(), |
|
|
|
|
], parsed); |
|
|
|
|
|
|
|
|
|