Massively add more instructions and way more features to the disassembler. that has to do pertaining with instructions
disassembler.rs:

use crate::instruction::{Instruction, Register};
use std::fmt;

/// Opcode definitions for the instruction set.
mod opcodes {
    pub const LOAD: u8 = 0x01;
    pub const ADD: u8 = 0x02;
    pub const SUB: u8 = 0x03;
    pub const JMP: u8 = 0x04;
    pub const CMP: u8 = 0x05;
    pub const JE: u8 = 0x06;
    pub const JNE: u8 = 0x07;
    pub const PUSH: u8 = 0x08;
    pub const POP: u8 = 0x09;
    pub const NOP: u8 = 0x0A;
    pub const HALT: u8 = 0x0B;
}

use opcodes::*;

/// Represents the possible errors during disassembly.
#[derive(Debug, Clone)]
pub enum DisassembleError {
    /// Occurs when there are insufficient bytes to decode an instruction.
    UnexpectedEndOfData {
        address: usize,
        expected: usize,
        found: usize,
    },
    /// Occurs when an unknown opcode is encountered.
    UnknownOpcode {
        address: usize,
        opcode: u8,
    },
}

impl fmt::Display for DisassembleError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            DisassembleError::UnexpectedEndOfData { address, expected, found } => {
                write!(
                    f,
                    "Unexpected end of data at address {}: expected {} bytes, found {}",
                    address, expected, found
                )
            }
            DisassembleError::UnknownOpcode { address, opcode } => {
                write!(
                    f,
                    "Unknown opcode 0x{:02X} encountered at address {}",
                    opcode, address
                )
            }
        }
    }
}

impl std::error::Error for DisassembleError {}

/// Represents a parsed instruction along with its address.
#[derive(Debug, Clone)]
pub struct ParsedInstruction {
    pub address: usize,
    pub instruction: Instruction,
}

/// Decoding function type. Each opcode has an associated decoding function.
type DecodeFn = fn(&[u8], usize) -> Result<(Instruction, usize), DisassembleError>;

/// Lookup table mapping opcodes to their decoding functions.
fn get_opcode_table() -> [Option<DecodeFn>; 256] {
    let mut table: [Option<DecodeFn>; 256] = [None; 256];
    
    table[LOAD as usize] = Some(decode_load);
    table[ADD as usize] = Some(decode_add);
    table[SUB as usize] = Some(decode_sub);
    table[JMP as usize] = Some(decode_jmp);
    table[CMP as usize] = Some(decode_cmp);
    table[JE as usize] = Some(decode_je);
    table[JNE as usize] = Some(decode_jne);
    table[PUSH as usize] = Some(decode_push);
    table[POP as usize] = Some(decode_pop);
    table[NOP as usize] = Some(decode_nop);
    table[HALT as usize] = Some(decode_halt);
    
    table
}

/// Disassembles binary data into a vector of parsed instructions.
///
/// # Arguments
///
/// * `data` - A slice of bytes representing the binary code.
///
/// # Returns
///
/// * A vector of `ParsedInstruction` structs or a disassembly error.
pub fn disassemble(data: &[u8]) -> Result<Vec<ParsedInstruction>, DisassembleError> {
    let mut instructions = Vec::new();
    let mut pc = 0;
    let opcode_table = get_opcode_table();

    while pc < data.len() {
        let address = pc;
        let opcode = data[pc];
        if let Some(decode_fn) = opcode_table[opcode as usize] {
            match decode_fn(data, pc) {
                Ok((instruction, bytes_consumed)) => {
                    instructions.push(ParsedInstruction {
                        address,
                        instruction,
                    });
                    pc += bytes_consumed;
                }
                Err(e) => {
                    return Err(e);
                }
            }
        } else {
            // Handle unknown opcode
            instructions.push(ParsedInstruction {
                address,
                instruction: Instruction::Unknown {
                    opcode,
                    bytes: data[pc..].iter().copied().take(1).collect(),
                },
            });
            pc += 1; // Skip unknown opcode
        }
    }

    Ok(instructions)
}

/// Decodes the LOAD instruction.
///
/// Format: LOAD Register, Immediate
fn decode_load(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // LOAD is 1 byte opcode + 1 byte register + 2 bytes immediate
    let expected_length = 4;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }
    let reg_code = data[pc + 1];
    let reg = decode_register(reg_code);
    let imm = u16::from_be_bytes([data[pc + 2], data[pc + 3]]);
    Ok((
        Instruction::Load {
            register: reg,
            value: imm,
        },
        expected_length,
    ))
}

/// Decodes the ADD instruction.
///
/// Format: ADD Register, Register
fn decode_add(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // ADD is 1 byte opcode + 1 byte dest + 1 byte src
    let expected_length = 3;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }
    let dest_code = data[pc + 1];
    let src_code = data[pc + 2];
    let dest = decode_register(dest_code);
    let src = decode_register(src_code);
    Ok((
        Instruction::Add { dest, src },
        expected_length,
    ))
}

/// Decodes the SUB instruction.
///
/// Format: SUB Register, Register
fn decode_sub(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // SUB is 1 byte opcode + 1 byte dest + 1 byte src
    let expected_length = 3;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }
    let dest_code = data[pc + 1];
    let src_code = data[pc + 2];
    let dest = decode_register(dest_code);
    let src = decode_register(src_code);
    Ok((
        Instruction::Sub { dest, src },
        expected_length,
    ))
}

/// Decodes the JMP instruction.
///
/// Format: JMP Address
fn decode_jmp(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // JMP is 1 byte opcode + 2 bytes address
    let expected_length = 3;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }
    let addr = u16::from_be_bytes([data[pc + 1], data[pc + 2]]);
    Ok((
        Instruction::Jmp { address: addr },
        expected_length,
    ))
}

