Website Summary Files Commits Branches @commit @diff @stats
path: root / assembler / src / parser / instruction.rs
diff options
context:
space:
mode:
Commit4b5ed8fb063f08ce399371e48c59665e59ceea47 (patch)
Author
 Syndamia <kamen@syndamia.com>
2025-02-15 00:19:03 +0200
Committer
 Syndamia <kamen@syndamia.com>
2025-02-15 00:19:03 +0200
Fileseddf26834aeb1549fbe468f2d0f95484c544073c /assembler/src/parser/instruction.rs
tonkobali-4b5ed8fb063f08ce399371e48c59665e59ceea47.tar
tonkobali-4b5ed8fb063f08ce399371e48c59665e59ceea47.tar.gz
tonkobali-4b5ed8fb063f08ce399371e48c59665e59ceea47.zip
Parente683120089bd669019a240c7eb5d615fa92df075 (diff)
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.rs49
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),
}