From be398a0177645aa3347a5d7c36b547fc3ef71399 Mon Sep 17 00:00:00 2001 From: jpl Date: Thu, 26 Jan 2023 15:31:00 +0000 Subject: [PATCH] Add interpret_loop --- src/assembler.rs | 27 ++++++- src/compiler.rs | 201 ++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 215 insertions(+), 13 deletions(-) diff --git a/src/assembler.rs b/src/assembler.rs index 340f58a..a890e6c 100644 --- a/src/assembler.rs +++ b/src/assembler.rs @@ -58,7 +58,7 @@ pub enum AsmInstruction { LEA(Register, AsmAddr), /// Trap (system call) TRAP(TrapVector), - FILL(Word), + FILL(AsmAddr), } #[derive(Debug, PartialEq, Eq)] @@ -143,7 +143,7 @@ impl LC3Assembler { self.asm_addr_to_offset(addr)? as Word, )), TRAP(trap) => PseudoInstruction::LC3(Instruction::TRAP(trap)), - FILL(word) => PseudoInstruction::FILL(word), + FILL(addr) => PseudoInstruction::FILL(self.asm_addr_to_offset(addr)? as Word), }; assembled_instructions.push(assembled); @@ -223,10 +223,25 @@ impl LC3Assembler { self.instr(LDI(r, addr)) } + pub fn load_effective_address(&mut self, r: Register, addr: AsmAddr) -> &mut Self { + self.instr(LEA(r, addr)) + } + pub fn neg(&mut self, dest: Register, src: Register) -> &mut Self { self.not(dest, src).add(dest, dest, AddMode::Immediate(1)) } + pub fn sub( + &mut self, + dest: Register, + intermediate: Register, + left: Register, + right: Register, + ) -> &mut Self { + self.neg(intermediate, right) + .add(dest, left, AddMode::Register(intermediate)) + } + // Optimizations fn num_diff_bits(a: Word, b: Word) -> u32 { @@ -256,6 +271,10 @@ impl LC3Assembler { self.instr(STI(src, addr)) } + pub fn jump(&mut self, dest: Register) -> &mut Self { + self.instr(JMP(dest)) + } + pub fn ret(&mut self) -> &mut Self { self.instr(JMP(R7)) } @@ -264,8 +283,8 @@ impl LC3Assembler { self.instr(JSR(mode)) } - pub fn fill(&mut self, w: Word) -> &mut Self { - self.instr(FILL(w)) + pub fn fill(&mut self, addr: AsmAddr) -> &mut Self { + self.instr(FILL(addr)) } pub fn halt(&mut self) -> &mut Self { diff --git a/src/compiler.rs b/src/compiler.rs index 52c85fc..a20cb34 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -18,6 +18,8 @@ pub type SignedWord = i16; pub struct ForthCompiler { asm: LC3Assembler, assembled_instructions: Vec, + /// Link to the previous word + link: Word, } impl ForthCompiler { @@ -25,10 +27,22 @@ impl ForthCompiler { pub const TIB: u16 = 0x4000; pub const TOIN: u16 = 0x4100; + const LATEST: Word = 0x4101; + const STATE: Word = 0x4102; + const HERE: Word = 0x4103; + + pub const SP_ADDR: Word = 0x5000; + pub const RP_ADDR: Word = 0x6000; + + pub const IP: Register = R4; + pub const SP: Register = R5; + pub const RP: Register = R6; + pub fn new() -> Self { Self { asm: LC3Assembler::new(), assembled_instructions: vec![], + link: 0, } } pub fn emit(&self) -> impl Iterator + '_ { @@ -41,7 +55,11 @@ impl ForthCompiler { let cells = vec![ ("tib", Self::TIB), ("toin", Self::TOIN), + ("latest", Self::LATEST), + ("state", Self::STATE), + ("here", Self::HERE), ("space", ' ' as Word), + ("question", '?' as Word), ]; self.asm @@ -49,7 +67,7 @@ impl ForthCompiler { for (label, val) in cells { self.asm.label(label); - self.asm.fill(val); + self.asm.fill(AsmAddr::Word(val)); } self } @@ -63,7 +81,7 @@ impl ForthCompiler { } } - pub fn read_input(&mut self) -> Result<&mut Self> { + pub fn read_input(&mut self) -> &mut Self { self.asm.label("readln"); let tib_addr = self.asm.reference_label("tib"); self.asm.load(R1, tib_addr); @@ -91,10 +109,18 @@ impl ForthCompiler { let token = self.asm.reference_label("token"); self.asm.branch_unconditionally(token); - Ok(self) + self } - fn parse_words(&mut self) -> Result<&mut Self> { + fn define_next(&mut self) -> &mut Self { + self.asm + .label("next") + .load_register(R0, Self::IP, 0) + .add(Self::IP, Self::IP, AddMode::Immediate(1)) + .jump(R0); + self + } + fn parse_words(&mut self) -> &mut Self { let token = self.asm.reference_label("token"); self.asm.subroutine(AsmJsrMode::Addr(token)); self.asm @@ -130,10 +156,12 @@ impl ForthCompiler { .label("findws") .add(R3, R3, AddMode::Immediate(1)) .load_register(R0, R3, 0); + let tokend = self.asm.reference_label("tokend"); self.asm .branch(ConditionCode::ZER as Word, tokend) .add(R0, R0, AddMode::Register(R1)); + let findws = self.asm.reference_label("findws"); self.asm.branch(ConditionCode::ZER as Word, findws); @@ -141,11 +169,58 @@ impl ForthCompiler { let toin = self.asm.reference_label("toin"); self.asm .store_indirect(R3, toin) - .neg(R1, R2) - .add(R3, R3, AddMode::Register(R1)) + // intermediate = R1, right = R2, dest = R3, left = R3 + .sub(R3, R1, R3, R2) .ret(); - Ok(self) + self + } + + fn word(&mut self, name: String, flags: Word) -> &mut Self { + self.asm.fill(AsmAddr::Word(self.link)); + self.link = self.asm.pc(); + self.asm.fill(AsmAddr::Word(name.len() as Word + flags)); + + for byte in name.as_bytes() { + self.asm.fill(AsmAddr::Word(*byte as Word)); + } + + self + } + + fn var(&mut self, name: String, ptr: AsmAddr, next: AsmAddr) -> &mut Self { + self.word(name, 0) + .asm + .load(R0, ptr) + .add(Self::SP, Self::SP, AddMode::Immediate(1)) + .store(R0, Self::SP, 0) + .branch_unconditionally(next); + + self + } + + fn builtin_words(&mut self) -> &mut Self { + // Fetch + self.word(String::from("@"), 0) + .asm + .load_register(R0, Self::SP, 0) + .load_register(R0, R0, 0) + .store(R0, Self::SP, 0); + let next = self.asm.reference_label("next"); + self.asm.branch_unconditionally(next); + + // Store + self.word(String::from("!"), 0) + .asm + .load_register(R0, Self::SP, 0) + .load_register(R1, Self::SP, -1i16 as Word) + .store(R1, R0, 0) + .add(Self::SP, Self::SP, AddMode::Immediate(-2i16 as Word)); + + let next = self.asm.reference_label("next"); + self.asm.branch_unconditionally(next); + + self } pub fn print_tib(&mut self) -> Result<&mut Self> { @@ -166,10 +241,118 @@ impl ForthCompiler { Ok(self) } + fn interpret_loop(&mut self) -> &mut Self { + self.asm.label("intrp"); + + let token = self.asm.reference_label("token"); + self.asm + .subroutine(AsmJsrMode::Addr(token)) + .store(R2, Self::SP, 2) + .store(R3, Self::SP, 3); + + let latest = self.asm.reference_label("latest"); + self.asm.load_indirect(R0, latest).label("is_match"); + + let error = self.asm.reference_label("error"); + self.asm + .branch(ConditionCode::ZER as Word, error) + .store(R0, Self::SP, 1) + .load_register(R1, Self::SP, 2) + .load_register(R2, Self::SP, 3) + .load_register(R3, R0, 1) + .and(R3, R3, AndMode::Immediate(0xf)) // mask to get the word length and not the flags + .sub(R3, R3, R2); + + let no_match = self.asm.reference_label("no_match"); + self.asm.branch( + ConditionCode::NEG as Word | ConditionCode::POS as Word, + no_match, + ); + + self.asm + .label("nextc") + .load_register(Self::IP, R0, 2) + .load_register(R3, R1, 0) + .sub(R3, Self::IP, R3); + + let no_match = self.asm.reference_label("no_match"); + self.asm + .branch( + ConditionCode::NEG as Word | ConditionCode::POS as Word, + no_match, + ) + .add(R1, R1, AddMode::Immediate(1)) + .add(R0, R0, AddMode::Immediate(1)) + .add(R2, R2, AddMode::Immediate(-1i16 as Word)); + let found = self.asm.reference_label("found"); + self.asm.branch(ConditionCode::ZER as Word, found); + + let nextc = self.asm.reference_label("nextc"); + self.asm.branch_unconditionally(nextc); + + self.asm + .label("no_match") + .load_register(R0, Self::SP, 1) + .load_register(R0, R0, 0); + + let is_match = self.asm.reference_label("is_match"); + self.asm.branch_unconditionally(is_match); + + self.asm.label("found").add(R0, R0, AddMode::Immediate(2)); + let loop_label = self.asm.reference_label("loop"); + + self.asm.load_effective_address(Self::IP, loop_label); + + let state = self.asm.reference_label("state"); + self.asm + .load_indirect(R1, state) + .load_register(R2, Self::SP, 1) + .load_register(R2, R2, 1) + .and(R2, R2, AndMode::Immediate(0x10)) + .add(R2, R2, AddMode::Register(R1)) + .add(R2, R2, AddMode::Immediate(-1i16 as Word)); + let compile = self.asm.reference_label("compile"); + self.asm + .branch(ConditionCode::ZER as Word, compile) + .jump(R0); + + self.asm.label("loop"); + let intrp = self.asm.reference_label("intrp"); + self.asm.fill(intrp); + + self.asm.label("compile"); + + let here = self.asm.reference_label("here"); + self.asm + .load_indirect(R1, here) + .store(R0, R1, 0) + .add(R1, R1, AddMode::Immediate(1)); + + let here = self.asm.reference_label("here"); + self.asm.store_indirect(R1, here); + + let next = self.asm.reference_label("next"); + self.asm.branch_unconditionally(next); + + self + } + + fn error(&mut self) -> &mut Self { + self.asm.label("error"); + let question = self.asm.reference_label("question"); + self.asm.load(R0, question).out_char().out_char(); + + self + } + pub fn compile(&mut self) -> Result<&mut Self> { self.load_intermediate_cells() - .parse_words()? - .read_input()? + .error() + .interpret_loop() + .parse_words() + .read_input() + .define_next() + .builtin_words() // .print_tib()? .halt() .assemble()?; -- 2.45.2