~jpl8/lorthc3

be398a0177645aa3347a5d7c36b547fc3ef71399 — jpl 1 year, 28 days ago 85ea14c
Add interpret_loop
2 files changed, 215 insertions(+), 13 deletions(-)

M src/assembler.rs
M src/compiler.rs
M src/assembler.rs => src/assembler.rs +23 -4
@@ 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 {

M src/compiler.rs => src/compiler.rs +192 -9
@@ 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()?;