From 9ef86217b18ac21dbf3e7ad6ca94c62ead4545e0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Magalh=C3=A3es?= <joamag@gmail.com>
Date: Sun, 3 Jul 2022 01:27:02 +0100
Subject: [PATCH] =?UTF-8?q?feat:=20added=20more=20instructions=20?=
 =?UTF-8?q?=F0=9F=A4=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/cpu.rs  |  22 +++++-
 src/inst.rs | 191 +++++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 188 insertions(+), 25 deletions(-)

diff --git a/src/cpu.rs b/src/cpu.rs
index d16da5f4..dc9ef41a 100644
--- a/src/cpu.rs
+++ b/src/cpu.rs
@@ -1,5 +1,5 @@
 use crate::{
-    inst::{BITWISE, INSTRUCTIONS},
+    inst::{EXTENDED, INSTRUCTIONS},
     mmu::Mmu,
     ppu::Ppu,
 };
@@ -26,6 +26,24 @@ pub struct Cpu {
 
 impl Cpu {
     pub fn new(mmu: Mmu) -> Cpu {
+        let mut implemented = 0;
+        let mut implemented_ext = 0;
+
+        for instruction in INSTRUCTIONS {
+            if instruction.2 != "! UNIMP !" {
+                implemented += 1;
+            }
+        }
+
+        for instruction in EXTENDED {
+            if instruction.2 != "! UNIMP !" {
+                implemented_ext += 1;
+            }
+        }
+
+        println!("Implemented {}/{} instructions", implemented, INSTRUCTIONS.len());
+        println!("Implemented {}/{} extended instructions", implemented_ext, EXTENDED.len());
+
         Cpu {
             pc: 0x0,
             sp: 0x0,
@@ -59,7 +77,7 @@ impl Cpu {
         if is_prefix {
             opcode = self.mmu.read(self.pc);
             self.pc = self.pc.wrapping_add(1);
-            instruction = &BITWISE[opcode as usize];
+            instruction = &EXTENDED[opcode as usize];
         } else {
             instruction = &INSTRUCTIONS[opcode as usize];
         }
diff --git a/src/inst.rs b/src/inst.rs
index e5229b81..752279d6 100644
--- a/src/inst.rs
+++ b/src/inst.rs
@@ -34,22 +34,22 @@ pub const INSTRUCTIONS: [(fn(&mut Cpu), u8, &'static str); 256] = [
     (inc_e, 4, "INC E"),
     (dec_e, 4, "DEC E"),
     (ld_e_u8, 8, "LD E, u8"),
-    (noimpl, 4, "! UNIMP !"),
+    (rra, 4, "RRA"),
     // 0x2 opcodes
     (jr_nz_i8, 8, "JR NZ, i8"),
     (ld_hl_u16, 12, "LD HL, u16"),
     (ld_mhli_a, 8, "LD [HL+], A"),
     (inc_hl, 8, "INC HL"),
     (inc_h, 4, "INC H"),
-    (noimpl, 4, "! UNIMP !"),
-    (noimpl, 4, "! UNIMP !"),
+    (dec_h, 4, "DEC H"),
+    (ld_h_u8, 8, "LD H, u8"),
     (noimpl, 4, "! UNIMP !"),
     (jr_z_i8, 8, "JR Z, i8"),
     (noimpl, 4, "! UNIMP !"),
     (ld_a_mhli, 8, "LD A, [HL+] "),
     (noimpl, 4, "! UNIMP !"),
     (inc_l, 4, "INC L"),
-    (noimpl, 4, "! UNIMP !"),
+    (dec_l, 4, "DEC L"),
     (ld_l_u8, 8, "LD L, u8"),
     (cpl, 4, "CPL"),
     // 0x3 opcodes
@@ -61,7 +61,7 @@ pub const INSTRUCTIONS: [(fn(&mut Cpu), u8, &'static str); 256] = [
     (noimpl, 4, "! UNIMP !"),
     (ld_mhl_u8, 12, "LD [HL], u8 "),
     (scf, 4, "SCF"),
-    (noimpl, 4, "! UNIMP !"),
+    (jr_c_i8, 8, "JR C, i8"),
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
@@ -76,7 +76,7 @@ pub const INSTRUCTIONS: [(fn(&mut Cpu), u8, &'static str); 256] = [
     (noimpl, 4, "! UNIMP !"),
     (ld_b_h, 4, "LD B, H"),
     (noimpl, 4, "! UNIMP !"),
-    (noimpl, 4, "! UNIMP !"),
+    (ld_b_mhl, 8, "LD B, [HL]"),
     (ld_b_a, 4, "LD B, A"),
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
@@ -84,7 +84,7 @@ pub const INSTRUCTIONS: [(fn(&mut Cpu), u8, &'static str); 256] = [
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
-    (noimpl, 4, "! UNIMP !"),
+    (ld_c_mhl, 8, "LD C, [HL]"),
     (ld_c_a, 4, "LD C, A"),
     // 0x5 opcodes
     (noimpl, 4, "! UNIMP !"),
@@ -93,7 +93,7 @@ pub const INSTRUCTIONS: [(fn(&mut Cpu), u8, &'static str); 256] = [
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
-    (noimpl, 4, "! UNIMP !"),
+    (ld_d_mhl, 8, "LD D, [HL]"),
     (ld_d_a, 4, "LD D, A"),
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
@@ -102,7 +102,7 @@ pub const INSTRUCTIONS: [(fn(&mut Cpu), u8, &'static str); 256] = [
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
-    (noimpl, 4, "! UNIMP !"),
+    (ld_e_a, 4, "LD E, A"),
     // 0x6 opcodes
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
@@ -121,9 +121,9 @@ pub const INSTRUCTIONS: [(fn(&mut Cpu), u8, &'static str); 256] = [
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
     // 0x7 opcodes
-    (noimpl, 4, "! UNIMP !"),
-    (noimpl, 4, "! UNIMP !"),
-    (noimpl, 4, "! UNIMP !"),
+    (ld_mhl_b, 8, "LD [HL], B"),
+    (ld_mhl_c, 8, "LD [HL], C"),
+    (ld_mhl_d, 8, "LD [HL], D"),
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
@@ -131,7 +131,7 @@ pub const INSTRUCTIONS: [(fn(&mut Cpu), u8, &'static str); 256] = [
     (ld_mhl_a, 8, "LD [HL], A"),
     (ld_a_b, 4, "LD A, B"),
     (ld_a_c, 4, "LD A, C"),
-    (noimpl, 4, "! UNIMP !"),
+    (ld_a_d, 4, "LD A, D"),
     (ld_a_e, 4, "LD A, E"),
     (ld_a_h, 4, "LD A, H"),
     (ld_a_l, 4, "LD A, L"),
@@ -186,7 +186,7 @@ pub const INSTRUCTIONS: [(fn(&mut Cpu), u8, &'static str); 256] = [
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
-    (noimpl, 4, "! UNIMP !"),
+    (xor_a_mhl, 8, "XOR A, [HL]"),
     (xor_a_a, 4, "XOR A, A"),
     // 0xb opcodes
     (or_a_b, 4, "OR A, B"),
@@ -254,7 +254,7 @@ pub const INSTRUCTIONS: [(fn(&mut Cpu), u8, &'static str); 256] = [
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
-    (noimpl, 4, "! UNIMP !"),
+    (xor_a_u8, 8, "XOR A, u8"),
     (rst_18h, 16, "RST 18h"),
     // 0xf opcodes
     (ld_a_mff00u8, 12, "LD A, [FF00+u8]"),
@@ -275,7 +275,7 @@ pub const INSTRUCTIONS: [(fn(&mut Cpu), u8, &'static str); 256] = [
     (rst_38h, 16, "RST 38h"),
 ];
 
-pub const BITWISE: [(fn(&mut Cpu), u8, &'static str); 176] = [
+pub const EXTENDED: [(fn(&mut Cpu), u8, &'static str); 176] = [
     // 0x0 opcodes
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
@@ -303,8 +303,8 @@ pub const BITWISE: [(fn(&mut Cpu), u8, &'static str); 176] = [
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
-    (noimpl, 4, "! UNIMP !"),
-    (noimpl, 4, "! UNIMP !"),
+    (rr_c, 8, "RR C"),
+    (rr_d, 8, "RR D"),
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
@@ -336,7 +336,7 @@ pub const BITWISE: [(fn(&mut Cpu), u8, &'static str); 176] = [
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
     (swap_a, 8, "SWAP A"),
-    (noimpl, 4, "! UNIMP !"),
+    (srl_b, 8, "SRL B"),
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
@@ -649,6 +649,18 @@ fn ld_e_u8(cpu: &mut Cpu) {
     cpu.e = byte;
 }
 
+fn rra(cpu: &mut Cpu) {
+    let carry = cpu.get_carry();
+
+    cpu.set_carry(cpu.a & 0x01 == 0x01);
+
+    cpu.a = cpu.a >> 1 | ((carry as u8) << 7);
+
+    cpu.set_sub(false);
+    cpu.set_zero(false);
+    cpu.set_half_carry(false);
+}
+
 fn jr_nz_i8(cpu: &mut Cpu) {
     let byte = cpu.read_u8() as i8;
 
@@ -684,6 +696,22 @@ fn inc_h(cpu: &mut Cpu) {
     cpu.h = value;
 }
 
+fn dec_h(cpu: &mut Cpu) {
+    let h = cpu.h;
+    let value = h.wrapping_sub(1);
+
+    cpu.set_sub(true);
+    cpu.set_zero(value == 0);
+    cpu.set_half_carry((h & 0xf) == 0xf);
+
+    cpu.h = value;
+}
+
+fn ld_h_u8(cpu: &mut Cpu) {
+    let byte = cpu.read_u8();
+    cpu.h = byte;
+}
+
 fn jr_z_i8(cpu: &mut Cpu) {
     let byte = cpu.read_u8() as i8;
 
@@ -711,6 +739,17 @@ fn inc_l(cpu: &mut Cpu) {
     cpu.l = value;
 }
 
+fn dec_l(cpu: &mut Cpu) {
+    let l = cpu.l;
+    let value = l.wrapping_sub(1);
+
+    cpu.set_sub(true);
+    cpu.set_zero(value == 0);
+    cpu.set_half_carry((l & 0xf) == 0xf);
+
+    cpu.l = value;
+}
+
 fn ld_l_u8(cpu: &mut Cpu) {
     let byte = cpu.read_u8();
     cpu.l = byte;
@@ -754,6 +793,17 @@ fn scf(cpu: &mut Cpu) {
     cpu.set_carry(true);
 }
 
+fn jr_c_i8(cpu: &mut Cpu) {
+    let byte = cpu.read_u8();
+
+    if !cpu.get_carry() {
+        return;
+    }
+
+    cpu.pc = (cpu.pc as i16).wrapping_add(byte as i16) as u16;
+    cpu.ticks = cpu.ticks.wrapping_add(4);
+}
+
 fn dec_a(cpu: &mut Cpu) {
     let a = cpu.a;
     let value = a.wrapping_sub(1);
@@ -774,22 +824,53 @@ fn ld_b_h(cpu: &mut Cpu) {
     cpu.b = cpu.h;
 }
 
+fn ld_b_mhl(cpu: &mut Cpu) {
+    let byte = cpu.mmu.read(cpu.hl());
+    cpu.b = byte;
+}
+
 fn ld_b_a(cpu: &mut Cpu) {
     cpu.b = cpu.a;
 }
 
+fn ld_c_mhl(cpu: &mut Cpu) {
+    let byte = cpu.mmu.read(cpu.hl());
+    cpu.c = byte;
+}
+
 fn ld_c_a(cpu: &mut Cpu) {
     cpu.c = cpu.a;
 }
 
+fn ld_d_mhl(cpu: &mut Cpu) {
+    let byte = cpu.mmu.read(cpu.hl());
+    cpu.d = byte;
+}
+
 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 ld_mhl_a(cpu: &mut Cpu) {
     cpu.mmu.write(cpu.hl(), cpu.a);
 }
@@ -802,6 +883,10 @@ 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;
 }
@@ -841,6 +926,16 @@ fn xor_a_c(cpu: &mut Cpu) {
     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;
 
@@ -979,6 +1074,16 @@ fn ld_mu16_a(cpu: &mut Cpu) {
     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);
 }
@@ -1024,23 +1129,52 @@ 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 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_7_h(cpu: &mut Cpu) {
     bit_h(cpu, 7);
 }
 
-/// Helper function that rotates (shifts) the given
+/// Helper function that rotates (shifts) left the given
 /// byte (probably from a register) and updates the
 /// proper flag registers.
-fn rl(cpu: &mut Cpu, byte: u8) -> u8 {
+fn rl(cpu: &mut Cpu, value: u8) -> u8 {
     let carry = cpu.get_carry();
 
-    cpu.set_carry(byte & 0x80 == 0x80);
+    cpu.set_carry(value & 0x80 == 0x80);
 
-    let result = (byte << 1) | carry as u8;
+    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);
@@ -1112,6 +1246,17 @@ fn swap(cpu: &mut Cpu, value: u8) -> u8 {
     (value << 4) | (value >> 4)
 }
 
+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.
-- 
GitLab