From edcb414ff4bb687f86b75654b25795ef625a655c Mon Sep 17 00:00:00 2001 From: velllu <91963404+velllu@users.noreply.github.com> Date: Sun, 19 Nov 2023 22:28:22 +0100 Subject: [PATCH] Implemented `RES` instructions And also: - Made `get_bit()` function into a new `Bit` trait, with a new `set_bit()` as well - Renamed `GameBoy.bit()` to `GameBoy.bit_r()` - Added tests for `u8.get_bit()` and `u8.set_bit()` --- src/common.rs | 29 ++++---- src/cpu/cb_opcodes.rs | 155 +++++++++++++++++++++++------------------- src/cpu/opcodes.rs | 1 + src/tests.rs | 24 +++++++ 4 files changed, 128 insertions(+), 81 deletions(-) diff --git a/src/common.rs b/src/common.rs index 91add63..0d3b435 100644 --- a/src/common.rs +++ b/src/common.rs @@ -20,16 +20,21 @@ pub(crate) enum BitwiseOperation { Xor, } -/// Get a specific bit from a `u8` -/// # Examples -/// ``` -/// use emulator::common::get_bit; -/// -/// let x: u8 = 0b0010_0000; -/// assert_eq!(true, get_bit(0b0010_0000, 5)); -/// assert_eq!(true, get_bit(0b0000_0001, 0)); -/// assert_eq!(false, get_bit(0b0000_0001, 6)); -/// ``` -pub fn get_bit(value: u8, offset: u8) -> bool { - (value >> offset) & 0b00000001 == 1 +pub(crate) trait Bit { + fn get_bit(&self, offset: Self) -> bool; + fn set_bit(&mut self, offset: Self, value: bool); +} + +impl Bit for u8 { + fn get_bit(&self, offset: u8) -> bool { + (self >> offset) & 0b00000001 != 0 + } + + fn set_bit(&mut self, offset: u8, value: bool) { + if value { + *self |= 1 << offset; + } else { + *self &= !(1 << offset); + } + } } diff --git a/src/cpu/cb_opcodes.rs b/src/cpu/cb_opcodes.rs index 99537e1..9f6ce42 100644 --- a/src/cpu/cb_opcodes.rs +++ b/src/cpu/cb_opcodes.rs @@ -1,87 +1,104 @@ -use crate::{common::get_bit, GameBoy}; +use crate::{common::Bit, registers::OneByteRegister, GameBoy}; use super::{Bytes, Cycles}; impl GameBoy { - fn bit(&mut self, value: u8, offset: u8) { - self.flags.zero = get_bit(value, offset); + fn bit_r(&mut self, value: u8, offset: u8) { + self.flags.zero = value.get_bit(offset); self.flags .update_zero_flag(if self.flags.zero { 1 } else { 0 }); } + + fn reset_ram(&mut self, address: u16, offset: u8) { + let mut byte_from_ram = self.bus[address].clone(); + byte_from_ram.set_bit(offset, false); + + self.bus[address] = byte_from_ram; + } } impl GameBoy { #[rustfmt::skip] pub(crate) fn interpret_cb_opcode(&mut self, opcode: u8) -> (Bytes, Cycles) { match opcode { - // BIT , R - 0x40 => { self.bit(self.registers.b, 0); (1, 2) }, - 0x41 => { self.bit(self.registers.c, 0); (1, 2) }, - 0x42 => { self.bit(self.registers.d, 0); (1, 2) }, - 0x43 => { self.bit(self.registers.e, 0); (1, 2) }, - 0x44 => { self.bit(self.registers.h, 0); (1, 2) }, - 0x45 => { self.bit(self.registers.l, 0); (1, 2) }, - 0x47 => { self.bit(self.registers.a, 0); (1, 2) }, - 0x48 => { self.bit(self.registers.b, 1); (1, 2) }, - 0x49 => { self.bit(self.registers.c, 1); (1, 2) }, - 0x4A => { self.bit(self.registers.d, 1); (1, 2) }, - 0x4B => { self.bit(self.registers.e, 1); (1, 2) }, - 0x4C => { self.bit(self.registers.h, 1); (1, 2) }, - 0x4D => { self.bit(self.registers.l, 1); (1, 2) }, - 0x4F => { self.bit(self.registers.a, 1); (1, 2) }, - 0x50 => { self.bit(self.registers.b, 2); (1, 2) }, - 0x51 => { self.bit(self.registers.c, 2); (1, 2) }, - 0x52 => { self.bit(self.registers.d, 2); (1, 2) }, - 0x53 => { self.bit(self.registers.e, 2); (1, 2) }, - 0x54 => { self.bit(self.registers.h, 2); (1, 2) }, - 0x55 => { self.bit(self.registers.l, 2); (1, 2) }, - 0x57 => { self.bit(self.registers.a, 2); (1, 2) }, - 0x58 => { self.bit(self.registers.b, 3); (1, 2) }, - 0x59 => { self.bit(self.registers.c, 3); (1, 2) }, - 0x5A => { self.bit(self.registers.d, 3); (1, 2) }, - 0x5B => { self.bit(self.registers.e, 3); (1, 2) }, - 0x5C => { self.bit(self.registers.h, 3); (1, 2) }, - 0x5D => { self.bit(self.registers.l, 3); (1, 2) }, - 0x5F => { self.bit(self.registers.a, 3); (1, 2) }, - 0x60 => { self.bit(self.registers.b, 4); (1, 2) }, - 0x61 => { self.bit(self.registers.c, 4); (1, 2) }, - 0x62 => { self.bit(self.registers.d, 4); (1, 2) }, - 0x63 => { self.bit(self.registers.e, 4); (1, 2) }, - 0x64 => { self.bit(self.registers.h, 4); (1, 2) }, - 0x65 => { self.bit(self.registers.l, 4); (1, 2) }, - 0x67 => { self.bit(self.registers.a, 4); (1, 2) }, - 0x68 => { self.bit(self.registers.b, 5); (1, 2) }, - 0x69 => { self.bit(self.registers.c, 5); (1, 2) }, - 0x6A => { self.bit(self.registers.d, 5); (1, 2) }, - 0x6B => { self.bit(self.registers.e, 5); (1, 2) }, - 0x6C => { self.bit(self.registers.h, 5); (1, 2) }, - 0x6D => { self.bit(self.registers.l, 5); (1, 2) }, - 0x6F => { self.bit(self.registers.a, 5); (1, 2) }, - 0x70 => { self.bit(self.registers.b, 6); (1, 2) }, - 0x71 => { self.bit(self.registers.c, 6); (1, 2) }, - 0x72 => { self.bit(self.registers.d, 6); (1, 2) }, - 0x73 => { self.bit(self.registers.e, 6); (1, 2) }, - 0x74 => { self.bit(self.registers.h, 6); (1, 2) }, - 0x75 => { self.bit(self.registers.l, 6); (1, 2) }, - 0x77 => { self.bit(self.registers.a, 6); (1, 2) }, - 0x78 => { self.bit(self.registers.b, 7); (1, 2) }, - 0x79 => { self.bit(self.registers.c, 7); (1, 2) }, - 0x7A => { self.bit(self.registers.d, 7); (1, 2) }, - 0x7B => { self.bit(self.registers.e, 7); (1, 2) }, - 0x7C => { self.bit(self.registers.h, 7); (1, 2) }, - 0x7D => { self.bit(self.registers.l, 7); (1, 2) }, - 0x7F => { self.bit(self.registers.a, 7); (1, 2) }, + // BIT R, + 0x40 => { self.bit_r(self.registers.b, 0); (1, 2) }, + 0x41 => { self.bit_r(self.registers.c, 0); (1, 2) }, + 0x42 => { self.bit_r(self.registers.d, 0); (1, 2) }, + 0x43 => { self.bit_r(self.registers.e, 0); (1, 2) }, + 0x44 => { self.bit_r(self.registers.h, 0); (1, 2) }, + 0x45 => { self.bit_r(self.registers.l, 0); (1, 2) }, + 0x47 => { self.bit_r(self.registers.a, 0); (1, 2) }, + 0x48 => { self.bit_r(self.registers.b, 1); (1, 2) }, + 0x49 => { self.bit_r(self.registers.c, 1); (1, 2) }, + 0x4A => { self.bit_r(self.registers.d, 1); (1, 2) }, + 0x4B => { self.bit_r(self.registers.e, 1); (1, 2) }, + 0x4C => { self.bit_r(self.registers.h, 1); (1, 2) }, + 0x4D => { self.bit_r(self.registers.l, 1); (1, 2) }, + 0x4F => { self.bit_r(self.registers.a, 1); (1, 2) }, + 0x50 => { self.bit_r(self.registers.b, 2); (1, 2) }, + 0x51 => { self.bit_r(self.registers.c, 2); (1, 2) }, + 0x52 => { self.bit_r(self.registers.d, 2); (1, 2) }, + 0x53 => { self.bit_r(self.registers.e, 2); (1, 2) }, + 0x54 => { self.bit_r(self.registers.h, 2); (1, 2) }, + 0x55 => { self.bit_r(self.registers.l, 2); (1, 2) }, + 0x57 => { self.bit_r(self.registers.a, 2); (1, 2) }, + 0x58 => { self.bit_r(self.registers.b, 3); (1, 2) }, + 0x59 => { self.bit_r(self.registers.c, 3); (1, 2) }, + 0x5A => { self.bit_r(self.registers.d, 3); (1, 2) }, + 0x5B => { self.bit_r(self.registers.e, 3); (1, 2) }, + 0x5C => { self.bit_r(self.registers.h, 3); (1, 2) }, + 0x5D => { self.bit_r(self.registers.l, 3); (1, 2) }, + 0x5F => { self.bit_r(self.registers.a, 3); (1, 2) }, + 0x60 => { self.bit_r(self.registers.b, 4); (1, 2) }, + 0x61 => { self.bit_r(self.registers.c, 4); (1, 2) }, + 0x62 => { self.bit_r(self.registers.d, 4); (1, 2) }, + 0x63 => { self.bit_r(self.registers.e, 4); (1, 2) }, + 0x64 => { self.bit_r(self.registers.h, 4); (1, 2) }, + 0x65 => { self.bit_r(self.registers.l, 4); (1, 2) }, + 0x67 => { self.bit_r(self.registers.a, 4); (1, 2) }, + 0x68 => { self.bit_r(self.registers.b, 5); (1, 2) }, + 0x69 => { self.bit_r(self.registers.c, 5); (1, 2) }, + 0x6A => { self.bit_r(self.registers.d, 5); (1, 2) }, + 0x6B => { self.bit_r(self.registers.e, 5); (1, 2) }, + 0x6C => { self.bit_r(self.registers.h, 5); (1, 2) }, + 0x6D => { self.bit_r(self.registers.l, 5); (1, 2) }, + 0x6F => { self.bit_r(self.registers.a, 5); (1, 2) }, + 0x70 => { self.bit_r(self.registers.b, 6); (1, 2) }, + 0x71 => { self.bit_r(self.registers.c, 6); (1, 2) }, + 0x72 => { self.bit_r(self.registers.d, 6); (1, 2) }, + 0x73 => { self.bit_r(self.registers.e, 6); (1, 2) }, + 0x74 => { self.bit_r(self.registers.h, 6); (1, 2) }, + 0x75 => { self.bit_r(self.registers.l, 6); (1, 2) }, + 0x77 => { self.bit_r(self.registers.a, 6); (1, 2) }, + 0x78 => { self.bit_r(self.registers.b, 7); (1, 2) }, + 0x79 => { self.bit_r(self.registers.c, 7); (1, 2) }, + 0x7A => { self.bit_r(self.registers.d, 7); (1, 2) }, + 0x7B => { self.bit_r(self.registers.e, 7); (1, 2) }, + 0x7C => { self.bit_r(self.registers.h, 7); (1, 2) }, + 0x7D => { self.bit_r(self.registers.l, 7); (1, 2) }, + 0x7F => { self.bit_r(self.registers.a, 7); (1, 2) }, + + // BIT RAM, + 0x46 => { self.bit_r(self.bus[self.registers.get_hl()], 0); (1, 3) }, + 0x4E => { self.bit_r(self.bus[self.registers.get_hl()], 1); (1, 3) }, + 0x56 => { self.bit_r(self.bus[self.registers.get_hl()], 2); (1, 3) }, + 0x5E => { self.bit_r(self.bus[self.registers.get_hl()], 3); (1, 3) }, + 0x66 => { self.bit_r(self.bus[self.registers.get_hl()], 4); (1, 3) }, + 0x6E => { self.bit_r(self.bus[self.registers.get_hl()], 5); (1, 3) }, + 0x76 => { self.bit_r(self.bus[self.registers.get_hl()], 6); (1, 3) }, + 0x7E => { self.bit_r(self.bus[self.registers.get_hl()], 7); (1, 3) }, - // BIT , RAM - 0x46 => { self.bit(self.bus[self.registers.get_hl()], 0); (1, 3) }, - 0x4E => { self.bit(self.bus[self.registers.get_hl()], 1); (1, 3) }, - 0x56 => { self.bit(self.bus[self.registers.get_hl()], 2); (1, 3) }, - 0x5E => { self.bit(self.bus[self.registers.get_hl()], 3); (1, 3) }, - 0x66 => { self.bit(self.bus[self.registers.get_hl()], 4); (1, 3) }, - 0x6E => { self.bit(self.bus[self.registers.get_hl()], 5); (1, 3) }, - 0x76 => { self.bit(self.bus[self.registers.get_hl()], 6); (1, 3) }, - 0x7E => { self.bit(self.bus[self.registers.get_hl()], 7); (1, 3) }, + // RESET RAM, + 0x86 => { self.reset_ram(self.registers.get_hl(), 0); (1, 4) } + 0x8E => { self.reset_ram(self.registers.get_hl(), 1); (1, 4) } + 0x96 => { self.reset_ram(self.registers.get_hl(), 2); (1, 4) } + 0x9E => { self.reset_ram(self.registers.get_hl(), 3); (1, 4) } + 0xA6 => { self.reset_ram(self.registers.get_hl(), 4); (1, 4) } + 0xAE => { self.reset_ram(self.registers.get_hl(), 5); (1, 4) } + 0xB6 => { self.reset_ram(self.registers.get_hl(), 6); (1, 4) } + 0xBE => { self.reset_ram(self.registers.get_hl(), 7); (1, 4) } _ => panic!("Opcode 0xcb{:x} not implemented yet", opcode), } diff --git a/src/cpu/opcodes.rs b/src/cpu/opcodes.rs index e5e56b9..7e14ff6 100644 --- a/src/cpu/opcodes.rs +++ b/src/cpu/opcodes.rs @@ -18,6 +18,7 @@ use super::{Bytes, Cycles}; // rr -> two byte register // ii -> the two bytes of immediate data // i -> the first byte of immediate data +// ram -> a byte from ram // INC/DEC function impl GameBoy { diff --git a/src/tests.rs b/src/tests.rs index 2b58fd4..b908ae8 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -119,4 +119,28 @@ mod cpu { assert_eq!(0x0022, gb.registers.sp); assert_eq!(0x0000, gb.registers.pc); } + + mod common { + use crate::common::Bit; + + #[test] + fn get_bit() { + assert!(0b0000_1000_u8.get_bit(3)); + assert!(0b1000_0000_u8.get_bit(7)); + } + + #[test] + fn set_bit() { + let mut blank_int: u8 = 0b0000_0000; + + blank_int.set_bit(3, true); + assert_eq!(blank_int, 0b0000_1000); + + blank_int.set_bit(7, true); + assert_eq!(blank_int, 0b1000_1000); + + blank_int.set_bit(3, false); + assert_eq!(blank_int, 0b1000_0000); + } + } }