feat: implement fetch, decode, execute loop

This commit is contained in:
Rekai Nyangadzayi Musuka 2020-12-23 03:25:16 -06:00
parent e540c86c7e
commit 4d2e0e33f2
6 changed files with 120 additions and 77 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
/target /target
/.idea /.idea
/.vscode /.vscode
/bin

View File

@ -1,20 +1,34 @@
#[derive(Debug, Copy, Clone)] const ROM: &[u8; 256] = include_bytes!("../bin/DMG_ROM.bin");
#[derive(Debug, Copy, Clone, Default)]
pub struct Bus {} pub struct Bus {}
impl Bus { impl Bus {
pub fn read_byte(&self, addr: u16) -> u8 { pub fn read_byte(&self, addr: u16) -> u8 {
unimplemented!() match addr {
0x0000..=0x00FF => {
// Restart and Interrupt Vectors
ROM[addr as usize]
}
_ => unimplemented!(),
}
} }
pub fn write_byte(&mut self, addr: u16, byte: u8) { pub fn write_byte(&mut self, _addr: u16, _byte: u8) {
unimplemented!() unimplemented!()
} }
pub fn read_word(&self, addr: u16) -> u16 { pub fn read_word(&self, addr: u16) -> u16 {
unimplemented!() match addr {
0x0000..=0x00FF => {
// Restart and Interrupt Vectors
(ROM[(addr + 1) as usize] as u16) << 8 | ROM[addr as usize] as u16
}
_ => unimplemented!(),
}
} }
pub fn write_word(&mut self, addr: u16, word: u16) { pub fn write_word(&mut self, _addr: u16, _word: u16) {
unimplemented!() unimplemented!()
} }
} }

View File

