jpl: 1 Add documentation to instructions 2 files changed, 100 insertions(+), 3 deletions(-)
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 -3Learn more about email & git
--- 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),
Four slashes instead of three here ;) Looks good otherwise, thank you!
+ /// 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.