~jpl8/lorthc3

fc713564cdb78dff09e284c960ef1c92e6d2cc96 — jpl 1 year, 1 month ago 3718b7d
Add initial builder pattern instruction adding
2 files changed, 234 insertions(+), 14 deletions(-)

A src/compiler.rs
M src/main.rs
A src/compiler.rs => src/compiler.rs +131 -0
@@ 0,0 1,131 @@
use toasty_lc3_primitives::condition_codes::ConditionCode;
use toasty_lc3_primitives::instructions::{AddMode, AndMode, TrapVector::*};
use toasty_lc3_primitives::instructions::{Instruction, Instruction::*};
use toasty_lc3_primitives::types::Word;

use toasty_lc3_primitives::registers::{Register, Register::*, Registers};

use std::iter;

pub type SignedWord = i16;

pub struct ForthCompiler {
    // BIG TODO: remove pub
    pub instructions: Vec<Instruction>,
    registers: Registers,
}

impl ForthCompiler {
    pub const ORIGIN: u16 = 0x3000;
    pub const TIB: u16 = 0x3090;
    pub const TOIN: u16 = 0x3100;

    pub fn new() -> Self {
        Self {
            instructions: vec![],
            registers: Registers::new(),
        }
    }
    pub fn load(&mut self, r: Register, addr: Word) -> &mut Self {
        let offset: SignedWord = (addr as SignedWord) - (self.pc() as SignedWord) - 1;
        eprintln!("Load Offset: {:#02X}", offset);
        self.instr(LD(r, offset as Word))
    }

    pub fn load_addr(&mut self, r: Register, addr: Word) -> &mut Self {
        let offset: SignedWord = (addr as SignedWord) - (self.pc() as SignedWord) - 1;
        eprintln!("Load Offset: {:#02X}", offset);
        self.instr(LEA(r, offset as Word))
    }

    pub fn get_char(&mut self) -> &mut Self {
        self.instr(TRAP(GETC))
    }

    pub fn out_char(&mut self) -> &mut Self {
        self.instr(TRAP(OUT))
    }

    pub fn add(&mut self, dest: Register, src: Register, arg: AddMode) -> &mut Self {
        self.instr(ADD(dest, src, arg))
    }
    pub fn and(&mut self, dest: Register, src: Register, arg: AndMode) -> &mut Self {
        self.instr(AND(dest, src, arg))
    }

    pub fn not(&mut self, dest: Register, src: Register) -> &mut Self {
        self.instr(NOT(dest, src))
    }

    pub fn branch(&mut self, cond: Word, addr: Word) -> &mut Self {
        eprintln!("Addr: {:#02X}", addr);
        let offset: SignedWord = (addr as SignedWord) - (self.pc() as SignedWord) - 1;
        self.instr(BR(cond, offset as Word))
    }

    /// Move 5 bit word
    pub fn mov(&mut self, r: Register, v: Word) -> &mut Self {
        self.and(r, r, AndMode::Immediate(0))
            .add(r, r, AddMode::Immediate(v))
    }

    pub fn store(&mut self, src: Register, base: Register, offset: Word) -> &mut Self {
        self.instr(STR(src, base, offset))
    }

    pub fn halt(&mut self) -> &mut Self {
        self.instr(TRAP(HALT))
    }

    pub fn instr(&mut self, instruction: Instruction) -> &mut Self {
        self.instructions.push(instruction);
        self.inc_pc()
    }
    pub fn instrs(&mut self, instructions: Vec<Instruction>) -> &mut Self {
        instructions.into_iter().for_each(|i| {
            self.instr(i);
        });
        self
    }

    pub fn inc_pc(&mut self) -> &mut Self {
        self.registers[PC] += 1;
        self
    }

    pub fn pc(&self) -> Word {
        eprintln!("PC: {:#02X}", self.registers[PC]);
        self.registers[PC]
    }