/// Decodes the CMP instruction.
///
/// Format: CMP Register, Register
fn decode_cmp(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // CMP is 1 byte opcode + 1 byte reg1 + 1 byte reg2
    let expected_length = 3;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }
    let reg1_code = data[pc + 1];
    let reg2_code = data[pc + 2];
    let reg1 = decode_register(reg1_code);
    let reg2 = decode_register(reg2_code);
    Ok((
        Instruction::Cmp { reg1, reg2 },
        expected_length,
    ))
}

/// Decodes the JE instruction.
///
/// Format: JE Address
fn decode_je(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // JE is 1 byte opcode + 2 bytes address
    let expected_length = 3;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }
    let addr = u16::from_be_bytes([data[pc + 1], data[pc + 2]]);
    Ok((
        Instruction::Je { address: addr },
        expected_length,
    ))
}

/// Decodes the JNE instruction.
///
/// Format: JNE Address
fn decode_jne(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // JNE is 1 byte opcode + 2 bytes address
    let expected_length = 3;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }
    let addr = u16::from_be_bytes([data[pc + 1], data[pc + 2]]);
    Ok((
        Instruction::Jne { address: addr },
        expected_length,
    ))
}

/// Decodes the PUSH instruction.
///
/// Format: PUSH Register
fn decode_push(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // PUSH is 1 byte opcode + 1 byte register
    let expected_length = 2;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }
    let reg_code = data[pc + 1];
    let reg = decode_register(reg_code);
    Ok((
        Instruction::Push { register: reg },
        expected_length,
    ))
}

/// Decodes the POP instruction.
///
/// Format: POP Register
fn decode_pop(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // POP is 1 byte opcode + 1 byte register
    let expected_length = 2;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }
    let reg_code = data[pc + 1];
    let reg = decode_register(reg_code);
    Ok((
        Instruction::Pop { register: reg },
        expected_length,
    ))
}

/// Decodes the NOP instruction.
///
/// Format: NOP
fn decode_nop(_data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // NOP is 1 byte opcode
    Ok((Instruction::Nop, 1))
}

/// Decodes the HALT instruction.
///
/// Format: HALT
fn decode_halt(_data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // HALT is 1 byte opcode
    Ok((Instruction::Halt, 1))
}

/// Decodes a register code into a `Register` enum.
///
/// # Arguments
///
/// * `code` - The register code as a `u8`.
///
/// # Returns
///
/// * A `Register` enum variant.
fn decode_register(code: u8) -> Register {
    match code {
        0x00 => Register::R0,
        0x01 => Register::R1,
        0x02 => Register::R2,
        0x03 => Register::R3,
        0x04 => Register::R4,
        0x05 => Register::R5,
        0x06 => Register::R6,
        0x07 => Register::R7,
        unknown => Register::Unknown(unknown),
    }
}

instruction.rs:
use std::fmt;

/// Defines the CPU registers.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Register {
    R0,
    R1,
    R2,
    R3,
    R4,
    R5,
    R6,
    R7,
    Unknown(u8),
}

impl fmt::Display for Register {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Register::R0 => write!(f, "R0"),
            Register::R1 => write!(f, "R1"),
            Register::R2 => write!(f, "R2"),
            Register::R3 => write!(f, "R3"),
            Register::R4 => write!(f, "R4"),
            Register::R5 => write!(f, "R5"),
            Register::R6 => write!(f, "R6"),
            Register::R7 => write!(f, "R7"),
            Register::Unknown(code) => write!(f, "R{}", code),
        }
    }
}

/// Defines various operand types for instructions.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Operand {
    Register(Register),
    Immediate(u16),
    Address(u16),
}

impl fmt::Display for Operand {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Operand::Register(reg) => write!(f, "{}", reg),
            Operand::Immediate(val) => write!(f, "0x{:04X}", val),
            Operand::Address(addr) => write!(f, "0x{:04X}", addr),
        }
    }
}

/// Defines the complete set of instructions supported by the CPU.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Instruction {
    /// LOAD Register, Immediate
    Load { register: Register, value: u16 },
    /// ADD Register, Register
    Add { dest: Register, src: Register },
    /// SUB Register, Register
    Sub { dest: Register, src: Register },
    /// JMP Address
    Jmp { address: u16 },
    /// CMP Register, Register
    Cmp { reg1: Register, reg2: Register },
    /// JE Address
    Je { address: u16 },
    /// JNE Address
    Jne { address: u16 },
    /// PUSH Register
    Push { register: Register },
    /// POP Register
    Pop { register: Register },
    /// NOP
    Nop,
    /// HALT
    Halt,
    /// Unknown or invalid instruction
    Unknown { opcode: u8, bytes: Vec<u8> },
}

impl fmt::Display for Instruction {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Instruction::Load { register, value } => write!(f, "LOAD {}, {}", register, value),
            Instruction::Add { dest, src } => write!(f, "ADD {}, {}", dest, src),
            Instruction::Sub { dest, src } => write!(f, "SUB {}, {}", dest, src),
            Instruction::Jmp { address } => write!(f, "JMP {}", address),
            Instruction::Cmp { reg1, reg2 } => write!(f, "CMP {}, {}", reg1, reg2),
            Instruction::Je { address } => write!(f, "JE {}", address),
            Instruction::Jne { address } => write!(f, "JNE {}", address),
            Instruction::Push { register } => write!(f, "PUSH {}", register),
            Instruction::Pop { register } => write!(f, "POP {}", register),
            Instruction::Nop => write!(f, "NOP"),
            Instruction::Halt => write!(f, "HALT"),
            Instruction::Unknown { opcode, bytes } => {
                write!(f, "UNKNOWN 0x{:02X} {:?}", opcode, bytes)
            }
        }
    }
}