Skip to content
Snippets Groups Projects
inst.rs 34.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • fn ld_d_a(cpu: &mut Cpu) {
        cpu.d = cpu.a;
    }
    
    
    fn ld_e_a(cpu: &mut Cpu) {
        cpu.e = cpu.a;
    }
    
    
    fn ld_h_a(cpu: &mut Cpu) {
        cpu.h = cpu.a;
    }
    
    
    fn ld_mhl_b(cpu: &mut Cpu) {
        cpu.mmu.write(cpu.hl(), cpu.b);
    }
    
    fn ld_mhl_c(cpu: &mut Cpu) {
        cpu.mmu.write(cpu.hl(), cpu.c);
    }
    
    fn ld_mhl_d(cpu: &mut Cpu) {
        cpu.mmu.write(cpu.hl(), cpu.d);
    }
    
    
    fn halt(cpu: &mut Cpu) {
        cpu.halt();
    }
    
    
    fn ld_mhl_a(cpu: &mut Cpu) {
        cpu.mmu.write(cpu.hl(), cpu.a);
    }
    
    fn ld_a_b(cpu: &mut Cpu) {
        cpu.a = cpu.b;
    }
    
    fn ld_a_c(cpu: &mut Cpu) {
        cpu.a = cpu.c;
    }
    
    
    fn ld_a_d(cpu: &mut Cpu) {
        cpu.a = cpu.d;
    }
    
    
    fn ld_a_e(cpu: &mut Cpu) {
        cpu.a = cpu.e;
    }
    
    fn ld_a_h(cpu: &mut Cpu) {
        cpu.a = cpu.h;
    }
    
    fn ld_a_l(cpu: &mut Cpu) {
        cpu.a = cpu.l;
    }
    
    
    fn ld_a_mhl(cpu: &mut Cpu) {
        let byte = cpu.mmu.read(cpu.hl());
        cpu.a = byte;
    }
    
    
    fn add_a_b(cpu: &mut Cpu) {
        cpu.a = add_set_flags(cpu, cpu.a, cpu.b);
    }
    
    
    fn add_a_c(cpu: &mut Cpu) {
        cpu.a = add_set_flags(cpu, cpu.a, cpu.c);
    }
    
    fn add_a_e(cpu: &mut Cpu) {
        cpu.a = add_set_flags(cpu, cpu.a, cpu.e);
    }
    
    
    fn add_a_mhl(cpu: &mut Cpu) {
        let byte = cpu.mmu.read(cpu.hl());
        cpu.a = add_set_flags(cpu, cpu.a, byte);
    }
    
    fn sub_a_b(cpu: &mut Cpu) {
        cpu.a = sub_set_flags(cpu, cpu.a, cpu.b);
    }
    
    
    fn sub_a_a(cpu: &mut Cpu) {
        cpu.a = sub_set_flags(cpu, cpu.a, cpu.a);
    }
    
    
    fn and_a_c(cpu: &mut Cpu) {
        cpu.a &= cpu.c;
    
        cpu.set_sub(false);
        cpu.set_zero(cpu.a == 0);
        cpu.set_half_carry(true);
        cpu.set_carry(false);
    }
    
    fn xor_a_c(cpu: &mut Cpu) {
        cpu.a ^= cpu.c;
    
        cpu.set_sub(false);
        cpu.set_zero(cpu.a == 0);
        cpu.set_half_carry(false);
        cpu.set_carry(false);
    }
    
    
    fn xor_a_mhl(cpu: &mut Cpu) {
        let byte = cpu.mmu.read(cpu.hl());
        cpu.a ^= byte;
    
        cpu.set_sub(false);
        cpu.set_zero(cpu.a == 0);
        cpu.set_half_carry(false);
        cpu.set_carry(false);
    }
    
    
    fn xor_a_a(cpu: &mut Cpu) {
        cpu.a ^= cpu.a;
    
        cpu.set_sub(false);
        cpu.set_zero(cpu.a == 0);
        cpu.set_half_carry(false);
        cpu.set_carry(false);
    }
    
    fn or_a_b(cpu: &mut Cpu) {
        cpu.a |= cpu.b;
    
        cpu.set_sub(false);
        cpu.set_zero(cpu.a == 0);
        cpu.set_half_carry(false);
        cpu.set_carry(false);
    }
    
    fn or_a_c(cpu: &mut Cpu) {
        cpu.a |= cpu.c;
    
        cpu.set_sub(false);
        cpu.set_zero(cpu.a == 0);
        cpu.set_half_carry(false);
        cpu.set_carry(false);
    }
    
    
    fn or_a_a(cpu: &mut Cpu) {
        cpu.a |= cpu.a;
    
        cpu.set_sub(false);
        cpu.set_zero(cpu.a == 0);
        cpu.set_half_carry(false);
        cpu.set_carry(false);
    }
    
    
    fn cp_a_mhl(cpu: &mut Cpu) {
        let byte = cpu.mmu.read(cpu.hl());
        sub_set_flags(cpu, cpu.a, byte);
    }
    
    fn ret_nz(cpu: &mut Cpu) {
        if cpu.get_zero() {
            return;
        }
    
        cpu.pc = cpu.pop_word();
        cpu.ticks = cpu.ticks.wrapping_add(12);
    }
    
    fn pop_bc(cpu: &mut Cpu) {
        let word = cpu.pop_word();
        cpu.set_bc(word);
    }
    
    
    fn jp_nz_u16(cpu: &mut Cpu) {
        let word = cpu.read_u16();
    
        if cpu.get_zero() {
            return;
        }
    
        cpu.pc = word;
        cpu.ticks = cpu.ticks.wrapping_add(4);
    }
    
    
    fn jp_u16(cpu: &mut Cpu) {
        let word = cpu.read_u16();
        cpu.pc = word;
    }
    
    fn call_nz_u16(cpu: &mut Cpu) {
        let word = cpu.read_u16();
    
        if cpu.get_zero() {
            return;
        }
    
        cpu.push_word(cpu.pc);
        cpu.pc = word;
        cpu.ticks = cpu.ticks.wrapping_add(12);
    }
    
    fn push_bc(cpu: &mut Cpu) {
        cpu.push_word(cpu.bc());
    }
    
    
    João Magalhães's avatar
    João Magalhães committed
    fn add_a_u8(cpu: &mut Cpu) {
        let byte = cpu.read_u8();
        cpu.a = add_set_flags(cpu, cpu.a, byte);
    }
    
    
    fn ret_z(cpu: &mut Cpu) {
        if !cpu.get_zero() {
            return;
        }
    
        cpu.pc = cpu.pop_word();
        cpu.ticks = cpu.ticks.wrapping_add(12);
    }
    
    
    fn ret(cpu: &mut Cpu) {
        cpu.pc = cpu.pop_word();
    }
    
    
    fn jp_z_u16(cpu: &mut Cpu) {
        let word = cpu.read_u16();
    
        if !cpu.get_zero() {
            return;
        }
    
        cpu.pc = word;
        cpu.ticks = cpu.ticks.wrapping_add(4);
    }
    
    fn call_z_u16(cpu: &mut Cpu) {
        let word = cpu.read_u16();
    
        if !cpu.get_zero() {
            return;
        }
    
        cpu.push_word(cpu.pc);
        cpu.pc = word;
        cpu.ticks = cpu.ticks.wrapping_add(12);
    }
    
    
    fn call_u16(cpu: &mut Cpu) {
        let word = cpu.read_u16();
        cpu.push_word(cpu.pc);
        cpu.pc = word;
    }
    
    
    fn adc_a_u8(cpu: &mut Cpu) {
        let byte = cpu.read_u8();
        cpu.a = add_carry_set_flags(cpu, cpu.a, byte);
    }
    
    
    fn rst_08h(cpu: &mut Cpu) {
        rst(cpu, 0x0008);
    }
    
    
    João Magalhães's avatar
    João Magalhães committed
    fn ret_nc(cpu: &mut Cpu) {
        if cpu.get_carry() {
            return;
        }
    
        cpu.pc = cpu.pop_word();
        cpu.ticks = cpu.ticks.wrapping_add(12);
    }
    
    
    João Magalhães's avatar
    João Magalhães committed
    fn pop_de(cpu: &mut Cpu) {
        let word = cpu.pop_word();
        cpu.set_de(word);
    }
    
    
    fn push_de(cpu: &mut Cpu) {
        cpu.push_word(cpu.de());
    }
    
    
    fn sub_a_u8(cpu: &mut Cpu) {
        let byte = cpu.read_u8();
        cpu.a = sub_set_flags(cpu, cpu.a, byte);
    }
    
    
    fn reti(cpu: &mut Cpu) {
        cpu.pc = cpu.pop_word();
        cpu.enable_int();
    }
    
    
    fn jp_c_u16(cpu: &mut Cpu) {
        let word = cpu.read_u16();
    
        if !cpu.get_carry() {
            return;
        }
    
        cpu.pc = word;
        cpu.ticks = cpu.ticks.wrapping_add(4);
    }
    
    fn call_c_u16(cpu: &mut Cpu) {
        let word = cpu.read_u16();
    
        if !cpu.get_carry() {
            return;
        }
    
        cpu.push_word(cpu.pc);
        cpu.pc = word;
        cpu.ticks = cpu.ticks.wrapping_add(12);
    }
    
    
    fn ld_mff00u8_a(cpu: &mut Cpu) {
        let byte = cpu.read_u8();
        cpu.mmu.write(0xff00 + byte as u16, cpu.a);
    }
    
    
    fn pop_hl(cpu: &mut Cpu) {
        let word = cpu.pop_word();
        cpu.set_hl(word);
    }
    
    
    fn ld_mff00c_a(cpu: &mut Cpu) {
        cpu.mmu.write(0xff00 + cpu.c as u16, cpu.a);
    }
    
    
    fn push_hl(cpu: &mut Cpu) {
        cpu.push_word(cpu.hl());
    }
    
    
    fn and_a_u8(cpu: &mut Cpu) {
        let byte = cpu.read_u8();
    
        cpu.a &= byte;
    
        cpu.set_sub(false);
        cpu.set_zero(cpu.a == 0);
        cpu.set_half_carry(true);
        cpu.set_carry(false);
    }
    
    fn ld_mu16_a(cpu: &mut Cpu) {
        let word = cpu.read_u16();
        cpu.mmu.write(word, cpu.a);
    }
    
    
    fn xor_a_u8(cpu: &mut Cpu) {
        let byte = cpu.read_u8();
        cpu.a ^= byte;
    
        cpu.set_sub(false);
        cpu.set_zero(cpu.a == 0);
        cpu.set_half_carry(false);
        cpu.set_carry(false);
    }
    
    
    fn rst_18h(cpu: &mut Cpu) {
        rst(cpu, 0x0018);
    }
    
    fn ld_a_mff00u8(cpu: &mut Cpu) {
        let byte = cpu.read_u8();
        cpu.a = cpu.mmu.read(0xff00 + byte as u16);
    }
    
    
    fn pop_af(cpu: &mut Cpu) {
        let word = cpu.pop_word();
        cpu.set_af(word);
    }
    
    
    fn di(cpu: &mut Cpu) {
        cpu.disable_int();
    }
    
    
    fn push_af(cpu: &mut Cpu) {
        cpu.push_word(cpu.af());
    }
    
    
    fn ld_a_mu16(cpu: &mut Cpu) {
        let word = cpu.read_u16();
        let byte = cpu.mmu.read(word);
        cpu.a = byte;
    }
    
    
    fn ei(cpu: &mut Cpu) {
        cpu.enable_int();
    }
    
    fn cp_a_u8(cpu: &mut Cpu) {
        let byte = cpu.read_u8();
        sub_set_flags(cpu, cpu.a, byte);
    }
    
    fn rst_38h(cpu: &mut Cpu) {
        rst(cpu, 0x0038);
    }
    
    fn rl_c(cpu: &mut Cpu) {
        cpu.c = rl(cpu, cpu.c);
    }
    
    
    fn rr_c(cpu: &mut Cpu) {
        cpu.c = rr(cpu, cpu.c);
    }
    
    fn rr_d(cpu: &mut Cpu) {
        cpu.d = rr(cpu, cpu.d);
    }
    
    
    fn sla_b(cpu: &mut Cpu) {
        cpu.b = sla(cpu, cpu.b);
    }
    
    
    fn swap_a(cpu: &mut Cpu) {
        cpu.a = swap(cpu, cpu.a)
    }
    
    
    fn srl_b(cpu: &mut Cpu) {
        cpu.b = srl(cpu, cpu.b);
    }
    
    
    fn bit_0_d(cpu: &mut Cpu) {
        bit_d(cpu, 0);
    }
    
    
    fn bit_7_h(cpu: &mut Cpu) {
        bit_h(cpu, 7);
    }
    
    
    fn res_7_mhl(cpu: &mut Cpu) {
        let hl = cpu.hl();
        let byte = cpu.mmu.read(hl);
        let value = res(byte, 7);
        cpu.mmu.write(hl, value);
    }
    
    
    fn set_4_a(cpu: &mut Cpu) {
        cpu.a = set(cpu.a, 4);
    }
    
    /// Helper function to set one bit in a u8.
    fn set(value: u8, bit: u8) -> u8 {
        value | (1u8 << (bit as usize))
    }
    
    
    /// Helper function to clear one bit in a u8
    fn res(value: u8, bit: u8) -> u8 {
        value & !(1u8 << (bit as usize))
    }
    
    
    /// Helper function that rotates (shifts) left the given
    
    /// byte (probably from a register) and updates the
    /// proper flag registers.
    
    fn rl(cpu: &mut Cpu, value: u8) -> u8 {
    
        let carry = cpu.get_carry();
    
    
        cpu.set_carry(value & 0x80 == 0x80);
    
        let result = (value << 1) | carry as u8;
    
        cpu.set_sub(false);
        cpu.set_zero(result == 0);
        cpu.set_half_carry(false);
    
        result
    }
    
    /// Helper function that rotates (shifts) right the given
    /// byte (probably from a register) and updates the
    /// proper flag registers.
    fn rr(cpu: &mut Cpu, value: u8) -> u8 {
        let carry = cpu.get_carry();
    
        cpu.set_carry(value & 0x01 == 0x01);
    
        let result = (value >> 1) | ((carry as u8) << 7);
    
    
        cpu.set_sub(false);
        cpu.set_zero(result == 0);
        cpu.set_half_carry(false);
    
        result
    }
    
    /// Helper function to test one bit in a u8.
    /// Returns true if bit is 0.
    fn bit_zero(val: u8, bit: u8) -> bool {
        (val & (1u8 << (bit as usize))) == 0
    }
    
    
    fn bit_d(cpu: &mut Cpu, bit: u8) {
        cpu.set_sub(false);
        cpu.set_zero(bit_zero(cpu.d, bit));
        cpu.set_half_carry(true);
    }
    
    
    fn bit_h(cpu: &mut Cpu, bit: u8) {
        cpu.set_sub(false);
        cpu.set_zero(bit_zero(cpu.h, bit));
        cpu.set_half_carry(true);
    }
    
    fn add_set_flags(cpu: &mut Cpu, first: u8, second: u8) -> u8 {
        let first = first as u32;
        let second = second as u32;
    
    
        let result = first.wrapping_add(second);
        let result_b = result as u8;
    
    
        cpu.set_sub(false);
    
        cpu.set_zero(result_b == 0);
        cpu.set_half_carry((first ^ second ^ result) & 0x10 == 0x10);
        cpu.set_carry(result & 0x100 == 0x100);
    
        result_b
    
    fn add_carry_set_flags(cpu: &mut Cpu, first: u8, second: u8) -> u8 {
        let first = first as u32;
        let second = second as u32;
        let carry = cpu.get_carry() as u32;
    
        let result = first.wrapping_add(second).wrapping_add(carry);
        let result_b = result as u8;
    
        cpu.set_sub(false);
        cpu.set_zero(result_b == 0);
        cpu.set_half_carry((first ^ second ^ result) & 0x10 == 0x10);
        cpu.set_carry(result & 0x100 == 0x100);
    
        result_b
    }
    
    
    fn sub_set_flags(cpu: &mut Cpu, first: u8, second: u8) -> u8 {
        let first = first as u32;
        let second = second as u32;
    
    
        let result = first.wrapping_sub(second);
        let result_b = result as u8;
    
    
        cpu.set_sub(true);
    
        cpu.set_zero(result_b == 0);
        cpu.set_half_carry((first ^ second ^ result) & 0x10 == 0x10);
        cpu.set_carry(result & 0x100 == 0x100);
    
        result_b
    
    }
    
    fn add_u16_u16(cpu: &mut Cpu, first: u16, second: u16) -> u16 {
        let first = first as u32;
        let second = second as u32;
    
        let result = first.wrapping_add(second);
    
    
        cpu.set_sub(false);
    
        cpu.set_half_carry((first ^ second ^ result) & 0x1000 == 0x1000);
        cpu.set_carry(result & 0x10000 == 0x10000);
    
        result as u16
    
    }
    
    fn swap(cpu: &mut Cpu, value: u8) -> u8 {
        cpu.set_sub(false);
        cpu.set_zero(value == 0);
        cpu.set_half_carry(false);
        cpu.set_carry(false);
    
        (value << 4) | (value >> 4)
    }
    
    
    /// Helper function to shift an `u8` to the left and update CPU
    /// flags.
    
    fn sla(cpu: &mut Cpu, value: u8) -> u8 {
    
        let result = value << 1;
    
        cpu.set_sub(false);
        cpu.set_zero(result == 0);
        cpu.set_half_carry(false);
        cpu.set_carry(value & 0x80 != 0);
    
        result
    }
    
    
    fn srl(cpu: &mut Cpu, value: u8) -> u8 {
        let result = value >> 1;
    
        cpu.set_sub(false);
        cpu.set_zero(result == 0);
        cpu.set_half_carry(false);
        cpu.set_carry(value & 0x01 == 0x01);
    
        result
    }
    
    
    /// Helper function for RST instructions, pushes the
    /// current PC to the stack and jumps to the provided
    /// address.
    fn rst(cpu: &mut Cpu, addr: u16) {
        cpu.push_word(cpu.pc);
        cpu.pc = addr;
    }