@@ 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 {
@@ 18,6 18,8 @@ pub type SignedWord = i16;
pub struct ForthCompiler {
asm: LC3Assembler,
assembled_instructions: Vec<PseudoInstruction>,
+ /// 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<Item = u8> + '_ {
@@ 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()?;