~tmpod/brainfucc

79c586aed89a0362dbc794d6e22820481b1ef6bd — tmpod 1 year, 1 month ago 7ac1579
Fix instruction generation

Working well now.
3 files changed, 24 insertions(+), 18 deletions(-)

M examples/hello_world_mini.bf
M src/lc3.rs
M src/main.rs
M examples/hello_world_mini.bf => examples/hello_world_mini.bf +5 -1
@@ 1,1 1,5 @@
++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.
++++++++[>++++[>++>+++>  20
+++>+<<<<-]>+>+>->>+[<]  56  
<-]>>.>---.+++++++..+++
.>>.<-.<.+++.------.
--------.>>+.>++.

M src/lc3.rs => src/lc3.rs +16 -14
@@ 19,6 19,7 @@ impl LC3CompiledBrainfuck {
    const ORIGIN: Word = 0x3000;

    // TODO: improve this to make use of negative bound being -16 and not -15
    // TODO: move sign un-extension into primitives crate on emit function
    fn compile_add(r: Register, n: i16) -> impl Iterator<Item = LC3Instruction> {
        let base = if n >= 0 { 0xF } else { 0x1F };
        let repeats = n / 0xF;


@@ 32,12 33,15 @@ impl LC3CompiledBrainfuck {
            )))
    }

    fn compile_br(offset: i16) {}

    // Curent register usage:
    // R0 -> temporary register for I/O and other operations
    // R1 -> data pointer
    // TODO: fix expected single-byte overflow not happening because LC3 words are 2-bytes wide.
    // TODO: improve naive instruction emition to make use of registers for hot paths.
    // TODO: fix ADDs due to immediate mode only bearing 5 bits
    // TODO: replace panics with result
    pub fn compile(ir: &BrainfuckIR) -> Self {
        let mut ir_iter = ir.instructions.iter().peekable();
        let mut lc3_insts = Vec::new();


@@ 46,9 50,6 @@ impl LC3CompiledBrainfuck {
        let mut value_mod = 0i16;
        let mut pos_mod = 0i16;

        // Placeholder instruction to then be replaced by R1 init to tape beginning
        lc3_insts.push(LC3Instruction::RES);

        // One pass to do small optimizations and produce LC3 instructions
        while let Some(i) = ir_iter.next() {
            match i {


@@ 90,15 91,19 @@ impl LC3CompiledBrainfuck {
                }
                BfInstruction::RET => {
                    let opening_pc = jump_stack.pop().expect("Invalid IR");
                    let closing_pc = lc3_insts.len() as u16;
                    let closing_pc = lc3_insts.len() as i16;
                    let offset = closing_pc - opening_pc as i16;
                    if offset >= 1 << 9 {
                        panic!("Too big of a jump");
                    }
                    lc3_insts.push(LC3Instruction::LDR(Register::R0, Register::R1, 0));
                    lc3_insts.push(LC3Instruction::BR(
                        ConditionCode::NEG as u16 | ConditionCode::POS as u16,
                        closing_pc - opening_pc as u16 + 2, // +2 because we wanna land on the inst after the [
                        (-offset) as u16, // + 2, // +2 because we wanna land on the inst after the [
                    ));
                    // and fill in the jump instruction
                    lc3_insts[opening_pc + 1] =
                        LC3Instruction::BR(ConditionCode::ZER.into(), closing_pc + 2);
                        LC3Instruction::BR(ConditionCode::ZER.into(), offset as u16);
                }
                BfInstruction::INP => {
                    lc3_insts.push(LC3Instruction::TRAP(TrapVector::GETC));


@@ 113,15 118,12 @@ impl LC3CompiledBrainfuck {

        lc3_insts.push(LC3Instruction::TRAP(TrapVector::HALT));

        // Complete R1 init
        lc3_insts[0] = LC3Instruction::ADD(
            Register::R1,
            Register::R1,
            AddMode::Immediate(lc3_insts.len() as Word + 1),
        );

        LC3CompiledBrainfuck {
            instructions: lc3_insts,
            instructions: [
                Self::compile_add(Register::R1, lc3_insts.len() as i16 + 1).collect(),
                lc3_insts,
            ]
            .concat(),
        }
    }


M src/main.rs => src/main.rs +3 -3
@@ 20,13 20,13 @@ fn main() -> Result<()> {
    // crate::interpreter::execute_default(&ir);
    let lc3_compiled = crate::lc3::LC3CompiledBrainfuck::compile(&ir);
    eprintln!("LC3 compiled:");
    for i in lc3_compiled.instructions.iter() {
        eprintln!("{:?}", i);
    for (i, inst) in lc3_compiled.instructions.iter().enumerate() {
        eprintln!("{i} {inst:?}");
    }

    // Write LC3 image
    out_filename.push_str(".lc3.obj");
    println!("Emitting to {}", out_filename);
    println!("Emitting to {out_filename}");
    let mut out_file = File::create(out_filename)?;
    // TODO: implement output buffering
    for c in lc3_compiled.emit() {