Skip to content

Commit

Permalink
Implemented RES instructions
Browse files Browse the repository at this point in the history
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()`
  • Loading branch information
velllu committed Nov 19, 2023
1 parent b459121 commit edcb414
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 81 deletions.
29 changes: 17 additions & 12 deletions src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
155 changes: 86 additions & 69 deletions src/cpu/cb_opcodes.rs
Original file line number Diff line number Diff line change
@@ -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 <bit offset>, 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, <bit offset>
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, <bit offset>
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 <bit offset>, 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, <bit offset>
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),
}
Expand Down
1 change: 1 addition & 0 deletions src/cpu/opcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
24 changes: 24 additions & 0 deletions src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}

0 comments on commit edcb414

Please sign in to comment.