text:
<file_sep>use crate::architecture::model::state::State;
use crate::architecture::units::memory_unit;
use crate::architecture::model::instruction::Instruction;
use crate::architecture::model::registers::Register;
use crate::architecture::AddressPtr;

/// # Data Instructions:
///
/// Instructions which transfer data between registers or between
/// memory and registers.

pub fn move_reg(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let value = memory_unit::get_reg_value(state, &instruction.register[1]);

    memory_unit::set_reg_value(state, &instruction.register[0], value);

    state.pc + instruction.size()
}

pub fn load_accumulator(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let data = memory_unit::get_reg_mem_value(state, &instruction.register[0]);

    memory_unit::set_reg_value(state, &Register::A, data);

    state.pc + instruction.size()
}

pub fn store_accumulator(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let data = memory_unit::get_reg_value(state, &Register::A);

    memory_unit::set_reg_mem_value(state, &instruction.register[0], data);

    state.pc + instruction.size()
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::architecture::model::opcodes::OpCode;

    #[test]
    fn test_move_reg_to_reg() {
        let mut state = State {a:10,b:7,..Default::default()};
        let instruction = &Instruction{opcode:OpCode::MOV,register:vec![Register::A, Register::B],..Default::default()};

        assert_eq!(state.a, 10);
        assert_eq!(state.b, 7);

        let result = move_reg(&mut state, instruction);
        assert_eq!(result, 1);
        assert_eq!(state.a, 7);
        assert_eq!(state.b, 7);
    }

    #[test]
    fn test_move_reg_to_mem() {
        let index:usize = 0x0020;
        let mut memory: Vec<u8> = vec![0;100];
        let value:u8 = 0x1c;
        let mut state = State {b:value, h:0x00, l:0x20,memory,..Default::default()};
        let instruction = &Instruction{opcode:OpCode::MOV,register:vec![Register::M, Register::B],..Default::default()};

        let result = move_reg(&mut state, instruction);
        assert_eq!(result, 1);
        assert_eq!(state.memory[index], value);
        assert_eq!(state.b, value);
    }

    #[test]
    fn test_move_mem_to_reg() {
        let index:usize = 0x0020;
        let mut memory: Vec<u8> = vec![0;100];
        let value:u8 = 0x1c;
        memory[index] = value;
        let mut state = State {b:0x00, h:0x00, l:0x20,memory,..Default::default()};
        let instruction = &Instruction{opcode:OpCode::MOV,register:vec![Register::B, Register::M],..Default::default()};

        let result = move_reg(&mut state, instruction);
        assert_eq!(result, 1);
        assert_eq!(state.memory[index], value);
        assert_eq!(state.b, value);
    }

    #[test]
    fn test_load_acc_from_bc() {
        let index:usize = 0x0020;
        let mut memory: Vec<u8> = vec![0;100];
        let value:u8 = 0x1c;
        memory[index] = value;
        let mut state = State {b:0x00, c:0x20, memory,..Default::default()};
        let instruction = &Instruction{opcode:OpCode::LDAX,register:vec![Register::B],..Default::default()};

        let result = load_accumulator(&mut state, instruction);
        assert_eq!(result, 1);
        assert_eq!(state.memory[index], value);
        assert_eq!(state.a, value);
        assert_eq!(state.b, 0x00);
        assert_eq!(state.c, 0x20);
    }

    #[test]
    fn test_load_acc_from_de() {
        let index:usize = 0x0020;
        let mut memory: Vec<u8> = vec![0;100];
        let value:u8 = 0x1c;
        memory[index] = value;
        let mut state = State {d:0x00, e:0x20, memory,..Default::default()};
        let instruction = &Instruction{opcode:OpCode::LDAX,register:vec![Register::D],..Default::default()};

        let result = load_accumulator(&mut state, instruction);
        assert_eq!(result, 1);
        assert_eq!(state.memory[index], value);
        assert_eq!(state.a, value);
        assert_eq!(state.d, 0x00);
        assert_eq!(state.e, 0x20);
    }

    #[test]
    fn test_store_acc_to_bc() {
        let index:usize = 0x0020;
        let mut memory: Vec<u8> = vec![0;100];
        let value:u8 = 0x1c;
        let mut state = State {a: value, b:0x00, c:0x20, memory,..Default::default()};
        let instruction = &Instruction{opcode:OpCode::STAX,register:vec![Register::B],..Default::default()};

        let result = store_accumulator(&mut state, instruction);
        assert_eq!(result, 1);
        assert_eq!(state.memory[index], value);
        assert_eq!(state.a, value);
        assert_eq!(state.b, 0x00);
        assert_eq!(state.c, 0x20);
    }

    #[test]
    fn test_store_acc_to_de() {
        let index:usize = 0x0020;
        let mut memory: Vec<u8> = vec![0;100];
        let value:u8 = 0x1c;
        let mut state = State {a: value, d:0x00, e:0x20, memory,..Default::default()};
        let instruction = &Instruction{opcode:OpCode::STAX,register:vec![Register::D],..Default::default()};

        let result = store_accumulator(&mut state, instruction);
        assert_eq!(result, 1);
        assert_eq!(state.memory[index], value);
        assert_eq!(state.a, value);
        assert_eq!(state.d, 0x00);
        assert_eq!(state.e, 0x20);
    }
}<file_sep>use crate::architecture::model::state::State;
use crate::architecture::model::instruction::Instruction;
use crate::architecture::AddressPtr;

/// # Halt Instructions:
///
/// Instructions which operate directly upon the Interrupt Enable
/// flip-flop INTE.

pub fn halt(state: &mut State, instruction: &Instruction) -> AddressPtr {
    state.stopped = true;
    state.pc + instruction.size()
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::architecture::model::opcodes::OpCode;

    #[test]
    fn test_halt() {
        let mut state = State {..Default::default()};
        let instruction = &Instruction{opcode:OpCode::HLT,..Default::default()};
        let result = halt(&mut state, instruction);
        assert_eq!(result, 1);
        assert_eq!(state.stopped, true);
    }
}<file_sep>[package]
name = "intel_8080_emulator"
version = "0.1.0"
authors = ["<NAME> <<EMAIL>>"]
edition = "2018"

[lib]
name = "intel_8080_emulator"
path = "./src/lib.rs"

[dependencies]
strum = "0.15.0"
strum_macros = "0.15.0"
<file_sep>use crate::architecture::model::state::State;
use crate::architecture::model::registers::Register;

pub fn push_return_addr(state: &mut State, ret: u16){
    let ret1 = ((ret >> 8) & 0xff) as u8;
    let ret2 = (ret & 0xff) as u8;
    push(state, (ret1, ret2));
}

pub fn pop_return_addr(state: &mut State) -> u16 {
    let addr = pop(state);
    ((addr.0 as u16) << 8) | addr.1 as u16
}

pub fn push_reg(state: &mut State, reg: &Register){
    let addr = match reg {
        Register::PSW => (state.a, state.cc.as_binary()),
        Register::B => (state.b, state.c),
        Register::D => (state.d, state.e),
        Register::H => (state.h, state.l),
        _ => (0,0)
    };

    push(state, addr);
}

pub fn push(state: &mut State, addr: (u8, u8)){
    state.memory[state.sp-1] = addr.0;
    state.memory[state.sp-2] = addr.1;
    state.sp -= 2;
}

pub fn pop(state: &mut State) -> (u8, u8) {
    let addr1 = state.memory[state.sp+1];
    let addr2 = state.memory[state.sp];

    state.sp += 2;
    (addr1, addr2)
}

pub fn pop_to_reg(state: &mut State, reg: &Register){
    let addr = pop(state);

    match reg {
        Register::PSW => {state.a = addr.0; state.cc.update_from_binary(addr.1)},
        Register::B => {state.b = addr.0; state.c = addr.1},
        Register::D => {state.d = addr.0; state.e = addr.1},
        Register::H => {state.h = addr.0; state.l = addr.1},
        _ => ()
    };
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_push() {
        let state = &mut State{pc:0x2000,sp:0x1002,memory:vec![0;10000],..Default::default()};
        let ret:u16 = (state.pc + 3) as u16;
        push_return_addr(state, ret);
        assert_eq!(state.pc, 0x2000);
        assert_eq!(state.sp, 0x1000);
        assert_eq!(state.memory[state.sp+1],0x20);
        assert_eq!(state.memory[state.sp],0x03);
    }

    #[test]
    fn test_pop() {
        let state = &mut State{pc:0x2000,sp:0x1002,memory:vec![0;10000],..Default::default()};
        let ret:u16 = (state.pc + 3) as u16;
        push_return_addr(state, ret);
        let popped_ret = pop_return_addr(state);
        assert_eq!(state.pc, 0x2000);
        assert_eq!(state.sp, 0x1002);
        assert_eq!(popped_ret,0x2003);
    }
}<file_sep>use crate::architecture::devices::output_handler;
use crate::architecture::devices::output_handler::OutputHandler;
use crate::architecture::devices::input_handler::InputHandler;
use crate::architecture::devices::input_handler;

pub fn get_output_handler(device_id: u8) -> &'static OutputHandler {
    &output_handler::DefaultHandler{}
}

pub fn get_input_handler(device_id: u8) -> &'static InputHandler {
    &input_handler::DefaultHandler{}
}<file_sep>
#[derive(Debug, Eq, PartialEq, Default)]
pub struct ConditionCodes {
    pub z: bool,
    pub s: bool,
    pub p: bool,
    pub cy: bool,
    pub ac: bool
}

impl ConditionCodes {
    pub fn as_binary(&self) -> u8 {
        let _7 = if self.s {0x80} else {0x00};
        let _6 = if self.z {0x40} else {0x00};
        let _5 = 0x00;
        let _4 = if self.ac {0x10} else {0x00};
        let _3 = 0x00;
        let _2 = if self.p {0x04} else {0x00};
        let _1 = 0x02;
        let _0 = if self.cy {0x01} else {0x00};

        let value = _7 | _6 | _5 | _4 | _3 | _2 | _1 | _0;

        value
    }