@ -1,7 +1,7 @@
use super::bus::Bus; use super::bus::Bus;
use super::instruction::Instruction; use super::instruction::Instruction;
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone, Default)]
pub struct Cpu { pub struct Cpu {
bus: Bus, bus: Bus,
reg: Registers, reg: Registers,
@ -11,6 +11,10 @@ pub struct Cpu {
} }
impl Cpu { impl Cpu {
pub fn new() -> Self {
Default::default()
}
pub fn ime(&self) -> bool { pub fn ime(&self) -> bool {
self.ime self.ime
} }
@ -18,34 +22,47 @@ impl Cpu {
pub fn set_ime(&mut self, enabled: bool) { pub fn set_ime(&mut self, enabled: bool) {
self.ime = enabled; self.ime = enabled;
} }
pub fn inc_pc(&mut self) {
self.reg.pc += 1;
}
} }
impl Cpu { impl Cpu {
fn fetch(&self) -> u8 { pub fn fetch(&mut self) -> u8 {
self.bus.read_byte(self.reg.pc) let opcode = self.bus.read_byte(self.reg.pc);
// TODO: Figure out where to increment the program counter. self.inc_pc();
opcode
} }
fn decode(&self, opcode: u8) -> Instruction { pub fn decode(&mut self, opcode: u8) -> Instruction {
Instruction::from_byte(self, opcode) Instruction::from_byte(self, opcode)
} }
fn execute(&mut self, instruction: Instruction) { pub fn execute(&mut self, instruction: Instruction) {
Instruction::execute(self, instruction); Instruction::execute(self, instruction);
} }
} }
impl Cpu { impl Cpu {
pub fn read_byte(&self, addr: u16) -> u8 { pub fn read_byte(&mut self, addr: u16) -> u8 {
self.bus.read_byte(addr) let byte = self.bus.read_byte(addr);
self.inc_pc();
byte
} }
pub fn write_byte(&mut self, addr: u16, byte: u8) { pub fn write_byte(&mut self, addr: u16, byte: u8) {
self.bus.write_byte(addr, byte) self.bus.write_byte(addr, byte)
} }
pub fn read_word(&self, addr: u16) -> u16 { pub fn read_word(&mut self, addr: u16) -> u16 {
self.bus.read_word(addr) let word = self.bus.read_word(addr);
self.inc_pc();
self.inc_pc();
word
} }
pub fn write_word(&mut self, addr: u16, word: u16) { pub fn write_word(&mut self, addr: u16, word: u16) {
@ -56,8 +73,14 @@ impl Cpu {
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
enum State { enum State {
Execute, Execute,
Halt, // Halt,
Stop, // Stop,
}
impl Default for State {
fn default() -> Self {
Self::Execute
}
} }
impl Cpu { impl Cpu {
@ -70,7 +93,7 @@ impl Cpu {
Register::E => self.reg.e = value, Register::E => self.reg.e = value,
Register::H => self.reg.h = value, Register::H => self.reg.h = value,
Register::L => self.reg.l = value, Register::L => self.reg.l = value,
Register::Flag => self.reg.a = value.into(), Register::Flag => self.reg.a = value,
} }
} }
@ -147,7 +170,7 @@ pub enum RegisterPair {
PC, PC,
} }
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone, Default)]
struct Registers { struct Registers {
a: u8, a: u8,
b: u8, b: u8,
@ -160,7 +183,7 @@ struct Registers {
pc: u16, pc: u16,
} }
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone, Default)]
pub struct Flags { pub struct Flags {
pub z: bool, // Zero Flag pub z: bool, // Zero Flag
pub n: bool, // Negative Flag pub n: bool, // Negative Flag

View File

@ -106,19 +106,6 @@ pub enum InstrRegister {
IndirectHL, // (HL) IndirectHL, // (HL)
} }
#[derive(Debug, Clone, Copy)]
enum InstrRegisterWithC {
A,
B,
C,
D,
E,
H,
L,
IndirectHL, // (HL)
IndirectC, // (0xFF00 + C)
}
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub enum JumpCondition { pub enum JumpCondition {
NotZero, NotZero,
@ -150,9 +137,7 @@ impl Instruction {
RegisterPair::BC RegisterPair::BC
| RegisterPair::DE | RegisterPair::DE
| RegisterPair::HL | RegisterPair::HL
| RegisterPair::SP => { | RegisterPair::SP => cpu.set_register_pair(pair, nn),
cpu.set_register_pair(RegisterPair::try_from(pair).unwrap(), nn)
}
_ => unreachable!(), _ => unreachable!(),
} }
Cycles(12) Cycles(12)
@ -190,19 +175,22 @@ impl Instruction {
// LD A, (BC) | Put value at address BC into A // LD A, (BC) | Put value at address BC into A
// LD A, (DE) | Put value at address DE into A // LD A, (DE) | Put value at address DE into A
let addr = cpu.register_pair(RegisterPair::try_from(pair).unwrap()); let addr = cpu.register_pair(RegisterPair::try_from(pair).unwrap());
cpu.set_register(Register::A, cpu.read_byte(addr)); let byte = cpu.read_byte(addr);
cpu.set_register(Register::A, byte);
} }
InstrRegisterPair::IncrementHL => { InstrRegisterPair::IncrementHL => {
// LD A, (HL+) | Put value at address HL into A, then increment HL // LD A, (HL+) | Put value at address HL into A, then increment HL
let addr = cpu.register_pair(RegisterPair::HL); let addr = cpu.register_pair(RegisterPair::HL);
cpu.set_register(Register::A, cpu.read_byte(addr)); let byte = cpu.read_byte(addr);
cpu.set_register(Register::A, byte);
cpu.set_register_pair(RegisterPair::HL, addr + 1); cpu.set_register_pair(RegisterPair::HL, addr + 1);
} }
InstrRegisterPair::DecrementHL => { InstrRegisterPair::DecrementHL => {
// LD A, (HL-) | Put value at address HL into A, then increment HL // LD A, (HL-) | Put value at address HL into A, then increment HL
let addr = cpu.register_pair(RegisterPair::HL); let addr = cpu.register_pair(RegisterPair::HL);
cpu.set_register(Register::A, cpu.read_byte(addr)); let byte = cpu.read_byte(addr);
cpu.set_register(Register::A, byte);
cpu.set_register_pair(RegisterPair::HL, addr - 1); cpu.set_register_pair(RegisterPair::HL, addr - 1);
} }
@ -238,7 +226,8 @@ impl Instruction {
} }
(LDTarget::Register(InstrRegister::A), LDTarget::IndirectC) => { (LDTarget::Register(InstrRegister::A), LDTarget::IndirectC) => {
let addr = 0xFF00 + cpu.register(Register::C) as u16; let addr = 0xFF00 + cpu.register(Register::C) as u16;
cpu.set_register(Register::A, cpu.read_byte(addr)); let byte = cpu.read_byte(addr);
cpu.set_register(Register::A, byte);
Cycles(8) Cycles(8)
} }
(LDTarget::Register(lhs), LDTarget::Register(rhs)) => { (LDTarget::Register(lhs), LDTarget::Register(rhs)) => {
@ -256,7 +245,8 @@ impl Instruction {
} }
(LDTarget::Register(InstrRegister::A), LDTarget::ByteAtAddressWithOffset(n)) => { (LDTarget::Register(InstrRegister::A), LDTarget::ByteAtAddressWithOffset(n)) => {
// LD A, (0xFF00 + n) | Store value at address (0xFF00 + n) in register A // LD A, (0xFF00 + n) | Store value at address (0xFF00 + n) in register A
cpu.set_register(Register::A, cpu.read_byte(0xFF00 + (n as u16))); let byte = cpu.read_byte(0xFF00 + (n as u16));
cpu.set_register(Register::A, byte);
Cycles(12) Cycles(12)
} }
( (
@ -272,7 +262,8 @@ impl Instruction {
Cycles(16) Cycles(16)
} }
(LDTarget::Register(InstrRegister::A), LDTarget::ByteAtAddress(nn)) => { (LDTarget::Register(InstrRegister::A), LDTarget::ByteAtAddress(nn)) => {
cpu.set_register(Register::A, cpu.read_byte(nn)); let byte = cpu.read_byte(nn);
cpu.set_register(Register::A, byte);
Cycles(16) Cycles(16)
} }
_ => unreachable!(), _ => unreachable!(),
@ -332,7 +323,7 @@ impl Instruction {
| RegisterPair::HL | RegisterPair::HL
| RegisterPair::SP => { | RegisterPair::SP => {
let hl_value = cpu.register_pair(RegisterPair::HL); let hl_value = cpu.register_pair(RegisterPair::HL);
let value = cpu.register_pair(RegisterPair::try_from(pair).unwrap()); let value = cpu.register_pair(pair);
let sum = Self::add_u16s(hl_value, value, &mut flags); let sum = Self::add_u16s(hl_value, value, &mut flags);
cpu.set_register_pair(RegisterPair::HL, sum); cpu.set_register_pair(RegisterPair::HL, sum);
@ -413,10 +404,8 @@ impl Instruction {
} }
InstrRegister::IndirectHL => { InstrRegister::IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL); let addr = cpu.register_pair(RegisterPair::HL);
cpu.write_byte( let byte = Self::inc_register(cpu.read_byte(addr), &mut flags);
addr, cpu.write_byte(addr, byte);
Self::inc_register(cpu.read_byte(addr), &mut flags),
);
cycles = Cycles(12) cycles = Cycles(12)
} }
} }
@ -471,7 +460,8 @@ impl Instruction {
} }
InstrRegister::IndirectHL => { InstrRegister::IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL); let addr = cpu.register_pair(RegisterPair::HL);
cpu.write_byte(addr, Self::dec_register(cpu.read_byte(addr), &mut flags)); let byte = cpu.read_byte(addr);
cpu.write_byte(addr, Self::dec_register(byte, &mut flags));
cycles = Cycles(12); cycles = Cycles(12);
} }
} }
@ -1058,7 +1048,7 @@ impl Instruction {
// RST n | Push current address onto the stack, jump to 0x0000 + n // RST n | Push current address onto the stack, jump to 0x0000 + n
let addr = cpu.register_pair(RegisterPair::PC); let addr = cpu.register_pair(RegisterPair::PC);
Self::push(cpu, addr); Self::push(cpu, addr);
cpu.set_register_pair(RegisterPair::PC, 0x0000 + (n as u16)); cpu.set_register_pair(RegisterPair::PC, n as u16);
Cycles(16) Cycles(16)
} }
Instruction::RLC(reg) => { Instruction::RLC(reg) => {
@ -1589,7 +1579,7 @@ impl Instruction {
fn u16_half_carry(left: u16, right: u16) -> bool { fn u16_half_carry(left: u16, right: u16) -> bool {
// Self::u8_half_carry((left >> 8) as u8, (right >> 8) as u8) // Self::u8_half_carry((left >> 8) as u8, (right >> 8) as u8)
((left & 0xFFFF) + (right & 0xFFFF)) > 0xFFF // Thanks @Nectar Boy#1003 left + right > 0xFFF // Thanks @Nectar Boy#1003
} }
fn u8_half_carry(left: u8, right: u8) -> bool { fn u8_half_carry(left: u8, right: u8) -> bool {
@ -1619,7 +1609,7 @@ impl Instruction {
} }
impl Instruction { impl Instruction {
pub fn from_byte(cpu: &Cpu, byte: u8) -> Self { pub fn from_byte(cpu: &mut Cpu, byte: u8) -> Self {
if byte == 0xCB { if byte == 0xCB {
Self::from_prefixed_byte(cpu) Self::from_prefixed_byte(cpu)
} else { } else {
@ -1627,7 +1617,7 @@ impl Instruction {
} }
} }
fn from_unprefixed_byte(cpu: &Cpu, opcode: u8) -> Self { fn from_unprefixed_byte(cpu: &mut Cpu, opcode: u8) -> Self {
// https://gb-archive.github.io/salvage/decoding_gbz80_opcodes/Decoding%20Gamboy%20Z80%20Opcodes.html // https://gb-archive.github.io/salvage/decoding_gbz80_opcodes/Decoding%20Gamboy%20Z80%20Opcodes.html
let x = (opcode >> 6) & 0b00000011; let x = (opcode >> 6) & 0b00000011;
let y = (opcode >> 3) & 0b00000111; let y = (opcode >> 3) & 0b00000111;
@ -1635,23 +1625,22 @@ impl Instruction {
let p = y >> 1; let p = y >> 1;
let q = y & 0b00000001; let q = y & 0b00000001;
let n = cpu.read_byte(cpu.register_pair(RegisterPair::PC) + 1); let pc = cpu.register_pair(RegisterPair::PC);
let nn = cpu.read_word(cpu.register_pair(RegisterPair::PC) + 1);
match (x, z, q, y, p) { match (x, z, q, y, p) {
(0, 0, _, 0, _) => Self::NOP, // NOP (0, 0, _, 0, _) => Self::NOP, // NOP
(0, 0, _, 1, _) => Self::LD( (0, 0, _, 1, _) => Self::LD(
// LD (nn), SP // LD (nn), SP
LDTarget::ByteAtAddress(nn), LDTarget::ByteAtAddress(cpu.read_word(pc)),
LDTarget::RegisterPair(RegisterPair::SP), LDTarget::RegisterPair(RegisterPair::SP),
), ),
(0, 0, _, 2, _) => Self::STOP, // STOP (0, 0, _, 2, _) => Self::STOP, // STOP
(0, 0, _, 3, _) => Self::JR(JumpCondition::Always, n as i8), // JR d (0, 0, _, 3, _) => Self::JR(JumpCondition::Always, cpu.read_byte(pc) as i8), // JR d
(0, 0, _, 4..=7, _) => Self::JR(Table::cc(y - 4), n as i8), // JR cc[y - 4], d (0, 0, _, 4..=7, _) => Self::JR(Table::cc(y - 4), cpu.read_byte(pc) as i8), // JR cc[y - 4], d
(0, 1, 0, _, _) => Self::LD( (0, 1, 0, _, _) => Self::LD(
// LD rp[p], nn // LD rp[p], nn
LDTarget::RegisterPair(Table::rp(p)), LDTarget::RegisterPair(Table::rp(p)),
LDTarget::ImmediateWord(nn), LDTarget::ImmediateWord(cpu.read_word(pc)),
), ),
(0, 1, 1, _, _) => Self::ADD( (0, 1, 1, _, _) => Self::ADD(
// ADD HL, rp[p] // ADD HL, rp[p]
@ -1717,7 +1706,7 @@ impl Instruction {
(0, 6, _, _, _) => Self::LD( (0, 6, _, _, _) => Self::LD(
// LD r[y], n // LD r[y], n
LDTarget::Register(Table::r(y)), LDTarget::Register(Table::r(y)),
LDTarget::ImmediateByte(n), LDTarget::ImmediateByte(cpu.read_byte(pc)),
), ),
(0, 7, _, 0, _) => Self::RLCA, (0, 7, _, 0, _) => Self::RLCA,
(0, 7, _, 1, _) => Self::RRCA, (0, 7, _, 1, _) => Self::RRCA,
@ -1737,22 +1726,22 @@ impl Instruction {
(3, 0, _, 0..=3, _) => Self::RET(Table::cc(y)), // RET cc[y] (3, 0, _, 0..=3, _) => Self::RET(Table::cc(y)), // RET cc[y]
(3, 0, _, 4, _) => Self::LD( (3, 0, _, 4, _) => Self::LD(
// LD (0xFF00 + n), A // LD (0xFF00 + n), A
LDTarget::ByteAtAddressWithOffset(n), LDTarget::ByteAtAddressWithOffset(cpu.read_byte(pc)),
LDTarget::Register(InstrRegister::A), LDTarget::Register(InstrRegister::A),
), ),
(3, 0, _, 5, _) => Self::ADD( (3, 0, _, 5, _) => Self::ADD(
// ADD SP, d // ADD SP, d
MATHTarget::RegisterPair(RegisterPair::SP), MATHTarget::RegisterPair(RegisterPair::SP),
MATHTarget::ImmediateByte(n), MATHTarget::ImmediateByte(cpu.read_byte(pc)),
), ),
(3, 0, _, 6, _) => Self::LD( (3, 0, _, 6, _) => Self::LD(
// LD A, (0xFF00 + n) // LD A, (0xFF00 + n)
LDTarget::Register(InstrRegister::A), LDTarget::Register(InstrRegister::A),
LDTarget::ByteAtAddressWithOffset(n), LDTarget::ByteAtAddressWithOffset(cpu.read_byte(pc)),
), ),
(3, 0, _, 7, _) => Self::LDHL(n as i8), // LD HL, SP + d (3, 0, _, 7, _) => Self::LDHL(cpu.read_byte(pc) as i8), // LD HL, SP + d
(3, 1, 0, _, _) => Self::POP(Table::rp2(p)), // POP rp2[p] (3, 1, 0, _, _) => Self::POP(Table::rp2(p)), // POP rp2[p]
(3, 1, 1, _, 0) => Self::RET(JumpCondition::Always), // RET (3, 1, 1, _, 0) => Self::RET(JumpCondition::Always), // RET
(3, 1, 1, _, 1) => Self::RETI, (3, 1, 1, _, 1) => Self::RETI,
(3, 1, 1, _, 2) => Self::JP( (3, 1, 1, _, 2) => Self::JP(
// JP HL // JP HL
@ -1767,7 +1756,7 @@ impl Instruction {
(3, 2, _, 0..=3, _) => Self::JP( (3, 2, _, 0..=3, _) => Self::JP(
// JP cc[y], nn // JP cc[y], nn
Table::cc(y), Table::cc(y),
JPTarget::ImmediateWord(nn), JPTarget::ImmediateWord(cpu.read_word(pc)),
), ),
(3, 2, _, 4, _) => Self::LD( (3, 2, _, 4, _) => Self::LD(
// LD (0xFF00 + C) ,A // LD (0xFF00 + C) ,A
@ -1776,7 +1765,7 @@ impl Instruction {
), ),
(3, 2, _, 5, _) => Self::LD( (3, 2, _, 5, _) => Self::LD(
// LD (nn), A // LD (nn), A
LDTarget::ByteAtAddress(nn), LDTarget::ByteAtAddress(cpu.read_word(pc)),
LDTarget::Register(InstrRegister::A), LDTarget::Register(InstrRegister::A),
), ),
(3, 2, _, 6, _) => Self::LD( (3, 2, _, 6, _) => Self::LD(
@ -1787,12 +1776,12 @@ impl Instruction {
(3, 2, _, 7, _) => Self::LD( (3, 2, _, 7, _) => Self::LD(
// LD A, (nn) // LD A, (nn)
LDTarget::Register(InstrRegister::A), LDTarget::Register(InstrRegister::A),
LDTarget::ByteAtAddress(nn), LDTarget::ByteAtAddress(cpu.read_word(pc)),
), ),
(3, 3, _, 0, _) => Self::JP( (3, 3, _, 0, _) => Self::JP(
// JP nn // JP nn
JumpCondition::Always, JumpCondition::Always,
JPTarget::ImmediateWord(nn), JPTarget::ImmediateWord(cpu.read_word(pc)),
), ),
(3, 3, _, 1, _) => unreachable!("This is the 0xCB Prefix"), (3, 3, _, 1, _) => unreachable!("This is the 0xCB Prefix"),
// (3, 3, _, 2, _) => unreachable!(), ("removed" in documentation) // (3, 3, _, 2, _) => unreachable!(), ("removed" in documentation)
@ -1801,12 +1790,12 @@ impl Instruction {
// (3, 3, _, 5, _) => unreachable!(), ("removed" in documentation) // (3, 3, _, 5, _) => unreachable!(), ("removed" in documentation)
(3, 3, _, 6, _) => Self::DI, (3, 3, _, 6, _) => Self::DI,
(3, 3, _, 7, _) => Self::EI, (3, 3, _, 7, _) => Self::EI,
(3, 4, _, 0..=3, _) => Self::CALL(Table::cc(y), nn), // CALL cc[y], nn (3, 4, _, 0..=3, _) => Self::CALL(Table::cc(y), cpu.read_word(pc)), // CALL cc[y], nn
// (3, 4, _, 4..=7, _) => unreachable!(), ("removed" in documentation) // (3, 4, _, 4..=7, _) => unreachable!(), ("removed" in documentation)
(3, 5, 0, _, _) => Self::PUSH(Table::rp2(p)), // PUSH rp2[p] (3, 5, 0, _, _) => Self::PUSH(Table::rp2(p)), // PUSH rp2[p]
(3, 5, 1, _, 0) => Self::CALL(JumpCondition::Always, nn), // CALL nn (3, 5, 1, _, 0) => Self::CALL(JumpCondition::Always, cpu.read_word(pc)), // CALL nn
// (3, 5, 1, _, 1..=3) => unreachable!(), ("removed" in documentation) // (3, 5, 1, _, 1..=3) => unreachable!(), ("removed" in documentation)
(3, 6, _, _, _) => Table::x3_alu(y, n), (3, 6, _, _, _) => Table::x3_alu(y, cpu.read_byte(pc)),
(3, 7, _, _, _) => Self::RST(y * 8), // RST n (3, 7, _, _, _) => Self::RST(y * 8), // RST n
_ => panic!( _ => panic!(
"Unknown Opcode: {:#x?}\n x: {}, z: {}, q: {}, y: {}, p: {}", "Unknown Opcode: {:#x?}\n x: {}, z: {}, q: {}, y: {}, p: {}",
@ -1815,8 +1804,9 @@ impl Instruction {
} }
} }
fn from_prefixed_byte(cpu: &Cpu) -> Self { fn from_prefixed_byte(cpu: &mut Cpu) -> Self {
let opcode = cpu.read_byte(cpu.register_pair(RegisterPair::PC) + 1); let pc = cpu.register_pair(RegisterPair::PC);
let opcode = cpu.read_byte(pc); // FIXME: Should the PC be incremented here?
// https://gb-archive.github.io/salvage/decoding_gbz80_opcodes/Decoding%20Gamboy%20Z80%20Opcodes.html // https://gb-archive.github.io/salvage/decoding_gbz80_opcodes/Decoding%20Gamboy%20Z80%20Opcodes.html
let x = (opcode >> 6) & 0b00000011; let x = (opcode >> 6) & 0b00000011;

View File

@ -1,3 +1,3 @@
mod cpu;
mod bus; mod bus;
pub mod cpu;
mod instruction; mod instruction;

View File

@ -1,3 +1,18 @@
use gb::cpu::Cpu as LR35902;
fn main() { fn main() {
println!("Hello World!"); let mut game_boy = LR35902::new();
loop {
let pc = game_boy.register_pair(gb::cpu::RegisterPair::PC);
let opcode = game_boy.fetch();
let instruction = game_boy.decode(opcode);
println!(
"Addr: {:#06x} | Opcode: {:#x} | Instr: {:x?}",
pc, opcode, instruction
);
game_boy.execute(instruction);
}
} }