~tmpod/toasty-lc3-vm

Add documentation to instructions v2 PROPOSED

jpl: 1
 Add documentation to instructions

 2 files changed, 100 insertions(+), 3 deletions(-)
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~tmpod/toasty-lc3-vm/patches/34360/mbox | git am -3
Learn more about email & git

[PATCH v2] Add documentation to instructions Export this patch

---
 primitives/src/instructions.rs | 86 ++++++++++++++++++++++++++++++++--
 vm/src/cpu.rs                  | 17 +++++++
 2 files changed, 100 insertions(+), 3 deletions(-)

diff --git a/primitives/src/instructions.rs b/primitives/src/instructions.rs
index 31651d3..b4c677a 100644
--- a/primitives/src/instructions.rs
+++ b/primitives/src/instructions.rs
@@ -7,36 +7,88 @@ use crate::utils::sign_extend;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Instruction {
    // Conditional branch
    /// Conditional branch
    /// Offsets the Program Counter (PC) by the given offset
    /// if the condition is met.
    BR(u16, u16),

    /// Addition
    /// Adds the value in the first register with
    /// either the value in a second register, or
    /// an immediate.
    ADD(Register, Register, AddMode),
    // Load

    /// Load
    //// Loads a value from memory into a destination register
    //// at an address offset from the PC.
    LD(Register, u16),

    /// Store
    /// Loads a value into memory from a source register
    /// at an address offset from the PC:
    ST(Register, u16),

    /// Jump to subroutine
    /// Sets the PC to the base register
    /// or offsets it by an immediate.
    /// The previous value of the PC is stored
    /// in R7 to allow jumping back to when
    /// the sub-routine was called.
    JSR(JsrMode),

    /// Bit-wise logical AND
    /// Performs the bit-wise AND of the value in
    /// the first register with either the value in
    /// a second register, or an immediate:
    AND(Register, Register, AndMode),

    /// Load base+offset
    /// Loads a value from memory into a destination register
    /// at an address offset from the base register.
    LDR(Register, Register, u16),

    /// Store base+offset
    /// Loads a value into memory from a source register
    /// at an address offset from the base register:
    STR(Register, Register, u16),
    /// Return from trap or interrupt

    /// Return from trap or interrupt.
    RTI,

    /// Bit-wise complement
    /// Performs the bit-wise NOT of the value
    /// in the source register and stores it
    /// in the destination register.
    NOT(Register, Register),

    /// Load indirect
    /// Loads a value from memory into a destination register
    /// by performing a double memory access on the PC
    /// offset by the immediate.
    ///
    /// dest = mem[mem[PC + offset]]
    LDI(Register, u16),

    /// Store indirect
    /// Stores a value in memory from a source register
    /// by performing a double memory access on the PC
    /// offset by the immediate.
    ///
    /// mem[mem[PC + offset]] = source
    STI(Register, u16),

    /// Jump
    /// Sets the PC to the value of the base register.
    JMP(Register),

    /// Reserved (unused instruction)
    RES,

    /// Load effective address
    /// Sets the destination register to the PC offset
    /// by an immediate.
    LEA(Register, u16),

    /// Trap (system call)
    TRAP(TrapVector),
}
@@ -90,11 +142,39 @@ impl JsrMode {
#[derive(Copy, Clone, Debug, TryFromPrimitive, IntoPrimitive, PartialEq, Eq)]
#[repr(u16)]
pub enum TrapVector {
    /// Get Character
    /// Reads a single character from the keyboard,
    /// storing the ASCII value in R0.
    GETC = 0x20,

    /// Out Character
    /// Writes a single character to the screen.
    OUT,

    /// Put String
    /// Writes a string of ASCII characters to
    /// the screen.
    /// Starts at the address specified by R0
    /// and ends upon encountering 0x0000.
    PUTS,

    /// Prompt for a character input from the keyboard.
    /// The character is echoed on the screen and copied
    /// to R0.
    IN,

    /// Put String Pair(?)
    /// Writes a string of ASCII characters to
    /// the screen.
    /// The 16 bits of the word are treated as two
    /// consecutive 8 bit ASCII characters.
    /// Starts at the address specified by R0
    /// and ends upon encountering 0x__00.
    PUTSP,

    /// Halt
    /// Halts execution and prints a message
    /// on the screen.
    HALT,
}

diff --git a/vm/src/cpu.rs b/vm/src/cpu.rs
index 2fb8310..200ad85 100644
--- a/vm/src/cpu.rs
+++ b/vm/src/cpu.rs
@@ -43,12 +43,14 @@ impl CPU {
        instruction: Instruction,
    ) -> Result<()> {
        match instruction {
            // Branch
            Instruction::BR(cond, offset) => {
                if cond & self.registers[Register::COND] != 0 {
                    let sum = self.registers[Register::PC].wrapping_add(offset);
                    self.registers[Register::PC] = sum;
                }
            }
            // Addition
            Instruction::ADD(dest, first, mode) => {
                let second_val = match mode {
                    AddMode::Register(reg) => self.registers[reg],
@@ -57,15 +59,18 @@ impl CPU {
                self.registers[dest] = self.registers[first].wrapping_add(second_val);
                self.registers.update_cond_codes(dest);
            }
            // Load
            Instruction::LD(dest, offset) => {
                let addr = self.registers[Register::PC].wrapping_add(offset);
                self.registers[dest] = memory.read(addr);
                self.registers.update_cond_codes(dest);
            }
            // Store
            Instruction::ST(source, offset) => {
                let addr = self.registers[Register::PC].wrapping_add(offset);
                memory.write(addr, self.registers[source]);
            }
            // Jump Sub-Routine
            Instruction::JSR(mode) => {
                let tmp = self.registers[Register::PC];
                let new_pc = match mode {
@@ -75,6 +80,7 @@ impl CPU {
                self.registers[Register::PC] = new_pc;
                self.registers[Register::R7] = tmp;
            }
            // Bit-wise AND
            Instruction::AND(dest, first, mode) => {
                let second_val = match mode {
                    AndMode::Register(reg) => self.registers[reg],
@@ -84,11 +90,13 @@ impl CPU {
                self.registers[dest] = self.registers[first] & second_val;
                self.registers.update_cond_codes(dest);
            }
            // Load Register
            Instruction::LDR(dest, base, offset) => {
                let addr = self.registers[base].wrapping_add(offset);
                self.registers[dest] = memory.read(addr);
                self.registers.update_cond_codes(dest);
            }
            // Store
            Instruction::STR(source, base, offset) => {
                let addr = self.registers[base].wrapping_add(offset);
                memory.write(addr, self.registers[source]);
@@ -100,21 +108,25 @@ impl CPU {
                self.registers[dest] = !self.registers[source];
                self.registers.update_cond_codes(dest);
            }
            // Load Indirect
            Instruction::LDI(dest, offset) => {
                let addr = self.registers[Register::PC].wrapping_add(offset);
                let addr_final = memory.read(addr);
                self.registers[dest] = memory.read(addr_final);
                self.registers.update_cond_codes(dest);
            }
            // Store Indirect
            Instruction::STI(source, offset) => {
                let addr = self.registers[Register::PC].wrapping_add(offset);
                let addr_final = memory.read(addr);
                memory.write(addr_final, self.registers[source]);
            }
            // Jump
            Instruction::JMP(base) => self.registers[Register::PC] = self.registers[base],
            Instruction::RES => {
                // NO-OP
            }
            // Load Effective Address
            Instruction::LEA(dest, offset) => {
                let val = self.registers[Register::PC].wrapping_add(offset);
                self.registers[dest] = val;
@@ -124,14 +136,17 @@ impl CPU {
            }
            Instruction::TRAP(vector) => {
                match vector {
                    // Get character
                    TrapVector::GETC => {
                        let c = utils::get_char()? as Word;
                        self.registers[Register::R0] = c;
                    }
                    // Output character
                    TrapVector::OUT => {
                        let c = (self.registers[Register::R0] & 0xFF) as u8;
                        utils::put_char(screen, c)?;
                    }
                    // Output string
                    TrapVector::PUTS => {
                        let mut addr = self.registers[Register::R0];
                        loop {
@@ -147,6 +162,7 @@ impl CPU {
                            addr = addr.wrapping_add(1);
                        }
                    }
                    // Prompt for character input
                    TrapVector::IN => {
                        print!("\n> ");
                        screen.flush().unwrap();
@@ -173,6 +189,7 @@ impl CPU {
                            addr = addr.wrapping_add(1);
                        }
                    }
                    // Stop execution
                    TrapVector::HALT => {
                        self.running.store(false, Ordering::SeqCst);
                    }
-- 
2.37.1


Moved the instruction docs to the primitives, as requested.
Still kept the instructions names in the match arms in the vm cpu, for
clarities sake.