    pub fn emit(&self) -> impl Iterator<Item = u8> + '_ {
        let inst_words = self.instructions.iter().map(|i| i.emit());
        iter::once(Self::ORIGIN)
            .chain(inst_words)
            .flat_map(|w| w.to_be_bytes())
    }

    pub fn read_input(&mut self) -> &mut Self {
        let tib_cell = self.pc();

        self.load_addr(R1, ForthCompiler::TIB)
            .load_addr(R0, ForthCompiler::TOIN);
        let loop_top = self.pc();
        self.get_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))
            .branch(
                ConditionCode::NEG as Word | ConditionCode::POS as Word,
                loop_top,
            )
            .add(R1, R1, AddMode::Immediate(-1i16 as Word))
            .store(R0, R1, 0)
    }

    pub fn compile(&mut self) -> &mut Self {
        self.read_input().halt()
    }
}

M src/main.rs => src/main.rs +103 -14
@@ 1,18 1,107 @@
use std::io;

fn main() -> io::Result<()> {
    let stdin = io::stdin();

    let lines = stdin.lines();
    for line in lines {
        let line = line?;
        let words = line.split_whitespace();
        for word in words {
            println!("{}", word);
        }
    }
mod compiler;

use compiler::ForthCompiler;
use toasty_lc3_primitives::condition_codes::ConditionCode;
use toasty_lc3_primitives::instructions::{AddMode, AndMode};
use toasty_lc3_primitives::registers::{Register, Register::*, Registers};
use toasty_lc3_primitives::types::Word;

use std::fs::File;
use std::io::{Result, Write};

// struct ForthCompiler {
//     instructions: Vec<Instruction>,
//     registers: Registers,
// }

// impl ForthCompiler {
//     /// Terminal Input Buffer
//     const TIB: u16 = 0x4000;
//     const TOIN: u16 = 0x4100;

//     fn new() -> Self {
//         Self {
//             instructions: vec![],
//             registers: Registers::new(),
//         }
//     }

//     fn test_compile(&mut self) {
//         let test = vec![
//             TRAP(GETC),
//             TRAP(OUT),
//             ADD(R0, R0, AddMode::Immediate(-1i16 as Word)), // -1
//             TRAP(OUT),
//             TRAP(HALT),
//         ];

//         self.add_instr(&test);
//     }

//     fn add_instr(&mut self, instructions: &Vec<Instruction>) -> &mut Self {
//         self.instructions.extend(instructions);
//         self
//     }

//     fn compile_readln(&mut self) {
//         // let readln_pc: Word = Registers[PC];

    println!("Hello, world!");
//         let load_addresses = vec![LD(R1, Self::TIB), LD(R0, Self::TOIN), STR(R1, R0, 0)];
//         let loop_character_reading = vec![
//             TRAP(GETC),
//             TRAP(OUT),
//             STR(R0, R1, 0),
//             ADD(R1, R1, AddMode::Immediate(1 as Word)),
//             NOT(R0, R0),
//             AND(R0, R0, AndMode::Immediate('\n' as Word)),
//         ];
//         let branching = vec![
//             BR(
//                 ConditionCode::NEG as Word | ConditionCode::POS as Word,
//                 -((loop_character_reading.len() + 1) as i16) as Word,
//             ),
//             ADD(R1, R1, AddMode::Immediate(-1i16 as Word)), // -1
//             STR(R0, R1, 0),
//         ];

//         let print_chars = vec![
//             LD(R0, Self::TIB),
//             TRAP(OUT),
//             LD(R0, Self::TIB + 1),
//             TRAP(OUT),
//             LD(R0, Self::TIB + 2),
//             TRAP(OUT),
//         ];

//         let halt = vec![TRAP(HALT)];

//         self.add_instr(&load_addresses)
//             .add_instr(&loop_character_reading)
//             .add_instr(&branching)
//             .add_instr(&print_chars)
//             // TODO: remove halt and print
//             .add_instr(&halt);
//     }

//     fn emit(&self) -> impl Iterator<Item = u8> + '_ {
//         let inst_words = self.instructions.iter().map(|i| i.emit());
//         iter::once(Self::ORIGIN)
//             .chain(inst_words)
//             .flat_map(|w| w.to_be_bytes())
//     }
// }

fn main() -> Result<()> {
    let mut out = File::create("test.obj")?;

    let mut compiler = ForthCompiler::new();
    compiler.compile();

    println!("{:?}", compiler.instructions);

    for c in compiler.emit() {
        out.write(&[c])?;
    }

    Ok(())
}