diff options
feat(assembler): Add support for two pass collapse instructions and implement subroutine instructions
1 files changed, 42 insertions, 7 deletions
| -rw-r--r-- | assembler/src/parser/instruction.rs | 49 |
diff --git a/assembler/src/parser/instruction.rs b/assembler/src/parser/instruction.rs index 5e19b7e..3ccd309 100644 --- a/assembler/src/parser/instruction.rs +++ b/assembler/src/parser/instruction.rs @@ -1,8 +1,9 @@ -use super::{ Instruction, Address }; +use super::{ Instruction, Address, Word }; static Z: Address = Address::Memory(0); static E: Address = Address::Memory(1); static N: Address = Address::Memory(2); +static STACK_POINTER: Address = Address::Memory(4); #[derive(Debug)] pub(crate) enum ArgumentError { @@ -15,14 +16,21 @@ pub(crate) enum ArgumentError { } impl Instruction { + fn new1(name: &str, a: &Address) -> Instruction { + Instruction { name: name.to_string(), args: vec![a.clone()] } + } + fn new2(name: &str, a: &Address, b: &Address) -> Instruction { + Instruction { name: name.to_string(), args: vec![a.clone(), b.clone()] } + } + fn new3(name: &str, a: &Address, b: &Address, c: &Address) -> Instruction { + Instruction { name: name.to_string(), args: vec![a.clone(), b.clone(), c.clone()] } + } + fn new_subleq(a: &Address, b: &Address, c: &Address) -> Instruction { if let Address::Constants(_) = c { panic!("Constants cannot be the third subleq argument!"); } - Instruction { - name: "subleq".to_string(), - args: vec![a.clone(), b.clone(), c.clone()], - } + Self::new3("subleq", a, b, c) } fn check_args_len(&self, expected: usize) -> Result<(), ArgumentError> { @@ -46,7 +54,7 @@ impl Instruction { } } }, - "jmp" => { + "jmp" | "jsr" => { self.check_args_len(1)?; if ! self.args[0].is_location() { @@ -69,6 +77,9 @@ impl Instruction { return Err(ArgumentError::NotLocation); } }, + "rts" => { + self.check_args_len(0)?; + }, _ => return Err(ArgumentError::UnknownInstruction), } Ok(()) @@ -78,6 +89,7 @@ impl Instruction { self.name = self.name.to_lowercase(); match &*self.name { + /* Primitive instrutions (need only one collapse) */ "subleq" => vec![self.clone()], "jmp" => vec![ Instruction::new_subleq(&Z, &Z, &self.args[0]), @@ -105,6 +117,29 @@ impl Instruction { Instruction::new_subleq(&Z, &Z, &Address::Instruction(next + 3)), Instruction::new_subleq(&Z, &self.args[0], &self.args[1] ), ], + + /* Composite instructions (require two collapses) */ + "jsr" => { + vec![ + Instruction::new1("inc", &STACK_POINTER), + + // We're modifying the generated mov instruction + // Every &self.args[1] value gets replaced with the value which SP points to + Instruction::new2("mov", &STACK_POINTER, &Address::InstructionOffset(next + 4, 0)), + Instruction::new2("mov", &STACK_POINTER, &Address::InstructionOffset(next + 4, 1)), + Instruction::new2("mov", &STACK_POINTER, &Address::InstructionOffset(next + 4, 7)), + + Instruction::new2("mov", &Address::InstructionConstant(next + 6), &Z), + Instruction::new1("jmp", &self.args[0]), + ] + }, + "rts" => vec![ + Instruction::new2("mov", &STACK_POINTER, &Address::InstructionOffset(next + 1, 3)), + Instruction::new2("mov", &Z, &Address::InstructionOffset(next + 3, 2)), + Instruction::new1("dec", &STACK_POINTER), + Instruction::new1("jmp", &Z), + ], + _ => panic!("Unknown instruction {}!", self.name), } } @@ -115,7 +150,7 @@ impl Instruction { => 1, "add" => 3, - "mov" | "beq" + "mov" | "beq" | "jsr" | "rts" => 4, _ => panic!("Unknown instruction {}!", self.name), } |