    pub fn update_from_binary(&mut self, bin: u8) {
        self.cy = bin & 1 == 1;
        self.p = (bin >> 2) & 1 == 1;
        self.ac = (bin >> 4) & 1 == 1;
        self.z = (bin >> 6) & 1 == 1;
        self.s = (bin >> 7) & 1 == 1;
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_all_conditions_false() {
        let cc = ConditionCodes{z: false,s: false,p: false,cy: false,ac: false};
        assert_eq!(cc.as_binary(), 0x02);
    }

    #[test]
    fn test_all_conditions_true() {
        let cc = ConditionCodes{z: true,s: true,p: true,cy: true,ac: true};
        assert_eq!(cc.as_binary(), 0xd7);
    }

    #[test]
    fn test_some_conditions_true() {
        let cc = ConditionCodes{z: false,s: false,p: true,cy: false,ac: true};
        assert_eq!(cc.as_binary(), 0x16);
    }

    #[test]
    fn test_update_all_conditions_false() {
        let mut cc = ConditionCodes{z: false,s: false,p: false,cy: false,ac: false};
        cc.update_from_binary(0x02);
        assert_eq!(cc, ConditionCodes{z: false,s: false,p: false,cy: false,ac: false});
    }

    #[test]
    fn test_update_all_conditions_true() {
        let mut cc = ConditionCodes{z: false,s: false,p: false,cy: false,ac: false};
        cc.update_from_binary(0xd7);
        assert_eq!(cc, ConditionCodes{z: true,s: true,p: true,cy: true,ac: true});
    }

    #[test]
    fn test_update_some_conditions_true() {
        let mut cc = ConditionCodes{z: false,s: false,p: false,cy: false,ac: false};
        cc.update_from_binary(0x16);
        assert_eq!(cc, ConditionCodes{z: false,s: false,p: true,cy: false,ac: true});
    }
}<file_sep>pub mod state;
pub mod registers;
pub mod condition_codes;
pub mod opcodes;
pub mod instruction;<file_sep>use crate::architecture::model::state::State;
use crate::architecture::model::instruction::Instruction;
use crate::architecture::AddressPtr;
use crate::architecture::units::memory_unit;
use crate::architecture::units::arithmetic_logic_unit;

/// # Register or Memory to Accumulator Instructions:
///
/// Instructions which operate on the accumulator using a byte
/// fetched from another register or memory.

//TODO: unit tests
pub fn add(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let reg = memory_unit::get_reg_value(state, &instruction.register[0]);
    let acc = state.a;
    let result = arithmetic_logic_unit::add(acc, reg);
    state.a = result.0;
    state.cc = result.1;
    state.pc + instruction.size()
}

//TODO: unit tests
pub fn add_with_carry(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let reg = memory_unit::get_reg_value(state, &instruction.register[0]);
    let acc = state.a;
    let result = arithmetic_logic_unit::add(acc, reg);
    let result = if state.cc.cy {arithmetic_logic_unit::add(result.0, 1)} else {result};

    state.a = result.0;
    state.cc = result.1;
    state.pc + instruction.size()
}

//TODO: unit tests
pub fn sub(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let reg = memory_unit::get_reg_value(state, &instruction.register[0]);
    let acc = state.a;
    let result = arithmetic_logic_unit::sub(acc, reg);
    state.a = result.0;
    state.cc = result.1;
    state.pc + instruction.size()
}

//TODO: unit tests
pub fn sub_with_borrow(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let reg = memory_unit::get_reg_value(state, &instruction.register[0]);
    let acc = state.a;
    let result = arithmetic_logic_unit::sub(acc, reg);
    let result = if state.cc.cy {arithmetic_logic_unit::sub(result.0, 1)} else {result};

    state.a = result.0;
    state.cc = result.1;
    state.pc + instruction.size()
}

//TODO: unit tests
pub fn logical_and(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let acc_value = state.a;
    let reg_value = memory_unit::get_reg_value(state, &instruction.register[0]);

    let result = arithmetic_logic_unit::and(acc_value, reg_value);

    state.cc.cy = result.1.cy;
    state.cc.s = result.1.s;
    state.cc.z = result.1.z;
    state.cc.p = result.1.p;

    state.a = result.0;

    state.pc + instruction.size()
}

//TODO: unit tests
pub fn logical_xor(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let acc_value = state.a;
    let reg_value = memory_unit::get_reg_value(state, &instruction.register[0]);

    let result = arithmetic_logic_unit::xor(acc_value, reg_value);

    state.cc.cy = result.1.cy;
    state.cc.s = result.1.s;
    state.cc.z = result.1.z;
    state.cc.p = result.1.p;

    state.a = result.0;

    state.pc + instruction.size()
}

//TODO: unit tests
pub fn logical_or(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let acc_value = state.a;
    let reg_value = memory_unit::get_reg_value(state, &instruction.register[0]);

    let result = arithmetic_logic_unit::or(acc_value, reg_value);

    state.cc.cy = result.1.cy;
    state.cc.s = result.1.s;
    state.cc.z = result.1.z;
    state.cc.p = result.1.p;

    state.a = result.0;

    state.pc + instruction.size()
}

//TODO: unit tests
pub fn compare(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let acc = state.a;
    let reg = memory_unit::get_reg_value(state, &instruction.register[0]);

    let result = arithmetic_logic_unit::compare(acc, reg);

    state.cc = result.1;

    state.pc + instruction.size()
}<file_sep>use std::io;
use std::result::Result::Ok;

use intel_8080_emulator::architecture::cpu_context::CpuContext;
use intel_8080_emulator::disassembler;

fn main() -> io::Result<()> {
    let program = "resources/invaders.rom";

    disassembler::disassemble(program, false)?;

    let mut cpu = CpuContext::load_program(program, 65536);
    //cpu.run();

    Ok(())
}
<file_sep>use crate::architecture::model::state::State;
use crate::architecture::model::instruction::Instruction;
use crate::architecture::AddressPtr;

/// # Interrupt Instructions:
///
/// Instructions which operate directly upon the Interrupt Enable
/// flip-flop INTE.

pub fn enable(state: &mut State, instruction: &Instruction) -> AddressPtr {
    state.int_enable = true;
    state.pc + instruction.size()
}

pub fn disable(state: &mut State, instruction: &Instruction) -> AddressPtr {
    state.int_enable = false;
    state.pc + instruction.size()
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::architecture::model::opcodes::OpCode;

    #[test]
    fn test_enable() {
        let mut state = State {..Default::default()};
        let instruction = &Instruction{opcode:OpCode::EI,..Default::default()};
        let result = enable(&mut state, instruction);
        assert_eq!(result, 1);
        assert_eq!(state.int_enable, true);
    }

    #[test]
    fn test_disable() {
        let mut state = State {..Default::default()};
        let instruction = &Instruction{opcode:OpCode::DI,..Default::default()};
        let result = disable(&mut state, instruction);
        assert_eq!(result, 1);
        assert_eq!(state.int_enable, false);
    }
}<file_sep>pub mod audio;
pub mod controls;
pub mod screen;
pub mod output_handler;
pub mod input_handler;<file_sep>use crate::architecture::model::condition_codes::ConditionCodes;
use crate::architecture::ExecutionStep;
use crate::architecture::AddressPtr;
use crate::architecture::IoSignal;

#[derive(Default)]
pub struct State {
    pub a: u8,                                 // accumulator
    pub b: u8,                                 // reg b
    pub c: u8,                                 // reg c
    pub d: u8,                                 // reg d
    pub e: u8,                                 // reg e
    pub h: u8,                                 // reg h
    pub l: u8,                                 // reg l
    pub pc: AddressPtr,                        // program counter
    pub sp: AddressPtr,                        // stack pointer
    pub nc: AddressPtr,                        // next counter
    pub memory: Vec<u8>,
    pub cc: ConditionCodes,
    pub int_enable: bool,                      // interrupt enabled / disabled
    pub stopped: bool,                         // if true, no further activity occurs until an interrupt
    pub input_queue: Vec<u8>,                  // signals sent from input devices
    pub output_queue: Vec<IoSignal>,       // signals sent to output devices
    pub instruction_queue: Vec<ExecutionStep>
}

impl State {
    pub fn debug(&self, instruction: String) {
        println!("*********************");
        println!("Executing: {} @ {:04x}",instruction, self.pc);
        println!("Registers: [a: {:02x}, b, {:02x}, c: {:02x}, d: {:02x}, e: {:02x}, h: {:02x}, l: {:02x}]", self.a, self.b, self.c, self.d, self.e, self.h, self.l);
        println!("Stack Pointer: {:04x}", self.sp);
        println!("Flags: [ac: {}, cy: {}, s: {}, p: {}, z: {}]", self.cc.ac, self.cc.cy, self.cc.s, self.cc.p, self.cc.z);
        println!("*********************");
    }
}<file_sep>use crate::architecture::model::state::State;
use crate::architecture::model::instruction::Instruction;
use crate::architecture::AddressPtr;

/// # Carry Bit Instructions:
///
/// Instructions which operate directly on the carry bit.

pub fn complement(state: &mut State, instruction: &Instruction) -> AddressPtr {
    state.cc.cy = !state.cc.cy;
    state.pc + instruction.size()
}

pub fn set(state: &mut State, instruction: &Instruction) -> AddressPtr {
    state.cc.cy = true;
    state.pc + instruction.size()
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::architecture::model::condition_codes::ConditionCodes;
    use crate::architecture::model::opcodes::OpCode;

    #[test]
    fn test_complement() {
        let cc = ConditionCodes{z: false,s: false,p: false,cy: false,ac: false};
        let mut state = State {cc,..Default::default()};
        let instruction = &Instruction{opcode:OpCode::CMC,..Default::default()};

        let result = complement(&mut state, instruction);
        assert_eq!(result, 1);
        assert_eq!(state.cc.cy, true);
    }

    #[test]
    fn test_complement_while_already_set() {
        let cc = ConditionCodes{z: false,s: false,p: false,cy: true,ac: false};
        let mut state = State {cc,..Default::default()};
        let instruction = &Instruction{opcode:OpCode::CMC,..Default::default()};

        let result = complement(&mut state, instruction);
        assert_eq!(result, 1);
        assert_eq!(state.cc.cy, false);
    }

    #[test]
    fn test_set() {
        let cc = ConditionCodes{z: false,s: false,p: false,cy: false,ac: false};
        let mut state = State {cc,..Default::default()};
        let instruction = &Instruction{opcode:OpCode::STC,..Default::default()};

        let result = set(&mut state, instruction);
        assert_eq!(result, 1);
        assert_eq!(state.cc.cy, true);
    }

    #[test]
    fn test_set_while_already_set() {
        let cc = ConditionCodes{z: false,s: false,p: false,cy: true,ac: false};
        let mut state = State {cc,..Default::default()};
        let instruction = &Instruction{opcode:OpCode::STC,..Default::default()};

        let result = set(&mut state, instruction);
        assert_eq!(result, 1);
        assert_eq!(state.cc.cy, true);
    }
}<file_sep>use crate::architecture::instructions::*;
use crate::architecture::model::opcodes::OpCode;
use crate::architecture::units::control_unit;
use crate::architecture::model::opcodes::OpCode::*;
use crate::architecture::ExecutionStep;

pub fn process_instruction(opcode: &OpCode) -> ExecutionStep {
    match opcode {
        NOP => nop::no_operation,
        LXI => immediate::load_register_pair,
        STAX => data_transfer::store_accumulator,
        INX => register_pair::increment,
        INR => single_register::increment,
        DCR => single_register::decrement,
        MVI => immediate::move_data,
        RLC => rotate_accumulator::rotate_left,
        DAD => register_pair::double_add,
        LDAX => data_transfer::load_accumulator,
        DCX => register_pair::decrement,
        RRC => rotate_accumulator::rotate_right,
        RAL => rotate_accumulator::rotate_left_through_carry,
        RAR => rotate_accumulator::rotate_right_through_carry,
        SHLD => direct_addressing::store_hl,
        DAA => single_register::decimal_adjust_accumulator,
        LHLD => direct_addressing::load_hl,
        CMA => single_register::complement_accumulator,
        STA => direct_addressing::store_accumulator,
        STC => carry_bit::set,
        LDA => direct_addressing::load_accumulator,
        CMC => carry_bit::complement,
        MOV => data_transfer::move_reg,
        HLT => hlt::halt,
        ADD => to_accumulator::add,
        ADC => to_accumulator::add_with_carry,
        SUB => to_accumulator::sub,
        SBB => to_accumulator::sub_with_borrow,
        ANA => to_accumulator::logical_and,
        XRA => to_accumulator::logical_xor,
        ORA => to_accumulator::logical_or,
        CMP => to_accumulator::compare,
        RNZ => control_unit::no_zero,
        POP => register_pair::pop,
        JNZ => control_unit::no_zero,
        JMP => control_unit::default,
        CNZ => control_unit::no_zero,
        PUSH => register_pair::push,
        ADI => immediate::add,
        RST => rst::restart,
        RZ => control_unit::zero,
        RET => control_unit::default,
        JZ => control_unit::zero,
        CZ => control_unit::zero,
        CALL => control_unit::default,
        ACI => immediate::add_with_carry,
        RNC => control_unit::no_carry,
        JNC => control_unit::no_carry,
        OUT => io::output,
        CNC => control_unit::no_carry,
        SUI => immediate::sub,
        RC => control_unit::carry,
        JC => control_unit::carry,
        IN => io::input,
        CC => control_unit::carry,
        SBI => immediate::sub_with_borrow,
        RPO => control_unit::parity_odd,
        JPO => control_unit::parity_odd,
        XTHL => register_pair::exchange_sp,
        CPO => control_unit::parity_odd,
        ANI => immediate::and,
        RPE => control_unit::parity_even,
        PCHL => control_unit::load_pc,
        JPE => control_unit::parity_even,
        XCHG => register_pair::exchange,
        CPE => control_unit::parity_even,
        XRI => immediate::xor,
        RP => control_unit::positive,
        JP => control_unit::positive,
        DI => interrupt::disable,
        CP => control_unit::positive,
        ORI => immediate::or,
        RM => control_unit::minus,
        SPHL => register_pair::load_sp_from_hl,
        JM => control_unit::minus,
        EI => interrupt::enable,
        CM => control_unit::minus,
        CPI => immediate::compare,
    }
}<file_sep>use crate::architecture::model::state::State;
use crate::architecture::model::instruction::Instruction;
use crate::architecture::AddressPtr;

pub fn no_operation(state: &mut State, _instruction: &Instruction) -> AddressPtr {
    state.pc + 1
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::architecture::model::opcodes::OpCode;

    #[test]
    fn test_nop() {
        let mut state = State {..Default::default()};
        let instruction = &Instruction{opcode:OpCode::NOP,..Default::default()};
        let result = no_operation(&mut state, instruction);
        assert_eq!(result, 1);
    }
}<file_sep>use crate::architecture::model::state::State;
use crate::architecture::IoSignal;

pub trait InputHandler {
    fn next_signal(&self, state: &mut State) -> IoSignal;
}

pub struct DefaultHandler {}

impl InputHandler for DefaultHandler {
    fn next_signal(&self, state: &mut State) -> IoSignal {
        let signal = IoSignal{device: 0x10, signal: 0x1c};
        println!("Default output handler #{:02x} just received the {:02x} signal", signal.device, signal.signal);
        signal
    }
}<file_sep>pub mod arithmetic_logic_unit;
pub mod control_unit;
pub mod memory_unit;
pub mod stack;
pub mod exception_handler;
pub mod processing_unit;
pub mod io_unit;<file_sep>use crate::architecture::model::state::State;
use crate::architecture::units::memory_unit;
use crate::architecture::model::instruction::Instruction;
use crate::architecture::AddressPtr;
use crate::architecture::model::registers::Register;
use crate::architecture::units::arithmetic_logic_unit;

/// # Direct Addressing Instructions:
///
/// Instructions which reference memory by a two-byte address
/// which is part of the instruction itself.

pub fn store_accumulator(state: &mut State, instruction: &Instruction) -> AddressPtr {
    memory_unit::set_mem_value(state, (instruction.operands[0], instruction.operands[1]), state.a);
    state.pc + instruction.size()
}

pub fn load_accumulator(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let data = memory_unit::get_mem_value(state, (instruction.operands[0], instruction.operands[1]));
    memory_unit::set_reg_value(state, &Register::A, data);
    state.pc + instruction.size()
}

pub fn store_hl(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let addr1 = (instruction.operands[0],instruction.operands[1]);
    let addr2 = arithmetic_logic_unit::double_add(addr1, (0x00, 0x01)).0;

    let reg_value = memory_unit::get_double_reg_value(state, &Register::H);

    memory_unit::set_mem_value(state, addr1, reg_value.1);
    memory_unit::set_mem_value(state, addr2, reg_value.0);

    state.pc + instruction.size()
}

pub fn load_hl(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let addr1 = (instruction.operands[0],instruction.operands[1]);
    let addr2 = arithmetic_logic_unit::double_add(addr1, (0x00, 0x01)).0;

    let addr1_value = memory_unit::get_mem_value(state, addr1);
    let addr2_value = memory_unit::get_mem_value(state, addr2);

    memory_unit::set_double_reg_value(state, &Register::H, (addr2_value, addr1_value));

    state.pc + instruction.size()
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::architecture::model::opcodes::OpCode;

    #[test]
    fn test_store_accumulator() {
        let index:usize = 0x0020;
        let mut memory: Vec<u8> = vec![0;100];
        let value:u8 = 0x1c;
        let mut state = State {a: value, memory,..Default::default()};
        let instruction = &Instruction{opcode:OpCode::STA,operands:vec![0x00, 0x20],..Default::default()};

        let result = store_accumulator(&mut state, instruction);
        assert_eq!(result, 3);
        assert_eq!(state.memory[index], value);
        assert_eq!(state.a, value);
    }

    #[test]
    fn test_load_accumulator() {
        let index:usize = 0x0020;
        let mut memory: Vec<u8> = vec![0;100];
        let value:u8 = 0x1c;
        memory[index] = value;
        let mut state = State {memory,..Default::default()};
        let instruction = &Instruction{opcode:OpCode::LDA,operands:vec![0x00, 0x20],..Default::default()};

        let result = load_accumulator(&mut state, instruction);
        assert_eq!(result, 3);
        assert_eq!(state.memory[index], value);
        assert_eq!(state.a, value);
    }

    #[test]
    fn test_store_hl() {
        let index:usize = 0x0020;
        let mut memory: Vec<u8> = vec![0;100];
        let value1:u8 = 0x1c;
        let value2:u8 = 0x11;
        let mut state = State {h: value2, l: value1, memory,..Default::default()};
        let instruction = &Instruction{opcode:OpCode::SHLD,operands:vec![0x00, 0x20],..Default::default()};

        let result = store_hl(&mut state, instruction);
        assert_eq!(result, 3);
        assert_eq!(state.memory[index], value1);
        assert_eq!(state.memory[index+1], value2);
    }

    #[test]
    fn test_load_hl() {
        let index:usize = 0x0020;
        let mut memory: Vec<u8> = vec![0;100];
        let value1:u8 = 0x1c;
        let value2:u8 = 0x11;

        memory[index] = value1;
        memory[index + 1] = value2;

        let mut state = State {memory,..Default::default()};
        let instruction = &Instruction{opcode:OpCode::LHLD,operands:vec![0x00, 0x20],..Default::default()};

        let result = load_hl(&mut state, instruction);
        assert_eq!(result, 3);
        assert_eq!(state.memory[index], value1);
        assert_eq!(state.memory[index+1], value2);
        assert_eq!(state.l, value1);
        assert_eq!(state.h, value2);
    }
}<file_sep>extern crate strum;
extern crate strum_macros;

use strum_macros::Display;

#[derive(Display, Debug, Eq, PartialEq)]
pub enum OpCode {
    NOP,
    LXI,
    STAX,
    INX,
    INR,
    DCR,
    MVI,
    RLC,
    DAD,
    LDAX,
    DCX,
    RRC,
    RAL,
    RAR,
    SHLD,
    DAA,
    LHLD,
    CMA,
    STA,
    STC,
    LDA,
    CMC,
    MOV,
    HLT,
    ADD,
    ADC,
    SUB,
    SBB,
    ANA,
    XRA,
    ORA,
    CMP,
    RNZ,
    POP,
    JNZ,
    JMP,
    CNZ,
    PUSH,
    ADI,
    RST,
    RZ,
    RET,
    JZ,
    CZ,
    CALL,
    ACI,
    RNC,
    JNC,
    OUT,
    CNC,
    SUI,
    RC,
    JC,
    IN,
    CC,
    SBI,
    RPO,
    JPO,
    XTHL,
    CPO,
    ANI,
    RPE,
    PCHL,
    JPE,
    XCHG,
    CPE,
    XRI,
    RP,
    JP,
    DI,
    CP,
    ORI,
    RM,
    SPHL,
    JM,
    EI,
    CM,
    CPI,
}<file_sep>use crate::architecture::model::state::State;
use crate::architecture::model::instruction::Instruction;

type AddressPtr = usize;
type ExecutionStep = fn(&mut State, &Instruction) -> AddressPtr;

pub struct IoSignal {
    device: u8,
    signal: u8
}

pub mod instruction_set;
pub mod instructions;
pub mod units;
pub mod cpu_context;
pub mod devices;
pub mod model;<file_sep>use crate::architecture::model::condition_codes::ConditionCodes;

pub fn add(num1: u8, num2:u8) -> (u8, ConditionCodes) {
    let mut conditions = ConditionCodes{..Default::default()};

    let sum = (num1 as u16) + (num2 as u16);

    conditions.z = (sum & 0xff) == 0;
    conditions.s = (sum & 0x80) > 0;
    conditions.cy = sum > 0xff;
    conditions.p = compute_parity(sum as u8);
    conditions.ac = (num1 < 0x80 && num2 < 0x80) && sum >= 0x80;

    (sum as u8, conditions)
}

pub fn double_add(num1: (u8,u8), num2:(u8,u8)) -> ((u8,u8), ConditionCodes) {
    let mut conditions = ConditionCodes{..Default::default()};

    let sum = (u8_to_u16(num1.0, num1.1) as u32) + (u8_to_u16(num2.0, num2.1) as u32);

    let split_sum = u16_to_u8(sum as u16);

    conditions.z = (sum & 0xffff) == 0;
    conditions.s = (sum & 0x8000) > 0;
    conditions.cy = sum > 0xffff;
    conditions.p = compute_parity_u16(split_sum);
    conditions.ac = (num1.1 < 0x80 && num2.1 < 0x80) && sum >= 0x8000;

    (split_sum, conditions)
}

pub fn u8_to_u16(num1: u8, num2: u8) -> u16 {
    ((num1 as u16) << 8) | num2 as u16
}

pub fn u16_to_u8(num: u16) -> (u8,u8) {
    let num1 = ((num >> 8) & 0xff) as u8;
    let num2 = (num & 0xff) as u8;
    (num1,num2)
}

pub fn sub(num1: u8, num2: u8) -> (u8, ConditionCodes) {
    let mut result = add(num1, twos_complement(num2));
    result.1.cy = !result.1.cy;

    result
}

pub fn double_sub(num1: (u8,u8), num2:(u8,u8)) -> ((u8,u8), ConditionCodes) {
    let mut result = double_add(num1, twos_complement_16(num2));
    result.1.cy = !result.1.cy;

    result
}

pub fn compare(num1: u8, num2: u8) -> (u8, ConditionCodes) {
    sub(num1, num2)
}

pub fn ones_complement(num: u8) -> u8 {
    num ^ 0xff
}

pub fn twos_complement(num: u8) -> u8 {
    add(ones_complement(num), 1).0
}

pub fn ones_complement_16(num: (u8,u8)) -> (u8,u8) {
    (num.0 ^ 0xff, num.1 ^ 0xff)
}

pub fn twos_complement_16(num: (u8,u8)) -> (u8,u8) {
    double_add(ones_complement_16(num), (0,1)).0
}

pub fn compute_parity(x: u8) -> bool {
    let mut y = x ^ (x >> 1);
    y = y ^ (y >> 2);
    y = y ^ (y >> 4);
    y % 2 == 0
}

pub fn compute_parity_u16(num: (u8,u8)) -> bool {
    let num1 = compute_parity(num.0);
    let num2 = compute_parity(num.1);
    !(num1 ^ num2)
}

pub fn and(num1: u8, num2: u8) -> (u8, ConditionCodes) {
    let mut conditions = ConditionCodes{..Default::default()};
    let result = num1 & num2;
    conditions.cy = false;
    conditions.z = result == 0;
    conditions.p = compute_parity(result);
    conditions.s = result > 127;

    (result, conditions)
}

pub fn xor(num1: u8, num2: u8) -> (u8, ConditionCodes) {
    let mut conditions = ConditionCodes{..Default::default()};
    let result = num1 ^ num2;
    conditions.cy = false;
    conditions.z = result == 0;
    conditions.p = compute_parity(result);
    conditions.s = result > 127;

    (result, conditions)
}

pub fn or(num1: u8, num2: u8) -> (u8, ConditionCodes) {
    let mut conditions = ConditionCodes{..Default::default()};
    let result = num1 | num2;
    conditions.cy = false;
    conditions.z = result == 0;
    conditions.p = compute_parity(result);
    conditions.s = result > 127;

    (result, conditions)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_add_zero() {
        let result = add(0x00,0x00);
        assert_eq!(result.0, 0x00);
        assert_eq!(result.1, ConditionCodes{z: true,s: false,p: true,cy: false,ac: false});
    }

    #[test]
    fn test_add_non_zero() {
        let result = add(0x05,0x03);
        assert_eq!(result.0, 0x08);
        assert_eq!(result.1, ConditionCodes{z: false,s: false,p: false,cy: false,ac: false});
    }

    #[test]
    fn test_add_carry_max() {
        let result = add(0x7f,0x01);
        assert_eq!(result.0, 0x80);
        assert_eq!(result.1, ConditionCodes{z: false,s: true,p: false,cy: false,ac: true});
    }

    #[test]
    fn test_add_carry_min() {
        let result = add(0x80,0xff);
        assert_eq!(result.0, 0x7f);
        assert_eq!(result.1, ConditionCodes{z: false,s: false,p: false,cy: true,ac: false});
    }

    #[test]
    fn test_negatives() {
        let result = add(0xf6,0xff);
        assert_eq!(result.0, 0xf5);
        assert_eq!(result.1, ConditionCodes{z: false,s: true,p: true,cy: true,ac: false});
    }

    #[test]
    fn test_with_example_in_manual() {
        let result = add(0x2e,0x6c);
        assert_eq!(result.0, 0x9a);
        assert_eq!(result.1, ConditionCodes{z: false,s: true,p: true,cy: false,ac: true});
    }

    #[test]
    fn test_parity_odd() {
        let result = compute_parity(0x1);
        assert_eq!(result, false);
    }

    #[test]
    fn test_parity_even() {
        let result = compute_parity(0x3);
        assert_eq!(result, true);
    }

    #[test]
    fn test_ones_complement() {
        let result = ones_complement(0x3e);
        assert_eq!(result, 0xc1);
    }

    #[test]
    fn test_twos_complement() {
        let result = twos_complement(0x3e);
        assert_eq!(result, 0xc2);
    }

    #[test]
    fn test_sub_both_positive() {
        let result = sub(0x03, 0x01);
        assert_eq!(result.0, 0x02);
        assert_eq!(result.1, ConditionCodes{z: false,s: false,p: false,cy: false,ac: false});
    }

    #[test]
    fn test_sub_neg() {
        let result = sub(0x03, 0xf6);
        assert_eq!(result.0, 0x0d);
        assert_eq!(result.1, ConditionCodes{z: false,s: false,p: false,cy: true,ac: false});
    }

    #[test]
    fn test_sub_from_neg() {
        let result = sub(0xf6, 0x01);
        assert_eq!(result.0, 0xf5);
        assert_eq!(result.1, ConditionCodes{z: false,s: true,p: true,cy: false,ac: false});
    }

    #[test]
    fn test_sub_with_example_in_manual() {
        let result = sub(0x3e, 0x3e);
        assert_eq!(result.0, 0);
        assert_eq!(result.1, ConditionCodes{z: true,s: false,p: true,cy: false,ac: false});
    }

    #[test]
    fn test_compare_with_example_in_manual() {
        let result = compare(0x4a, 0x40);
        assert_eq!(result.0, 0x0a);
        assert_eq!(result.1, ConditionCodes{z: false,s: false,p: true,cy: false,ac: false});
    }
}<file_sep>use crate::architecture::instruction_set;
use crate::architecture::model::condition_codes::ConditionCodes;
use crate::architecture::model::state::State;
use crate::disassembler::parser;
use crate::architecture::units::io_unit;

pub struct CpuContext {
    pub state: State
}

impl CpuContext {

