@@ 19,6 19,12 @@ pub enum AsmAddr {
}
#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum AsmJsrMode {
+ Addr(AsmAddr),
+ Register(Register),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AsmInstruction {
// Conditional branch
BR(u16, AsmAddr),
@@ 29,7 35,7 @@ pub enum AsmInstruction {
/// Store
ST(Register, AsmAddr),
/// Jump to subroutine
- JSR(JsrMode),
+ JSR(AsmJsrMode),
/// Bit-wise logical AND
AND(Register, Register, AndMode),
/// Load base+offset
@@ 106,7 112,15 @@ impl LC3Assembler {
r,
self.asm_addr_to_offset(addr)? as Word,
)),
- JSR(mode) => PseudoInstruction::LC3(Instruction::JSR(mode)),
+ JSR(mode) => match mode {
+ AsmJsrMode::Register(r) => {
+ PseudoInstruction::LC3(Instruction::JSR(JsrMode::Register(r)))
+ }
+
+ AsmJsrMode::Addr(addr) => PseudoInstruction::LC3(Instruction::JSR(
+ JsrMode::Offset(self.asm_addr_to_offset(addr)? as Word),
+ )),
+ },
AND(r1, r2, mode) => PseudoInstruction::LC3(Instruction::AND(r1, r2, mode)),
LDR(r1, r2, offset) => PseudoInstruction::LC3(Instruction::LDR(r1, r2, offset)),
STR(r1, r2, offset) => PseudoInstruction::LC3(Instruction::STR(r1, r2, offset)),
@@ 163,6 177,9 @@ impl LC3Assembler {
self.instr(LEA(r, addr))
}
+ pub fn load_register(&mut self, dest: Register, src: Register, offset: Word) -> &mut Self {
+ self.instr(LDR(dest, src, offset))
+ }
pub fn get_char(&mut self) -> &mut Self {
self.instr(TRAP(GETC))
}
@@ 206,6 223,10 @@ impl LC3Assembler {
self.instr(LDI(r, addr))
}
+ pub fn neg(&mut self, dest: Register, src: Register) -> &mut Self {
+ self.not(dest, src).add(dest, dest, AddMode::Immediate(1))
+ }
+
// Optimizations
fn num_diff_bits(a: Word, b: Word) -> u32 {
@@ 223,10 244,26 @@ impl LC3Assembler {
self.add(r, r, AddMode::Immediate(rem))
}
+ pub fn mov_reg(&mut self, dest: Register, src: Register) -> &mut Self {
+ self.and(dest, src, AndMode::Register(src))
+ }
+
pub fn store(&mut self, src: Register, base: Register, offset: Word) -> &mut Self {
self.instr(STR(src, base, offset))
}
+ pub fn store_indirect(&mut self, src: Register, addr: AsmAddr) -> &mut Self {
+ self.instr(STI(src, addr))
+ }
+
+ pub fn ret(&mut self) -> &mut Self {
+ self.instr(JMP(R7))
+ }
+
+ pub fn subroutine(&mut self, mode: AsmJsrMode) -> &mut Self {
+ self.instr(JSR(mode))
+ }
+
pub fn fill(&mut self, w: Word) -> &mut Self {
self.instr(FILL(w))
}
@@ 10,8 10,8 @@ use std::collections::HashMap;
use std::iter;
use crate::assembler::AsmInstruction::{self, *};
-use crate::assembler::LC3Assembler;
use crate::assembler::{AsmAddr, PseudoInstruction};
+use crate::assembler::{AsmJsrMode, LC3Assembler};
pub type SignedWord = i16;
@@ 64,48 64,94 @@ impl ForthCompiler {
}
pub fn read_input(&mut self) -> Result<&mut Self> {
+ self.asm.label("readln");
let tib_addr = self.asm.reference_label("tib");
self.asm.load(R1, tib_addr);
let toin_addr = self.asm.reference_label("toin");
- self.asm.load(R0, toin_addr);
+ self.asm.load(R0, toin_addr).store(R1, R0, 0);
- let input_reading_loop_label = "input_reading_loop";
self.asm
- .label(input_reading_loop_label)
+ .label("readlp")
.get_char()
+ // TODO: Remove out_char
.out_char()
.store(R0, R1, 0)
.add(R1, R1, AddMode::Immediate(1 as Word))
.not(R0, R0)
.and(R0, R0, AndMode::Immediate('\n' as Word));
- let loop_top = self.asm.reference_label(input_reading_loop_label);
+ let readlp = self.asm.reference_label("readlp");
self.asm
.branch(
ConditionCode::NEG as Word | ConditionCode::POS as Word,
- loop_top,
+ readlp,
)
.add(R1, R1, AddMode::Immediate(-1i16 as Word))
.store(R0, R1, 0);
+ let token = self.asm.reference_label("token");
+ self.asm.branch_unconditionally(token);
+
Ok(self)
}
fn parse_words(&mut self) -> Result<&mut Self> {
+ let token = self.asm.reference_label("token");
+ self.asm.subroutine(AsmJsrMode::Addr(token));
+ self.asm
+ .branch_unconditionally(AsmAddr::Word(-1i16 as Word));
+
self.asm.label("token");
let toin = self.asm.reference_label("toin");
- self.asm.load_indirect(R3, toin);
+ // self.asm.load_indirect(R3, toin);
+ self.asm.load(R3, toin);
let space = self.asm.reference_label("space");
- self.asm.load(R1, space);
+ self.asm.load(R1, space).neg(R1, R1);
+
+ self.asm.label("skipws");
+ self.asm.load_register(R0, R3, 0);
+
+ let readln = self.asm.reference_label("readln");
+ self.asm
+ .branch(ConditionCode::ZER as Word, readln)
+ .mov_reg(R2, R3)
+ .add(R3, R3, AddMode::Immediate(1))
+ .add(R0, R0, AddMode::Register(R1));
+
+ let skipws = self.asm.reference_label("skipws");
+ self.asm.branch(ConditionCode::ZER as Word, skipws).add(
+ R3,
+ R3,
+ AddMode::Immediate(-1i16 as Word),
+ );
+
+ self.asm
+ .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);
+
+ self.asm.label("tokend");
+ let toin = self.asm.reference_label("toin");
+ self.asm
+ .store_indirect(R3, toin)
+ .neg(R1, R2)
+ .add(R3, R3, AddMode::Register(R1))
+ .ret();
- // unimplemented!();
Ok(self)
}
pub fn print_tib(&mut self) -> Result<&mut Self> {
let tib_addr = self.asm.reference_label("tib");
self.asm.instr(LD(R0, tib_addr));
+
self.asm.instr(TRAP(PUTS));
Ok(self)
}
@@ 122,9 168,9 @@ impl ForthCompiler {
pub fn compile(&mut self) -> Result<&mut Self> {
self.load_intermediate_cells()
- .read_input()?
- .print_tib()?
.parse_words()?
+ .read_input()?
+ // .print_tib()?
.halt()
.assemble()?;