    pub fn load_program(program: &str, mem_size: usize) -> CpuContext {
        let program_in_bytes = parser::parse(program, mem_size).unwrap();

        let state = State{
            memory: program_in_bytes,
            cc: ConditionCodes {
                z: true,
                s: true,
                p: true,
                cy: true,
                ac: true
            },
            ..Default::default()
        };

        println!("Set memory to: {}", state.memory.capacity());

        CpuContext{
            state
        }
    }

    pub fn run(&mut self){
        self.state.nc = self.state.pc;
        self.state.pc = self.state.nc + 1;

        while self.still_running() {
            self.cycle()
        }
    }

    fn still_running(&self) -> bool {
        self.state.pc < self.state.memory.len() && self.state.nc != self.state.pc
    }

    // TODO: Determine how many cycles each step takes & potentially add a "cycles remaining" param to each instruction
    //       Really just need to figure out how to get proper timings....
    fn cycle(&mut self){
        // TODO
        // 1. Check input queue and update accordingly (ex: interrupts, etc.)

        // 2. Execute instructions
        self.state.pc = self.state.nc;
        let instr = instruction_set::read_next(&self.state.memory, self.state.pc);
        //self.state.debug(instr.to_string());
        self.state.nc = instr.execute(&mut self.state);

        // 3. Execute any output queue instructions
        match self.state.output_queue.pop() {
            Some(os) => (io_unit::get_output_handler(os.device).handle(&mut self.state, os)),
            None => ()
        }
    }
}<file_sep>use crate::architecture::model::state::State;
use crate::architecture::model::registers::Register;
use crate::architecture::units::arithmetic_logic_unit;

pub fn get_reg_value(state: &State, reg: &Register) -> u8 {
    match reg {
        Register::A => state.a,
        Register::B => state.b,
        Register::C => state.c,
        Register::D => state.d,
        Register::E => state.e,
        Register::H => state.h,
        Register::L => state.l,
        Register::M => get_mem_value(state, (state.h, state.l)),
        _ => 0
    }
}

pub fn get_double_reg_value(state: &State, reg: &Register) -> (u8,u8) {
    match reg {
        Register::B => (state.b, state.c),
        Register::D => (state.d, state.e),
        Register::H => (state.h, state.l),
        Register::PSW => (state.a, state.cc.as_binary()),
        Register::SP => arithmetic_logic_unit::u16_to_u8(state.sp as u16),
        _ => (0,0)
    }
}

pub fn set_double_reg_value(state: &mut State, reg: &Register, value: (u8,u8)) {
    match reg {
        Register::B => {state.b = value.0; state.c = value.1; },
        Register::D => {state.d = value.0; state.e = value.1; },
        Register::H => {state.h = value.0; state.l = value.1; },
        Register::PSW => {state.a = value.0; state.cc.update_from_binary(value.1); },
        Register::SP => {
            state.sp = arithmetic_logic_unit::u8_to_u16(value.0, value.1) as usize;
        },
        _ => ()
    };
}

pub fn get_mem_value(state: &State, loc: (u8, u8)) -> u8 {
    let addr = ((loc.0 as u16) << 8) | loc.1 as u16;
    state.memory[addr as usize]
}

pub fn set_mem_value(state: &mut State, loc: (u8, u8), value: u8) {
    let addr = ((loc.0 as u16) << 8) | loc.1 as u16;
    state.memory[addr as usize] = value;
}

pub fn get_reg_mem_value(state: &State, reg: &Register) -> u8 {
    let addr = get_double_reg_value(state, reg);
    get_mem_value(state, addr)
}

pub fn set_reg_mem_value(state: &mut State, reg: &Register, value: u8) {
    let addr = match reg {
        Register::B => (state.b, state.c),
        Register::D => (state.d, state.e),
        Register::H => (state.h, state.l),
        _ => (0,0),
    };

    set_mem_value(state, addr, value)
}

pub fn set_reg_value(state: &mut State, reg: &Register, value: u8) {
    match reg {
        Register::A => state.a = value,
        Register::B => state.b = value,
        Register::C => state.c = value,
        Register::D => state.d = value,
        Register::E => state.e = value,
        Register::H => state.h = value,
        Register::L => state.l = value,
        Register::M => set_mem_value(state, (state.h, state.l), value),
        _ => ()
    }
}

pub fn set_mem_loc_in_reg(state: &mut State, reg: &Register, data: &Vec<u8>) {
    match reg {
        Register::B => {
            state.b = data[0];
            state.c = data[1];
        },
        Register::D => {
            state.d = data[0];
            state.c = data[1];
        },
        Register::H => {
            state.h = data[0];
            state.l = data[1];
        },
        Register::SP => {
            state.sp = (((data[0] as u16) << 8) | data[1] as u16) as usize;
        },
        _ => ()
    };
}
<file_sep>use crate::architecture::model::state::State;
use crate::architecture::model::instruction::Instruction;
use crate::architecture::units::stack;
use crate::architecture::units::arithmetic_logic_unit;
use crate::architecture::AddressPtr;

pub fn default(state: &mut State, instruction: &Instruction) -> AddressPtr {

    match instruction.opcode.to_string().chars().next() {
        Some('C') => {
            let ret:u16 = (state.pc + instruction.size()) as u16;
            println!("Setting return address: {:04x}", ret);
            stack::push_return_addr(state, ret);
            arithmetic_logic_unit::u8_to_u16(instruction.operands[0], instruction.operands[1]) as usize
        },
        Some('J') => {
            arithmetic_logic_unit::u8_to_u16(instruction.operands[0], instruction.operands[1]) as usize
        },
        Some('R') => {
            let ret:u16 = stack::pop_return_addr(state);
            println!("Getting return address: {:04x}", ret);
            ret as usize
        },
        _ => (state.pc)
    }
}

fn condition(state: &mut State, instruction: &Instruction, expected_condition: bool) -> AddressPtr {
    if expected_condition {
        default(state, instruction)
    }else{
        state.pc + instruction.size()
    }
}

pub fn carry(state: &mut State, instruction: &Instruction) -> AddressPtr {
    condition(state, instruction, state.cc.cy)
}

pub fn no_carry(state: &mut State, instruction: &Instruction) -> AddressPtr {
    condition(state, instruction, !state.cc.cy)
}

pub fn zero(state: &mut State, instruction: &Instruction) -> AddressPtr {
    condition(state, instruction, state.cc.z)
}

pub fn no_zero(state: &mut State, instruction: &Instruction) -> AddressPtr {
    condition(state, instruction, !state.cc.z)
}

pub fn minus(state: &mut State, instruction: &Instruction) -> AddressPtr {
    condition(state, instruction, state.cc.s)
}

pub fn positive(state: &mut State, instruction: &Instruction) -> AddressPtr {
    condition(state, instruction, !state.cc.s)
}

pub fn parity_even(state: &mut State, instruction: &Instruction) -> AddressPtr {
    condition(state, instruction, state.cc.p)
}

pub fn parity_odd(state: &mut State, instruction: &Instruction) -> AddressPtr {
    condition(state, instruction, !state.cc.p)
}

pub fn load_pc(state: &mut State, instruction: &Instruction) -> AddressPtr {
    println!("ERROR: {} has not been implemented!", instruction.to_string());
    state.pc
}<file_sep>pub mod architecture;
pub mod disassembler;<file_sep>use std::fs::File;
use std::io::Read;
use std::io;

pub fn parse(filename: &str, mem_size: usize) -> io::Result<(Vec<u8>)> {
    let mut file=File::open(filename).unwrap();
    let mut memory = vec![0; mem_size];
    let mut program: Vec<u8> = vec![];

    file.read_to_end(&mut program)?;

    //TODO: find a cleaner way to do this
    for i in 0..program.len() {
        memory[i] = program[i];
    }

    Ok(memory)
}<file_sep>use crate::architecture::model::instruction::Instruction;
use crate::architecture::model::opcodes::OpCode;
use crate::architecture::model::registers::Register;

pub fn read_next(buf: &Vec<u8>, ix: usize) -> Instruction {
    let code = buf[ix];

    match code {
        0x00 => Instruction{ opcode: OpCode::NOP, register: vec![], operands: vec![] },
        0x01 => Instruction{ opcode: OpCode::LXI, register: vec![Register::B], operands: vec![buf[ix+2],buf[ix+1]] },
        0x02 => Instruction{ opcode: OpCode::STAX, register: vec![Register::B], operands: vec![] },
        0x03 => Instruction{ opcode: OpCode::INX, register: vec![Register::B], operands: vec![] },
        0x04 => Instruction{ opcode: OpCode::INR, register: vec![Register::B], operands: vec![] },
        0x05 => Instruction{ opcode: OpCode::DCR, register: vec![Register::B], operands: vec![] },
        0x06 => Instruction{ opcode: OpCode::MVI, register: vec![Register::B], operands: vec![buf[ix+1]] },
        0x07 => Instruction{ opcode: OpCode::RLC, register: vec![], operands: vec![] },
        0x08 => Instruction{ opcode: OpCode::NOP, register: vec![], operands: vec![] },
        0x09 => Instruction{ opcode: OpCode::DAD, register: vec![Register::B], operands: vec![] },
        0x0a => Instruction{ opcode: OpCode::LDAX, register: vec![Register::B], operands: vec![] },
        0x0b => Instruction{ opcode: OpCode::DCX, register: vec![Register::B], operands: vec![] },
        0x0c => Instruction{ opcode: OpCode::INR, register: vec![Register::C], operands: vec![] },
        0x0d => Instruction{ opcode: OpCode::DCR, register: vec![Register::C], operands: vec![] },
        0x0e => Instruction{ opcode: OpCode::MVI, register: vec![Register::C], operands: vec![buf[ix+1]] },
        0x0f => Instruction{ opcode: OpCode::RRC, register: vec![], operands: vec![] },
        0x10 => Instruction{ opcode: OpCode::NOP, register: vec![], operands: vec![] },
        0x11 => Instruction{ opcode: OpCode::LXI, register: vec![Register::D], operands: vec![buf[ix+2],buf[ix+1]] },
        0x12 => Instruction{ opcode: OpCode::STAX, register: vec![Register::D], operands: vec![] },
        0x13 => Instruction{ opcode: OpCode::INX, register: vec![Register::D], operands: vec![] },
        0x14 => Instruction{ opcode: OpCode::INR, register: vec![Register::D], operands: vec![] },
        0x15 => Instruction{ opcode: OpCode::DCR, register: vec![Register::D], operands: vec![] },
        0x16 => Instruction{ opcode: OpCode::MVI, register: vec![Register::D], operands: vec![buf[ix+1]] },
        0x17 => Instruction{ opcode: OpCode::RAL, register: vec![], operands: vec![] },
        0x18 => Instruction{ opcode: OpCode::NOP, register: vec![], operands: vec![] },
        0x19 => Instruction{ opcode: OpCode::DAD, register: vec![Register::D], operands: vec![] },
        0x1a => Instruction{ opcode: OpCode::LDAX, register: vec![Register::D], operands: vec![] },
        0x1b => Instruction{ opcode: OpCode::DCX, register: vec![Register::D], operands: vec![] },
        0x1c => Instruction{ opcode: OpCode::INR, register: vec![Register::E], operands: vec![] },
        0x1d => Instruction{ opcode: OpCode::DCR, register: vec![Register::E], operands: vec![] },
        0x1e => Instruction{ opcode: OpCode::MVI, register: vec![Register::E], operands: vec![buf[ix+1]] },
        0x1f => Instruction{ opcode: OpCode::RAR, register: vec![], operands: vec![] },
        0x20 => Instruction{ opcode: OpCode::NOP, register: vec![], operands: vec![] },
        0x21 => Instruction{ opcode: OpCode::LXI, register: vec![Register::H], operands: vec![buf[ix+2],buf[ix+1]] },
        0x22 => Instruction{ opcode: OpCode::SHLD, register: vec![], operands: vec![buf[ix+2],buf[ix+1]] },
        0x23 => Instruction{ opcode: OpCode::INX, register: vec![Register::H], operands: vec![] },
        0x24 => Instruction{ opcode: OpCode::INR, register: vec![Register::H], operands: vec![] },
        0x25 => Instruction{ opcode: OpCode::DCR, register: vec![Register::H], operands: vec![] },
        0x26 => Instruction{ opcode: OpCode::MVI, register: vec![Register::H], operands: vec![buf[ix+1]] },
        0x27 => Instruction{ opcode: OpCode::DAA, register: vec![], operands: vec![] },
        0x28 => Instruction{ opcode: OpCode::NOP, register: vec![], operands: vec![] },
        0x29 => Instruction{ opcode: OpCode::DAD, register: vec![Register::H], operands: vec![] },
        0x2a => Instruction{ opcode: OpCode::LHLD, register: vec![], operands: vec![buf[ix+2],buf[ix+1]] },
        0x2b => Instruction{ opcode: OpCode::DCX, register: vec![Register::H], operands: vec![] },
        0x2c => Instruction{ opcode: OpCode::INR, register: vec![Register::L], operands: vec![] },
        0x2d => Instruction{ opcode: OpCode::DCR, register: vec![Register::L], operands: vec![] },
        0x2e => Instruction{ opcode: OpCode::MVI, register: vec![Register::L], operands: vec![buf[ix+1]] },
        0x2f => Instruction{ opcode: OpCode::CMA, register: vec![], operands: vec![] },
        0x30 => Instruction{ opcode: OpCode::NOP, register: vec![], operands: vec![] },
        0x31 => Instruction{ opcode: OpCode::LXI, register: vec![Register::SP], operands: vec![buf[ix+2],buf[ix+1]] },
        0x32 => Instruction{ opcode: OpCode::STA, register: vec![], operands: vec![buf[ix+2],buf[ix+1]] },
        0x33 => Instruction{ opcode: OpCode::INX, register: vec![Register::SP], operands: vec![] },
        0x34 => Instruction{ opcode: OpCode::INR, register: vec![Register::M], operands: vec![] },
        0x35 => Instruction{ opcode: OpCode::DCR, register: vec![Register::M], operands: vec![] },
        0x36 => Instruction{ opcode: OpCode::MVI, register: vec![Register::M], operands: vec![buf[ix+1]] },
        0x37 => Instruction{ opcode: OpCode::STC, register: vec![], operands: vec![] },
        0x38 => Instruction{ opcode: OpCode::NOP, register: vec![], operands: vec![] },
        0x39 => Instruction{ opcode: OpCode::DAD, register: vec![Register::SP], operands: vec![] },
        0x3a => Instruction{ opcode: OpCode::LDA, register: vec![], operands: vec![buf[ix+2],buf[ix+1]] },
        0x3b => Instruction{ opcode: OpCode::DCX, register: vec![Register::SP], operands: vec![] },
        0x3c => Instruction{ opcode: OpCode::INR, register: vec![Register::A], operands: vec![] },
        0x3d => Instruction{ opcode: OpCode::DCR, register: vec![Register::A], operands: vec![] },
        0x3e => Instruction{ opcode: OpCode::MVI, register: vec![Register::A], operands: vec![buf[ix+1]] },
        0x3f => Instruction{ opcode: OpCode::CMC, register: vec![], operands: vec![] },
        0x40 => Instruction{ opcode: OpCode::MOV, register: vec![Register::B,Register::B], operands: vec![] },
        0x41 => Instruction{ opcode: OpCode::MOV, register: vec![Register::B,Register::C], operands: vec![] },
        0x42 => Instruction{ opcode: OpCode::MOV, register: vec![Register::B,Register::D], operands: vec![] },
        0x43 => Instruction{ opcode: OpCode::MOV, register: vec![Register::B,Register::E], operands: vec![] },
        0x44 => Instruction{ opcode: OpCode::MOV, register: vec![Register::B,Register::H], operands: vec![] },
        0x45 => Instruction{ opcode: OpCode::MOV, register: vec![Register::B,Register::L], operands: vec![] },
        0x46 => Instruction{ opcode: OpCode::MOV, register: vec![Register::B,Register::M], operands: vec![] },
        0x47 => Instruction{ opcode: OpCode::MOV, register: vec![Register::B,Register::A], operands: vec![] },
        0x48 => Instruction{ opcode: OpCode::MOV, register: vec![Register::C,Register::B], operands: vec![] },
        0x49 => Instruction{ opcode: OpCode::MOV, register: vec![Register::C,Register::C], operands: vec![] },
        0x4a => Instruction{ opcode: OpCode::MOV, register: vec![Register::C,Register::D], operands: vec![] },
        0x4b => Instruction{ opcode: OpCode::MOV, register: vec![Register::C,Register::E], operands: vec![] },
        0x4c => Instruction{ opcode: OpCode::MOV, register: vec![Register::C,Register::H], operands: vec![] },
        0x4d => Instruction{ opcode: OpCode::MOV, register: vec![Register::C,Register::L], operands: vec![] },
        0x4e => Instruction{ opcode: OpCode::MOV, register: vec![Register::C,Register::M], operands: vec![] },
        0x4f => Instruction{ opcode: OpCode::MOV, register: vec![Register::C,Register::A], operands: vec![] },
        0x50 => Instruction{ opcode: OpCode::MOV, register: vec![Register::D,Register::B], operands: vec![] },
        0x51 => Instruction{ opcode: OpCode::MOV, register: vec![Register::D,Register::C], operands: vec![] },
        0x52 => Instruction{ opcode: OpCode::MOV, register: vec![Register::D,Register::D], operands: vec![] },
        0x53 => Instruction{ opcode: OpCode::MOV, register: vec![Register::D,Register::E], operands: vec![] },
        0x54 => Instruction{ opcode: OpCode::MOV, register: vec![Register::D,Register::H], operands: vec![] },
        0x55 => Instruction{ opcode: OpCode::MOV, register: vec![Register::D,Register::L], operands: vec![] },
        0x56 => Instruction{ opcode: OpCode::MOV, register: vec![Register::D,Register::M], operands: vec![] },
        0x57 => Instruction{ opcode: OpCode::MOV, register: vec![Register::D,Register::A], operands: vec![] },
        0x58 => Instruction{ opcode: OpCode::MOV, register: vec![Register::E,Register::B], operands: vec![] },
        0x59 => Instruction{ opcode: OpCode::MOV, register: vec![Register::E,Register::C], operands: vec![] },
        0x5a => Instruction{ opcode: OpCode::MOV, register: vec![Register::E,Register::D], operands: vec![] },
        0x5b => Instruction{ opcode: OpCode::MOV, register: vec![Register::E,Register::E], operands: vec![] },
        0x5c => Instruction{ opcode: OpCode::MOV, register: vec![Register::E,Register::H], operands: vec![] },
        0x5d => Instruction{ opcode: OpCode::MOV, register: vec![Register::E,Register::L], operands: vec![] },
        0x5e => Instruction{ opcode: OpCode::MOV, register: vec![Register::E,Register::M], operands: vec![] },
        0x5f => Instruction{ opcode: OpCode::MOV, register: vec![Register::E,Register::A], operands: vec![] },
        0x60 => Instruction{ opcode: OpCode::MOV, register: vec![Register::H,Register::B], operands: vec![] },
        0x61 => Instruction{ opcode: OpCode::MOV, register: vec![Register::H,Register::C], operands: vec![] },
        0x62 => Instruction{ opcode: OpCode::MOV, register: vec![Register::H,Register::D], operands: vec![] },
        0x63 => Instruction{ opcode: OpCode::MOV, register: vec![Register::H,Register::E], operands: vec![] },
        0x64 => Instruction{ opcode: OpCode::MOV, register: vec![Register::H,Register::H], operands: vec![] },
        0x65 => Instruction{ opcode: OpCode::MOV, register: vec![Register::H,Register::L], operands: vec![] },
        0x66 => Instruction{ opcode: OpCode::MOV, register: vec![Register::H,Register::M], operands: vec![] },
        0x67 => Instruction{ opcode: OpCode::MOV, register: vec![Register::H,Register::A], operands: vec![] },
        0x68 => Instruction{ opcode: OpCode::MOV, register: vec![Register::L,Register::B], operands: vec![] },
        0x69 => Instruction{ opcode: OpCode::MOV, register: vec![Register::L,Register::C], operands: vec![] },
        0x6a => Instruction{ opcode: OpCode::MOV, register: vec![Register::L,Register::D], operands: vec![] },
        0x6b => Instruction{ opcode: OpCode::MOV, register: vec![Register::L,Register::E], operands: vec![] },
        0x6c => Instruction{ opcode: OpCode::MOV, register: vec![Register::L,Register::H], operands: vec![] },
        0x6d => Instruction{ opcode: OpCode::MOV, register: vec![Register::L,Register::L], operands: vec![] },
        0x6e => Instruction{ opcode: OpCode::MOV, register: vec![Register::L,Register::M], operands: vec![] },
        0x6f => Instruction{ opcode: OpCode::MOV, register: vec![Register::L,Register::A], operands: vec![] },
        0x70 => Instruction{ opcode: OpCode::MOV, register: vec![Register::M,Register::B], operands: vec![] },
        0x71 => Instruction{ opcode: OpCode::MOV, register: vec![Register::M,Register::C], operands: vec![] },
        0x72 => Instruction{ opcode: OpCode::MOV, register: vec![Register::M,Register::D], operands: vec![] },
        0x73 => Instruction{ opcode: OpCode::MOV, register: vec![Register::M,Register::E], operands: vec![] },
        0x74 => Instruction{ opcode: OpCode::MOV, register: vec![Register::M,Register::H], operands: vec![] },
        0x75 => Instruction{ opcode: OpCode::MOV, register: vec![Register::M,Register::L], operands: vec![] },
        0x76 => Instruction{ opcode: OpCode::HLT, register: vec![], operands: vec![] },
        0x77 => Instruction{ opcode: OpCode::MOV, register: vec![Register::M,Register::A], operands: vec![] },
        0x78 => Instruction{ opcode: OpCode::MOV, register: vec![Register::A,Register::B], operands: vec![] },
        0x79 => Instruction{ opcode: OpCode::MOV, register: vec![Register::A,Register::C], operands: vec![] },
        0x7a => Instruction{ opcode: OpCode::MOV, register: vec![Register::A,Register::D], operands: vec![] },
        0x7b => Instruction{ opcode: OpCode::MOV, register: vec![Register::A,Register::E], operands: vec![] },
        0x7c => Instruction{ opcode: OpCode::MOV, register: vec![Register::A,Register::H], operands: vec![] },
        0x7d => Instruction{ opcode: OpCode::MOV, register: vec![Register::A,Register::L], operands: vec![] },
        0x7e => Instruction{ opcode: OpCode::MOV, register: vec![Register::A,Register::M], operands: vec![] },
        0x7f => Instruction{ opcode: OpCode::MOV, register: vec![Register::A,Register::A], operands: vec![] },
        0x80 => Instruction{ opcode: OpCode::ADD, register: vec![Register::B], operands: vec![] },
        0x81 => Instruction{ opcode: OpCode::ADD, register: vec![Register::C], operands: vec![] },
        0x82 => Instruction{ opcode: OpCode::ADD, register: vec![Register::D], operands: vec![] },
        0x83 => Instruction{ opcode: OpCode::ADD, register: vec![Register::E], operands: vec![] },
        0x84 => Instruction{ opcode: OpCode::ADD, register: vec![Register::H], operands: vec![] },
        0x85 => Instruction{ opcode: OpCode::ADD, register: vec![Register::L], operands: vec![] },
        0x86 => Instruction{ opcode: OpCode::ADD, register: vec![Register::M], operands: vec![] },
        0x87 => Instruction{ opcode: OpCode::ADD, register: vec![Register::A], operands: vec![] },
        0x88 => Instruction{ opcode: OpCode::ADC, register: vec![Register::B], operands: vec![] },
        0x89 => Instruction{ opcode: OpCode::ADC, register: vec![Register::C], operands: vec![] },
        0x8a => Instruction{ opcode: OpCode::ADC, register: vec![Register::D], operands: vec![] },
        0x8b => Instruction{ opcode: OpCode::ADC, register: vec![Register::E], operands: vec![] },
        0x8c => Instruction{ opcode: OpCode::ADC, register: vec![Register::H], operands: vec![] },
        0x8d => Instruction{ opcode: OpCode::ADC, register: vec![Register::L], operands: vec![] },
        0x8e => Instruction{ opcode: OpCode::ADC, register: vec![Register::M], operands: vec![] },
        0x8f => Instruction{ opcode: OpCode::ADC, register: vec![Register::A], operands: vec![] },
        0x90 => Instruction{ opcode: OpCode::SUB, register: vec![Register::B], operands: vec![] },
        0x91 => Instruction{ opcode: OpCode::SUB, register: vec![Register::C], operands: vec![] },
        0x92 => Instruction{ opcode: OpCode::SUB, register: vec![Register::D], operands: vec![] },
        0x93 => Instruction{ opcode: OpCode::SUB, register: vec![Register::E], operands: vec![] },
        0x94 => Instruction{ opcode: OpCode::SUB, register: vec![Register::H], operands: vec![] },
        0x95 => Instruction{ opcode: OpCode::SUB, register: vec![Register::L], operands: vec![] },
        0x96 => Instruction{ opcode: OpCode::SUB, register: vec![Register::M], operands: vec![] },
        0x97 => Instruction{ opcode: OpCode::SUB, register: vec![Register::A], operands: vec![] },
        0x98 => Instruction{ opcode: OpCode::SBB, register: vec![Register::B], operands: vec![] },
        0x99 => Instruction{ opcode: OpCode::SBB, register: vec![Register::C], operands: vec![] },
        0x9a => Instruction{ opcode: OpCode::SBB, register: vec![Register::D], operands: vec![] },
        0x9b => Instruction{ opcode: OpCode::SBB, register: vec![Register::E], operands: vec![] },
        0x9c => Instruction{ opcode: OpCode::SBB, register: vec![Register::H], operands: vec![] },
        0x9d => Instruction{ opcode: OpCode::SBB, register: vec![Register::L], operands: vec![] },
        0x9e => Instruction{ opcode: OpCode::SBB, register: vec![Register::M], operands: vec![] },
        0x9f => Instruction{ opcode: OpCode::SBB, register: vec![Register::A], operands: vec![] },
        0xa0 => Instruction{ opcode: OpCode::ANA, register: vec![Register::B], operands: vec![] },
        0xa1 => Instruction{ opcode: OpCode::ANA, register: vec![Register::C], operands: vec![] },
        0xa2 => Instruction{ opcode: OpCode::ANA, register: vec![Register::D], operands: vec![] },
        0xa3 => Instruction{ opcode: OpCode::ANA, register: vec![Register::E], operands: vec![] },
        0xa4 => Instruction{ opcode: OpCode::ANA, register: vec![Register::H], operands: vec![] },
        0xa5 => Instruction{ opcode: OpCode::ANA, register: vec![Register::L], operands: vec![] },
        0xa6 => Instruction{ opcode: OpCode::ANA, register: vec![Register::M], operands: vec![] },
        0xa7 => Instruction{ opcode: OpCode::ANA, register: vec![Register::A], operands: vec![] },
        0xa8 => Instruction{ opcode: OpCode::XRA, register: vec![Register::B], operands: vec![] },
        0xa9 => Instruction{ opcode: OpCode::XRA, register: vec![Register::C], operands: vec![] },
        0xaa => Instruction{ opcode: OpCode::XRA, register: vec![Register::D], operands: vec![] },
        0xab => Instruction{ opcode: OpCode::XRA, register: vec![Register::E], operands: vec![] },
        0xac => Instruction{ opcode: OpCode::XRA, register: vec![Register::H], operands: vec![] },
        0xad => Instruction{ opcode: OpCode::XRA, register: vec![Register::L], operands: vec![] },
        0xae => Instruction{ opcode: OpCode::XRA, register: vec![Register::M], operands: vec![] },
        0xaf => Instruction{ opcode: OpCode::XRA, register: vec![Register::A], operands: vec![] },
        0xb0 => Instruction{ opcode: OpCode::ORA, register: vec![Register::B], operands: vec![] },
        0xb1 => Instruction{ opcode: OpCode::ORA, register: vec![Register::C], operands: vec![] },
        0xb2 => Instruction{ opcode: OpCode::ORA, register: vec![Register::D], operands: vec![] },
        0xb3 => Instruction{ opcode: OpCode::ORA, register: vec![Register::E], operands: vec![] },
        0xb4 => Instruction{ opcode: OpCode::ORA, register: vec![Register::H], operands: vec![] },
        0xb5 => Instruction{ opcode: OpCode::ORA, register: vec![Register::L], operands: vec![] },
        0xb6 => Instruction{ opcode: OpCode::ORA, register: vec![Register::M], operands: vec![] },
        0xb7 => Instruction{ opcode: OpCode::ORA, register: vec![Register::A], operands: vec![] },
        0xb8 => Instruction{ opcode: OpCode::CMP, register: vec![Register::B], operands: vec![] },
        0xb9 => Instruction{ opcode: OpCode::CMP, register: vec![Register::C], operands: vec![] },
        0xba => Instruction{ opcode: OpCode::CMP, register: vec![Register::D], operands: vec![] },
        0xbb => Instruction{ opcode: OpCode::CMP, register: vec![Register::E], operands: vec![] },
        0xbc => Instruction{ opcode: OpCode::CMP, register: vec![Register::H], operands: vec![] },
        0xbd => Instruction{ opcode: OpCode::CMP, register: vec![Register::L], operands: vec![] },
        0xbe => Instruction{ opcode: OpCode::CMP, register: vec![Register::M], operands: vec![] },
        0xbf => Instruction{ opcode: OpCode::CMP, register: vec![Register::A], operands: vec![] },
        0xc0 => Instruction{ opcode: OpCode::RNZ, register: vec![Register::B], operands: vec![] },
        0xc1 => Instruction{ opcode: OpCode::POP, register: vec![Register::B], operands: vec![] },
        0xc2 => Instruction{ opcode: OpCode::JNZ, register: vec![], operands: vec![buf[ix+2],buf[ix+1]] },
        0xc3 => Instruction{ opcode: OpCode::JMP, register: vec![], operands: vec![buf[ix+2],buf[ix+1]] },
        0xc4 => Instruction{ opcode: OpCode::CNZ, register: vec![], operands: vec![buf[ix+2],buf[ix+1]] },
        0xc5 => Instruction{ opcode: OpCode::PUSH, register: vec![Register::B], operands: vec![] },
        0xc6 => Instruction{ opcode: OpCode::ADI, register: vec![], operands: vec![buf[ix+1]] },
        0xc7 => Instruction{ opcode: OpCode::RST, register: vec![Register::_0], operands: vec![] },
        0xc8 => Instruction{ opcode: OpCode::RZ, register: vec![], operands: vec![] },
        0xc9 => Instruction{ opcode: OpCode::RET, register: vec![], operands: vec![] },
        0xca => Instruction{ opcode: OpCode::JZ, register: vec![], operands: vec![buf[ix+2],buf[ix+1]] },
        0xcb => Instruction{ opcode: OpCode::NOP, register: vec![], operands: vec![] },
        0xcc => Instruction{ opcode: OpCode::CZ, register: vec![], operands: vec![buf[ix+2],buf[ix+1]] },
        0xcd => Instruction{ opcode: OpCode::CALL, register: vec![], operands: vec![buf[ix+2],buf[ix+1]] },
        0xce => Instruction{ opcode: OpCode::ACI, register: vec![], operands: vec![buf[ix+1]] },
        0xcf => Instruction{ opcode: OpCode::RST, register: vec![Register::_1], operands: vec![] },
        0xd0 => Instruction{ opcode: OpCode::RNC, register: vec![], operands: vec![] },
        0xd1 => Instruction{ opcode: OpCode::POP, register: vec![Register::D], operands: vec![] },
        0xd2 => Instruction{ opcode: OpCode::JNC, register: vec![], operands: vec![buf[ix+2],buf[ix+1]] },
        0xd3 => Instruction{ opcode: OpCode::OUT, register: vec![], operands: vec![buf[ix+1]] },
        0xd4 => Instruction{ opcode: OpCode::CNC, register: vec![], operands: vec![buf[ix+2],buf[ix+1]] },
        0xd5 => Instruction{ opcode: OpCode::PUSH, register: vec![Register::D], operands: vec![] },
        0xd6 => Instruction{ opcode: OpCode::SUI, register: vec![], operands: vec![buf[ix+1]] },
        0xd7 => Instruction{ opcode: OpCode::RST, register: vec![Register::_2], operands: vec![] },
        0xd8 => Instruction{ opcode: OpCode::RC, register: vec![], operands: vec![] },
        0xd9 => Instruction{ opcode: OpCode::NOP, register: vec![], operands: vec![] },
        0xda => Instruction{ opcode: OpCode::JC, register: vec![], operands: vec![buf[ix+2],buf[ix+1]] },
        0xdb => Instruction{ opcode: OpCode::IN, register: vec![], operands: vec![buf[ix+1]] },
        0xdc => Instruction{ opcode: OpCode::CC, register: vec![], operands: vec![buf[ix+2],buf[ix+1]] },
        0xdd => Instruction{ opcode: OpCode::NOP, register: vec![], operands: vec![] },
        0xde => Instruction{ opcode: OpCode::SBI, register: vec![], operands: vec![buf[ix+1]] },
        0xdf => Instruction{ opcode: OpCode::RST, register: vec![Register::_3], operands: vec![] },
        0xe0 => Instruction{ opcode: OpCode::RPO, register: vec![], operands: vec![] },
        0xe1 => Instruction{ opcode: OpCode::POP, register: vec![Register::H], operands: vec![] },
        0xe2 => Instruction{ opcode: OpCode::JPO, register: vec![], operands: vec![buf[ix+2],buf[ix+1]] },
        0xe3 => Instruction{ opcode: OpCode::XTHL, register: vec![], operands: vec![] },
        0xe4 => Instruction{ opcode: OpCode::CPO, register: vec![], operands: vec![buf[ix+2],buf[ix+1]] },
        0xe5 => Instruction{ opcode: OpCode::PUSH, register: vec![Register::H], operands: vec![] },
        0xe6 => Instruction{ opcode: OpCode::ANI, register: vec![], operands: vec![buf[ix+1]] },
        0xe7 => Instruction{ opcode: OpCode::RST, register: vec![Register::_4], operands: vec![] },
        0xe8 => Instruction{ opcode: OpCode::RPE, register: vec![], operands: vec![] },
        0xe9 => Instruction{ opcode: OpCode::PCHL, register: vec![], operands: vec![] },
        0xea => Instruction{ opcode: OpCode::JPE, register: vec![], operands: vec![buf[ix+2],buf[ix+1]] },
        0xeb => Instruction{ opcode: OpCode::XCHG, register: vec![], operands: vec![] },
        0xec => Instruction{ opcode: OpCode::CPE, register: vec![], operands: vec![buf[ix+2],buf[ix+1]] },
        0xed => Instruction{ opcode: OpCode::NOP, register: vec![], operands: vec![] },
        0xee => Instruction{ opcode: OpCode::XRI, register: vec![], operands: vec![buf[ix+1]] },
        0xef => Instruction{ opcode: OpCode::RST, register: vec![Register::_5], operands: vec![] },
        0xf0 => Instruction{ opcode: OpCode::RP, register: vec![], operands: vec![] },
        0xf1 => Instruction{ opcode: OpCode::POP, register: vec![Register::PSW], operands: vec![] },
        0xf2 => Instruction{ opcode: OpCode::JP, register: vec![], operands: vec![buf[ix+2],buf[ix+1]] },
        0xf3 => Instruction{ opcode: OpCode::DI, register: vec![], operands: vec![] },
        0xf4 => Instruction{ opcode: OpCode::CP, register: vec![], operands: vec![buf[ix+2],buf[ix+1]] },
        0xf5 => Instruction{ opcode: OpCode::PUSH, register: vec![Register::PSW], operands: vec![] },
        0xf6 => Instruction{ opcode: OpCode::ORI, register: vec![], operands: vec![buf[ix+1]] },
        0xf7 => Instruction{ opcode: OpCode::RST, register: vec![Register::_6], operands: vec![] },
        0xf8 => Instruction{ opcode: OpCode::RM, register: vec![], operands: vec![] },
        0xf9 => Instruction{ opcode: OpCode::SPHL, register: vec![], operands: vec![] },
        0xfa => Instruction{ opcode: OpCode::JM, register: vec![], operands: vec![buf[ix+2],buf[ix+1]] },
        0xfb => Instruction{ opcode: OpCode::EI, register: vec![], operands: vec![] },
        0xfc => Instruction{ opcode: OpCode::CM, register: vec![], operands: vec![buf[ix+2],buf[ix+1]] },
        0xfd => Instruction{ opcode: OpCode::NOP, register: vec![], operands: vec![] },
        0xfe => Instruction{ opcode: OpCode::CPI, register: vec![], operands: vec![buf[ix+1]] },
        0xff => Instruction{ opcode: OpCode::RST, register: vec![Register::_7], operands: vec![] },
    }
}<file_sep>use crate::architecture::model::state::State;
use crate::architecture::units::memory_unit;
use crate::architecture::model::instruction::Instruction;
use crate::architecture::units::arithmetic_logic_unit;
use crate::architecture::AddressPtr;

/// # Single Register Instructions:
///
/// Instructions which operate on a single register or memory location.

//TODO: unit tests
pub fn increment(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let value = memory_unit::get_reg_value(state, &instruction.register[0]);

    let result = arithmetic_logic_unit::add(value, 1);

    memory_unit::set_reg_value(state, &instruction.register[0], result.0);

    state.cc.z = result.1.z;
    state.cc.s = result.1.s;
    state.cc.p = result.1.p;
    state.cc.ac = result.1.ac;

    state.pc + instruction.size()
}

//TODO: unit tests
pub fn decrement(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let value = memory_unit::get_reg_value(state, &instruction.register[0]);

    let result = arithmetic_logic_unit::sub(value, 1);

    memory_unit::set_reg_value(state, &instruction.register[0], result.0);

    state.cc.z = result.1.z;
    state.cc.s = result.1.s;
    state.cc.p = result.1.p;
    state.cc.ac = result.1.ac;

    state.pc + instruction.size()
}

//TODO: unit tests
pub fn complement_accumulator(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let value = memory_unit::get_reg_value(state, &instruction.register[0]);
    let result = arithmetic_logic_unit::ones_complement(value);
    memory_unit::set_reg_value(state, &instruction.register[0], result);
    state.pc + instruction.size()
}

//TODO: unit tests & handle edge cases for carry bits
pub fn decimal_adjust_accumulator(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let inc_amount = if state.a & 0xf0 > 9 || state.cc.ac {
        0x06
    }else{
        0x00
    } +
    if state.a >> 4 > 9 || state.cc.cy {
       0x60
    }else {
        0x00
    };

    let result = arithmetic_logic_unit::add(state.a, inc_amount);
    state.a = result.0;
    state.cc = result.1;

    state.pc + instruction.size()
}<file_sep>pub mod util;
pub mod parser;
pub mod converter;

use crate::disassembler::util::write_instructions_to_file;

pub fn disassemble(program: &str, with_address: bool) -> std::io::Result<()>{
    let program_in_bytes = parser::parse(program, 8500).unwrap();
    let instructions = converter::convert_to_assembly(program_in_bytes.clone());
    write_instructions_to_file(instructions, format!("{}.asm", program).as_str(), with_address)
}<file_sep># Intel 8080 Emulator

[![build status](https://travis-ci.org/leahthecatlady/intel_8080_emulator.svg?branch=master)](https://travis-ci.org/leahthecatlady/intel_8080_emulator)
[![Coverage Status](https://coveralls.io/repos/github/leahthecatlady/intel_8080_emulator/badge.svg?branch=master)](https://coveralls.io/github/leahthecatlady/intel_8080_emulator?branch=master)

## About

This project is an exploration into rust and emulators. The current goal is to run Space Invaders via the developed emulator.

_Work on this project is currently on hold until I figure out a proper mechanism for [creating a GUI in Rust](https://areweguiyet.com/)_

## Resources

1. [emulator101.com](http://emulator101.com/)
2. [8080 Programmers Manual](http://altairclone.com/downloads/manuals/8080%20Programmers%20Manual.pdf)
3. [Space Invaders Disassembly Analysis Guide](http://computerarcheology.com/Arcade/SpaceInvaders/Code.html)

## How to Run

_Note: these instructions assume you have already installed `rust`, `rustc`, and `cargo` on your machine._

1. Download this repository
2. Navigate into the project directory
3. To run the project, execute the following command: `cargo run`
4. To run the unit tests, execute the following command: `cargo test`
<file_sep>use crate::architecture::model::state::State;
use crate::architecture::IoSignal;

pub trait OutputHandler {
    fn handle(&self, state: &mut State, signal: IoSignal);
}

pub struct DefaultHandler {}

impl OutputHandler for DefaultHandler {
    fn handle(&self, state: &mut State, signal: IoSignal){
        println!("Default output handler #{:02x} just received the {:02x} signal", signal.device, signal.signal);
    }
}<file_sep>use crate::architecture::model::state::State;
use crate::architecture::model::instruction::Instruction;
use crate::architecture::units::memory_unit;
use crate::architecture::model::registers::Register;
use crate::architecture::AddressPtr;
use crate::architecture::IoSignal;
use crate::architecture::units::io_unit;

/// # Input/Output Instructions:
///
/// Instructions which cause data to be input to or output from the 8080.

pub fn input(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let handler = io_unit::get_input_handler(instruction.operands[0]);

    let signal = handler.next_signal(state).signal;

    memory_unit::set_reg_value(state, &Register::A, signal);

    state.pc + instruction.size()
}

pub fn output(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let signal = memory_unit::get_reg_value(state, &Register::A);
    let device = instruction.operands[0];

    state.output_queue.push(IoSignal {signal, device});
    state.pc + instruction.size()
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::architecture::model::opcodes::OpCode;

    #[test]
    fn test_input() {
        let mut state = State {..Default::default()};
        let instruction = &Instruction{opcode:OpCode::IN,operands: vec![0x10],..Default::default()};
        let result = input(&mut state, instruction);
        assert_eq!(result, 2);
        assert_eq!(state.a, 0x1c);
    }

    #[test]
    fn test_output() {
        let mut state = State {a: 0x1c,..Default::default()};
        let instruction = &Instruction{opcode:OpCode::OUT,operands: vec![0x10],..Default::default()};
        let result = output(&mut state, instruction);
        assert_eq!(result, 2);
        assert_eq!(state.output_queue.pop().unwrap().signal, 0x1c)
    }
}<file_sep>use crate::architecture::model::state::State;
use crate::architecture::model::instruction::Instruction;
use crate::architecture::AddressPtr;

/// # Rotate Accumulator Instructions:
///
/// Instructions which rotate the contents of the accumulator.

pub fn rotate_left(state: &mut State, instruction: &Instruction) -> AddressPtr {
    state.cc.cy = state.a > 127;
    state.a = state.a.rotate_left(1);
    state.pc + instruction.size()
}

pub fn rotate_right(state: &mut State, instruction: &Instruction) -> AddressPtr {
    state.cc.cy = state.a % 2 == 1;
    state.a = state.a.rotate_right(1);
    state.pc + instruction.size()
}

pub fn rotate_left_through_carry(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let former_carry = if state.cc.cy {1} else {0};
    state.cc.cy = state.a > 127;

    state.a = (state.a << 1) + former_carry;
    state.pc + instruction.size()
}

pub fn rotate_right_through_carry(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let former_carry = if state.cc.cy {128} else {0};
    state.cc.cy = state.a % 2 == 1;

    state.a = (state.a >> 1) + former_carry;
    state.pc + instruction.size()
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::architecture::model::opcodes::OpCode;

    #[test]
    fn test_rotate_left() {
        let mut state = State {a:0x16,..Default::default()};
        let instruction = &Instruction{opcode:OpCode::RLC,..Default::default()};

        let result = rotate_left(&mut state, instruction);
        assert_eq!(result, 1);
        assert_eq!(state.cc.cy, false);
        assert_eq!(state.a, 0x2c);
    }

    #[test]
    fn test_rotate_right() {
        let mut state = State {a:0xf2,..Default::default()};
        let instruction = &Instruction{opcode:OpCode::RLC,..Default::default()};

        let result = rotate_right(&mut state, instruction);
        assert_eq!(result, 1);
        assert_eq!(state.cc.cy, false);
        assert_eq!(state.a, 0x79);
    }

    #[test]
    fn test_rotate_left_w_carry() {
        let mut state = State {a:0xf2,..Default::default()};
        let instruction = &Instruction{opcode:OpCode::RLC,..Default::default()};

        let result = rotate_left(&mut state, instruction);
        assert_eq!(result, 1);
        assert_eq!(state.cc.cy, true);
        assert_eq!(state.a, 0xe5);
    }

    #[test]
    fn test_rotate_right_w_carry() {
        let mut state = State {a:0x79,..Default::default()};
        let instruction = &Instruction{opcode:OpCode::RLC,..Default::default()};

        let result = rotate_right(&mut state, instruction);
        assert_eq!(result, 1);
        assert_eq!(state.cc.cy, true);
        assert_eq!(state.a, 0xbc);
    }

    #[test]
    fn test_rotate_left_through_carry() {
        let mut state = State {a:0xb5,..Default::default()};
        let instruction = &Instruction{opcode:OpCode::RLC,..Default::default()};

        let result = rotate_left_through_carry(&mut state, instruction);
        assert_eq!(result, 1);
        assert_eq!(state.cc.cy, true);
        assert_eq!(state.a, 0x6a);
    }

    #[test]
    fn test_rotate_right_through_carry() {
        let mut state = State {a:0x6a,..Default::default()};
        state.cc.cy = true;

        let instruction = &Instruction{opcode:OpCode::RLC,..Default::default()};

        let result = rotate_right_through_carry(&mut state, instruction);
        assert_eq!(result, 1);
        assert_eq!(state.cc.cy, false);
        assert_eq!(state.a, 0xb5);
    }
}<file_sep>extern crate strum;
extern crate strum_macros;

use strum_macros::Display;

#[derive(Display, Debug, Eq, PartialEq)]
pub enum Register {
    A,
    B,
    C,
    D,
    E,
    H,
    L,
    M,
    SP,
    PSW,
    #[strum(serialize="0")]
    _0,
    #[strum(serialize="1")]
    _1,
    #[strum(serialize="2")]
    _2,
    #[strum(serialize="3")]
    _3,
    #[strum(serialize="4")]
    _4,
    #[strum(serialize="5")]
    _5,
    #[strum(serialize="6")]
    _6,
    #[strum(serialize="7")]
    _7
}<file_sep>use crate::architecture::model::state::State;
use crate::architecture::model::instruction::Instruction;
use crate::architecture::AddressPtr;
use crate::architecture::units::stack;

/// # Reset Instructions:
///
/// The restart instruction is a special purpose subroutine jump.

//TODO: unit tests
pub fn restart(state: &mut State, instruction: &Instruction) -> AddressPtr {
    stack::push_return_addr(state, state.pc as u16);
    println!("ERROR: {} has not been implemented!", instruction.to_string());
    0x18
}<file_sep>pub mod carry_bit;
pub mod data_transfer;
pub mod direct_addressing;
pub mod register_pair;
pub mod hlt;
pub mod immediate;
pub mod interrupt;
pub mod io;
pub mod nop;
pub mod rotate_accumulator;
pub mod rst;
pub mod single_register;
pub mod to_accumulator;<file_sep>use crate::architecture::model::instruction::Instruction;
use crate::architecture::instruction_set;

pub fn convert_to_assembly(buf: Vec<u8>) -> Vec<Instruction> {
    let mut ptr:usize = 0;
    buf.len();

    let mut instructions: Vec<Instruction> = Vec::new();

    while ptr < buf.len() {
        let instr = instruction_set::read_next(&buf, ptr);
        ptr += instr.size();
        instructions.push(instr);
    }
    return instructions;
}<file_sep>use std::fs::File;
use std::io::prelude::*;
use std::io::LineWriter;
use crate::architecture::model::instruction::Instruction;

pub fn print_in_hex(buf: Vec<u8>, chunk_size: usize){
    let mut counter = 0;

    for bytes in buf.chunks(chunk_size) {
        print!("{:07x} ", counter);
        for byte in bytes {
            print!("{:02x} ", byte);
            counter += 1;
        }
        println!();
    }
}

pub fn print_instructions(instructions: Vec<Instruction>){
    let mut counter:usize = 0;

    for i in instructions {
        println!("{:04x} {}", counter, i.to_string());
        counter += i.size();
    }
}

pub fn write_instructions_to_file(instructions: Vec<Instruction>, filename: &str, with_address: bool) -> std::io::Result<()>{
    let file = File::create(filename)?;
    let mut file = LineWriter::new(file);

    let mut counter:usize = 0;

    for i in instructions {
        let line = if with_address {
            format!("{:04x} {}\n", counter, i.to_string())
        }else{
            format!("{}\n", i.to_string())
        };
        file.write_all(line.as_bytes())?;
        counter += i.size();
    }

    Ok(())
}<file_sep>use crate::architecture::model::state::State;
use crate::architecture::model::instruction::Instruction;
use crate::architecture::units::memory_unit;
use crate::architecture::model::registers::Register;
use crate::architecture::units::arithmetic_logic_unit;
use crate::architecture::AddressPtr;

/// # Immediate Instructions:
///
/// Instructions which perform operations using a byte or bytes of data
/// which are part of the instruction itself.

pub fn load_register_pair(state: &mut State, instruction: &Instruction) -> AddressPtr {
    memory_unit::set_mem_loc_in_reg(state, &instruction.register[0], &instruction.operands);
    state.pc + instruction.size()
}

pub fn move_data(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let reg = &instruction.register[0];
    let data = instruction.operands[0];

    memory_unit::set_reg_value(state, reg, data);
    state.pc + instruction.size()
}

pub fn add(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let acc_value = state.a;
    let imm_value = instruction.operands[0];

    let result = arithmetic_logic_unit::add(acc_value, imm_value);

    state.cc.cy = result.1.cy;
    state.cc.s = result.1.s;
    state.cc.z = result.1.z;
    state.cc.p = result.1.p;
    state.cc.ac = result.1.ac;

    state.a = result.0;

    state.pc + instruction.size()
}

//TODO: unit tests and verify logic on condition codes is correct
pub fn add_with_carry(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let acc_value = state.a;
    let imm_value = instruction.operands[0];

    let result = arithmetic_logic_unit::add(acc_value, imm_value);

    let result = if state.cc.cy {arithmetic_logic_unit::add(result.0, 1)} else {result};

    state.cc.cy = result.1.cy;
    state.cc.s = result.1.s;
    state.cc.z = result.1.z;
    state.cc.p = result.1.p;
    state.cc.ac = result.1.ac;

    state.a = result.0;

    state.pc + instruction.size()
}

//TODO: unit tests
pub fn sub(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let acc_value = state.a;
    let imm_value = instruction.operands[0];

    let result = arithmetic_logic_unit::sub(acc_value, imm_value);

    state.cc.cy = result.1.cy;
    state.cc.s = result.1.s;
    state.cc.z = result.1.z;
    state.cc.p = result.1.p;
    state.cc.ac = result.1.ac;

    state.a = result.0;

    state.pc + instruction.size()
}

//TODO: unit tests
pub fn sub_with_borrow(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let acc_value = state.a;
    let imm_value = instruction.operands[0];

    let result = arithmetic_logic_unit::sub(acc_value, imm_value);

    let result = if state.cc.cy {arithmetic_logic_unit::sub(result.0, 1)} else {result};

    state.cc.cy = result.1.cy;
    state.cc.s = result.1.s;
    state.cc.z = result.1.z;
    state.cc.p = result.1.p;
    state.cc.ac = result.1.ac;

    state.a = result.0;

    state.pc + instruction.size()
}

//TODO: unit tests
pub fn and(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let acc_value = state.a;
    let imm_value = instruction.operands[0];

    let result = arithmetic_logic_unit::and(acc_value, imm_value);

    state.cc.cy = result.1.cy;
    state.cc.s = result.1.s;
    state.cc.z = result.1.z;
    state.cc.p = result.1.p;

    state.a = result.0;

    state.pc + instruction.size()
}

//TODO: unit tests
pub fn xor(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let acc_value = state.a;
    let imm_value = instruction.operands[0];

    let result = arithmetic_logic_unit::xor(acc_value, imm_value);

    state.cc.cy = result.1.cy;
    state.cc.s = result.1.s;
    state.cc.z = result.1.z;
    state.cc.p = result.1.p;

    state.a = result.0;

    state.pc + instruction.size()
}

//TODO: unit tests
pub fn or(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let acc_value = state.a;
    let imm_value = instruction.operands[0];

    let result = arithmetic_logic_unit::or(acc_value, imm_value);

    state.cc.cy = result.1.cy;
    state.cc.s = result.1.s;
    state.cc.z = result.1.z;
    state.cc.p = result.1.p;

    state.a = result.0;

    state.pc + instruction.size()
}

//TODO: unit tests
pub fn compare(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let acc = memory_unit::get_reg_value(state, &Register::A);
    let imm = instruction.operands[0];

    let result = arithmetic_logic_unit::compare(acc, imm);

    state.cc.cy = result.1.cy;
    state.cc.s = result.1.s;
    state.cc.z = result.1.z;
    state.cc.p = result.1.p;
    state.cc.ac = result.1.ac;

    state.pc + instruction.size()
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::architecture::model::opcodes::OpCode;

    #[test]
    fn test_load_reg_pair() {
        let mut state = State {..Default::default()};
        let instruction = &Instruction{opcode:OpCode::LXI,register: vec![Register::B], operands:vec![0x00, 0x20],..Default::default()};

        let result = load_register_pair(&mut state, instruction);
        assert_eq!(result, 3);
        assert_eq!(state.b, 0x00);
        assert_eq!(state.c, 0x20)
    }

    #[test]
    fn test_load_sp() {
        let mut state = State {..Default::default()};
        let instruction = &Instruction{opcode:OpCode::LXI,register: vec![Register::SP], operands:vec![0x00, 0x20],..Default::default()};

        let result = load_register_pair(&mut state, instruction);
        assert_eq!(result, 3);
        assert_eq!(state.sp, 0x0020);
    }

    #[test]
    fn test_move_data_reg() {
        let mut state = State {..Default::default()};
        let instruction = &Instruction{opcode:OpCode::MVI,register: vec![Register::B], operands:vec![0x1c],..Default::default()};

        let result = move_data(&mut state, instruction);
        assert_eq!(result, 2);
        assert_eq!(state.b, 0x1c);
    }

    #[test]
    fn test_move_data_mem() {
        let index:usize = 0x0020;
        let mut memory: Vec<u8> = vec![0;100];
        let value:u8 = 0x1c;

        let mut state = State {h: 0x00, l: 0x20, memory,..Default::default()};
        let instruction = &Instruction{opcode:OpCode::MVI,register: vec![Register::M], operands:vec![value],..Default::default()};

        let result = move_data(&mut state, instruction);
        assert_eq!(result, 2);
        assert_eq!(state.memory[index], value);
    }

    #[test]
    fn test_add() {
        let mut state = State {a: 0x10,..Default::default()};
        let instruction = &Instruction{opcode:OpCode::ADI, operands:vec![0x1c],..Default::default()};

        let result = add(&mut state, instruction);
        assert_eq!(result, 2);
        assert_eq!(state.a, 0x2c);
    }

    #[test]
    fn test_add_carry_set() {
        let mut state = State {a: 0x10,..Default::default()};
        state.cc.cy = true;
        let instruction = &Instruction{opcode:OpCode::ACI, operands:vec![0x1c],..Default::default()};

        let result = add_with_carry(&mut state, instruction);
        assert_eq!(result, 2);
        assert_eq!(state.a, 0x2d);
    }

    #[test]
    fn test_add_carry_not_set() {
        let mut state = State {a: 0x10,..Default::default()};
        state.cc.cy = false;
        let instruction = &Instruction{opcode:OpCode::ACI, operands:vec![0x1c],..Default::default()};

        let result = add_with_carry(&mut state, instruction);
        assert_eq!(result, 2);
        assert_eq!(state.a, 0x2c);
    }
}<file_sep>extern crate strum;
extern crate strum_macros;

use crate::architecture::model::opcodes::OpCode;
use crate::architecture::model::registers::Register;
use crate::architecture::model::state::State;
use crate::architecture::units::processing_unit;

#[derive(Debug, Eq, PartialEq)]
pub struct Instruction{
    pub opcode: OpCode,
    pub register: Vec<Register>,
    pub operands: Vec<u8>
}

impl Instruction{
    pub fn to_string(&self) -> String {
        let mut instruction:String = self.opcode.to_string();

        match self.register.len() {
            1 => instruction = format!("{} {}", instruction, self.register[0]),
            2 => instruction = format!("{} {},{}", instruction, self.register[0], self.register[1]),
            _ => ()
        }

        match self.operands.len() {
            1 if self.register.len() == 0 => instruction = format!("{} #${:02x}", instruction, self.operands[0]),
            1 if self.register.len() > 0 => instruction = format!("{},#${:02x}", instruction, self.operands[0]),
            2 if self.register.len() == 0 => instruction = format!("{} ${:02x}{:02x}",instruction, self.operands[0], self.operands[1]),
            2 if self.register.len() > 0 => instruction = format!("{},#${:02x}{:02x}",instruction, self.operands[0], self.operands[1]),
            _ => ()
        }

        instruction
    }

    pub fn size(&self) -> usize {
        self.operands.len() + 1
    }

    pub fn execute(&self, state: &mut State) -> usize {
        processing_unit::process_instruction(&self.opcode)(state, self)
    }
}

impl Default for Instruction {
    fn default() -> Instruction {
        Instruction {
            opcode: OpCode::NOP,
            register: vec![],
            operands: vec![]
        }
    }
}<file_sep>use crate::architecture::model::state::State;
use crate::architecture::model::instruction::Instruction;
use crate::architecture::units::stack;
use crate::architecture::units::memory_unit;
use crate::architecture::units::arithmetic_logic_unit;
use crate::architecture::model::registers::Register;
use crate::architecture::AddressPtr;

/// # Register Pair Instructions:
///
/// Instructions which operate on pairs of registers

//TODO: unit tests
pub fn push(state: &mut State, instruction: &Instruction) -> AddressPtr {
    stack::push_reg(state, &instruction.register[0]);
    state.pc + instruction.size()
}

//TODO: unit tests
pub fn pop(state: &mut State, instruction: &Instruction) -> AddressPtr {
    stack::pop_to_reg(state, &instruction.register[0]);
    state.pc + instruction.size()
}

//TODO: unit tests
pub fn double_add(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let reg_pair_val = memory_unit::get_double_reg_value(state, &instruction.register[0]);
    let hl_pair_val = memory_unit::get_double_reg_value(state, &Register::H);
    let result = arithmetic_logic_unit::double_add(reg_pair_val, hl_pair_val);

    state.cc.cy = result.1.cy;

    memory_unit::set_double_reg_value(state, &Register::H, result.0);

    state.pc + instruction.size()
}

//TODO: unit tests
pub fn increment(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let reg = &instruction.register[0];

    let reg_pair = memory_unit::get_double_reg_value(state, reg);
    let result = arithmetic_logic_unit::double_add(reg_pair, (0,1));
    memory_unit::set_double_reg_value(state, reg, result.0);
    state.pc + instruction.size()
}

//TODO: unit tests
pub fn decrement(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let reg = &instruction.register[0];

    let reg_pair = memory_unit::get_double_reg_value(state, reg);
    let result = arithmetic_logic_unit::double_sub(reg_pair, (0,1));
    memory_unit::set_double_reg_value(state, reg, result.0);
    state.pc + instruction.size()
}

//TODO: unit tests
pub fn exchange(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let hl_pair_val = memory_unit::get_double_reg_value(state, &Register::H);
    let de_pair_val = memory_unit::get_double_reg_value(state, &Register::D);

    memory_unit::set_double_reg_value(state, &Register::H, de_pair_val);
    memory_unit::set_double_reg_value(state, &Register::D, hl_pair_val);

    state.pc + instruction.size()
}

//TODO: unit tests
pub fn exchange_sp(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let sp1_loc = memory_unit::get_double_reg_value(state, &Register::SP);
    let sp2_loc = arithmetic_logic_unit::double_add(sp1_loc, (0,1)).0;

    let sp1_value = memory_unit::get_mem_value(state, sp1_loc);
    let sp2_value = memory_unit::get_mem_value(state, sp2_loc);

    let hl_pair_val = memory_unit::get_double_reg_value(state, &Register::H);

    memory_unit::set_double_reg_value(state, &Register::H, (sp2_value, sp1_value));
    memory_unit::set_mem_value(state, sp1_loc, hl_pair_val.1);
    memory_unit::set_mem_value(state, sp2_loc, hl_pair_val.0);

    state.pc + instruction.size()
}

//TODO: unit tests
pub fn load_sp_from_hl(state: &mut State, instruction: &Instruction) -> AddressPtr {
    let hl_pair_val = memory_unit::get_double_reg_value(state, &Register::H);
    memory_unit::set_double_reg_value(state, &Register::SP, hl_pair_val);
    state.pc + instruction.size()
}

languages: Rust TOML Markdown

repo_language: Rust