Restart GB Emulator

This commit is contained in:
Rekai Musuka 2020-08-04 17:58:48 -05:00
parent 9032716346
commit 8b475cb4cf
4 changed files with 82 additions and 729 deletions

14
src/bus.rs Normal file
View File

@ -0,0 +1,14 @@
#[derive(Debug, Copy, Clone)]
pub struct MemoryBus {
}
impl MemoryBus {
pub fn read_byte(&self, _address: u16) {
unimplemented!()
}
pub fn write_byte(&self, _address: u16) {
unimplemented!()
}
}

View File

@ -1,365 +1,91 @@
// use super::instructions::Instruction;
use super::bus::MemoryBus;
use std::ops::{Index, IndexMut};
use std::convert::From;
// Gameboy CPU
#[derive(Debug, Copy, Clone)]
pub struct LR35902 {
_sp: u16,
_pc: u16,
_reg: Registers,
bus: MemoryBus,
registers: Registers,
sp: u16, // Stack Pointer
pc: u16, // Program Counter
flag: Flag, // Flag Register
ime: bool, // Interrupt Master Enable Flag
}
impl LR35902 {
pub fn cycle(&mut self) {
let opcode = Self::fetch();
self.decode(opcode);
Self::execute();
}
#[derive(Debug, Copy, Clone)]
pub struct Flag {
z: bool, // Zero Flag
n: bool, // Subtract Flag
h: bool, // Half-Carry Flag
c: bool, // Carry Flag
}
fn fetch() -> u8 {
unimplemented!()
}
fn decode(&mut self, opcode: u8) {
// Source: https://gb-archive.github.io/salvage/decoding_gbz80_opcodes/Decoding%20Gamboy%20Z80%20Opcodes.html
// x = the opcode's 1st octal digit (i.e. bits 7-6)
// y = the opcode's 2nd octal digit (i.e. bits 5-3)
// z = the opcode's 3rd octal digit (i.e. bits 2-0)
// p = y right-shifted one position (i.e. bits 5-4)
// q = y modulo 2 (i.e. bit 3)
let x = opcode >> 6;
let y = (opcode & 0b00111000) >> 3; // 0b00111000 = 0x38
let z = opcode & 0b00000111; // 0b00000111 = 0x07
let p = y >> 1;
let q = y & 0b00000001; // 0b001 = 0x1;
let _d: i8 = 0; // Displacement Byte
let _n: u8 = 0; // 8-bit Immediate Operand
let _nn: u16 = 0; // 16-bit Immediate Operand
match (x, z, q, y, p) {
(0, 0, _, 0, _) => {}
_ => panic!("Unexpected Opcode!"),
impl From<u8> for Flag {
fn from(num: u8) -> Self {
Flag {
z: (num >> 7) == 1,
n: ((num >> 6) & 0x01) == 1,
h: ((num >> 5) & 0x01) == 1,
c: ((num >> 4) & 0x01) == 1,
}
}
fn execute() {
unimplemented!()
}
impl From<Flag> for u8 {
fn from(flag: Flag) -> Self {
(flag.z as u8) << 7 | (flag.n as u8) << 6 | (flag.h as u8) << 5 | (flag.c as u8) << 4
}
}
#[derive(Debug, Copy, Clone, Default)]
#[derive(Debug, Copy, Clone)]
pub struct Registers {
a: u8, // Accumulator Register
a: u8,
b: u8,
c: u8,
d: u8,
e: u8,
h: u8,
l: u8,
f: Flag,
}
impl Registers {
pub fn set_af(&mut self, value: u16) {
let (high, low) = Self::split_u16(value);
impl Index<Register> for Registers {
type Output = u8;
self.a = high;
self.f = low.into();
}
pub fn get_af(&self) -> u16 {
Self::merge_u8s(self.a, self.f.into())
}
pub fn set_bc(&mut self, value: u16) {
let (high, low) = Self::split_u16(value);
self.b = high;
self.c = low;
}
pub fn get_bc(&self) -> u16 {
Self::merge_u8s(self.b, self.c)
}
pub fn set_de(&mut self, value: u16) {
let (high, low) = Self::split_u16(value);
self.d = high;
self.e = low;
}
pub fn get_de(&self) -> u16 {
Self::merge_u8s(self.d, self.e)
}
pub fn set_hl(&mut self, value: u16) {
let (high, low) = Self::split_u16(value);
self.h = high;
self.l = low;
}
pub fn get_hl(&self) -> u16 {
Self::merge_u8s(self.h, self.l)
}
pub fn set_a(&mut self, a: u8) {
self.a = a;
}
pub fn get_a(&self) -> u8 {
self.a
}
pub fn set_b(&mut self, b: u8) {
self.b = b;
}
pub fn get_b(&self) -> u8 {
self.b
}
pub fn set_c(&mut self, c: u8) {
self.c = c;
}
pub fn get_c(&self) -> u8 {
self.c
}
pub fn set_d(&mut self, d: u8) {
self.d = d;
}
pub fn get_d(&self) -> u8 {
self.d
}
pub fn set_e(&mut self, e: u8) {
self.e = e;
}
pub fn get_e(&self) -> u8 {
self.e
}
pub fn set_h(&mut self, h: u8) {
self.h = h;
}
pub fn get_h(&self) -> u8 {
self.h
}
pub fn set_l(&mut self, l: u8) {
self.l = l;
}
pub fn get_l(&self) -> u8 {
self.l
}
pub fn set_f<F: Into<Flag>>(&mut self, flag: F) {
self.f = flag.into();
}
pub fn get_f(&self) -> Flag {
self.f
}
pub fn get_u8_f(&self) -> u8 {
self.f.into()
}
fn split_u16(value: u16) -> (u8, u8) {
((value >> 8) as u8, value as u8)
}
fn merge_u8s(left: u8, right: u8) -> u16 {
(left as u16) << 8 | right as u16
}
}
#[derive(Debug, Copy, Clone, Default)]
pub struct Flag(u8);
impl Flag {
pub fn get_zf(&self) -> bool {
(self.0 >> 7) == 1
}
pub fn set_zf(&mut self, enabled: bool) {
if enabled {
self.0 |= 0b10000000; // Set
} else {
self.0 &= 0b01111111; // Clear
}
}
pub fn get_n(&self) -> bool {
((self.0 >> 6) & 0x01) == 1
}
pub fn set_n(&mut self, enabled: bool) {
if enabled {
self.0 |= 0b01000000; // Set
} else {
self.0 &= 0b10111111; // Clear
}
}
pub fn get_h(&self) -> bool {
((self.0 >> 5) & 0x01) == 1
}
pub fn set_h(&mut self, enabled: bool) {
if enabled {
self.0 |= 0b00100000; // Set
} else {
self.0 &= 0b11011111; // Clear
}
}
pub fn get_cy(&self) -> bool {
((self.0 >> 4) & 0x01) == 1
}
pub fn set_cy(&mut self, enabled: bool) {
if enabled {
self.0 |= 0b00010000; // Set
} else {
self.0 &= 0b11101111; // Clear
fn index(&self, index: Register) -> &Self::Output {
match index {
Register::A => &self.a,
Register::B => &self.b,
Register::C => &self.c,
Register::D => &self.d,
Register::E => &self.e,
Register::H => &self.h,
Register::L => &self.l,
}
}
}
impl From<u8> for Flag {
fn from(value: u8) -> Self {
Self(value & 0xF0) // Throw out bits 0 -> 3
impl IndexMut<Register> for Registers {
fn index_mut(&mut self, index: Register) -> &mut Self::Output {
match index {
Register::A => &mut self.a,
Register::B => &mut self.b,
Register::C => &mut self.c,
Register::D => &mut self.d,
Register::E => &mut self.e,
Register::H => &mut self.h,
Register::L => &mut self.l,
}
}
}
impl From<Flag> for u8 {
fn from(flag: Flag) -> Self {
flag.0
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn flag_zf_works() {
let mut flag: Flag = Default::default();
flag.set_zf(true);
assert_eq!(u8::from(flag), 0b10000000);
assert!(flag.get_zf());
flag.set_zf(false);
assert_eq!(u8::from(flag), 0b00000000);
assert!(!flag.get_zf());
}
#[test]
fn flag_n_works() {
let mut flag: Flag = Default::default();
flag.set_n(true);
assert_eq!(u8::from(flag), 0b01000000);
assert!(flag.get_n());
flag.set_n(false);
assert_eq!(u8::from(flag), 0b00000000);
assert!(!flag.get_n());
}
#[test]
fn flag_h_works() {
let mut flag: Flag = Default::default();
flag.set_h(true);
assert_eq!(u8::from(flag), 0b00100000);
assert!(flag.get_h());
flag.set_h(false);
assert_eq!(u8::from(flag), 0b00000000);
assert!(!flag.get_h());
}
#[test]
fn flags_work_together() {
let mut flag: Flag = Default::default();
assert_eq!(u8::from(flag), 0b00000000);
flag.set_zf(true);
flag.set_cy(true);
flag.set_h(true);
flag.set_n(true);
assert_eq!(u8::from(flag), 0b11110000);
assert!(flag.get_zf());
assert!(flag.get_n());
assert!(flag.get_h());
assert!(flag.get_cy());
flag.set_cy(false);
assert_eq!(u8::from(flag), 0b11100000);
assert!(!flag.get_cy());
flag.set_n(false);
assert_eq!(u8::from(flag), 0b10100000);
assert!(!flag.get_n());
}
#[test]
fn flag_to_u8_and_back_works() {
let flag: Flag = 0b10011111.into();
assert_eq!(u8::from(flag), 0b10010000);
assert_eq!(flag.0, 0b10010000);
assert!(flag.get_zf());
assert!(!flag.get_n());
assert!(!flag.get_h());
assert!(flag.get_cy());
let mut base: Flag = Default::default();
base.set_h(true);
base.set_zf(true);
assert_eq!(base.0, 0b10100000);
assert_eq!(u8::from(base), 0b10100000);
}
#[test]
fn flag_cy_works() {
let mut flag: Flag = Default::default();
flag.set_cy(true);
assert_eq!(u8::from(flag), 0b00010000);
assert!(flag.get_cy());
flag.set_cy(false);
assert_eq!(u8::from(flag), 0b00000000);
assert!(!flag.get_cy());
}
#[test]
fn split_u16_works() {
let num = 0xABCD;
let (high, low) = Registers::split_u16(num);
assert_eq!(high, 0xAB);
assert_eq!(low, 0xCD);
}
#[test]
fn merge_u8s_works() {
let left = 0xAB;
let right = 0xCD;
let res = Registers::merge_u8s(left, right);
assert_eq!(res, 0xABCD);
}
#[derive(Debug, Copy, Clone)]
pub enum Register {
A,
B,
C,
D,
E,
H,
L,
}

View File

@ -1,389 +0,0 @@
use super::cpu::Flag;
/// Sharp SM83 Instructions
/// ### Definitions
/// * "Any valid 8-bit register" refers to the registers `B`, `C`, `D`, `E`, `H` and `L`.
/// * If `A` is also a valid register, it will be **explicitly** stated as such.
/// * "Any valid 16-bit register" refers to the registers BC, DE and HL.
/// * If `AF` is a valid register, it will be **explicitly** stated as such.
/// * If `SP` is a valid register, it will be **explicitly** stated as such.
/// * the value of any 16-bit register in brackets is the value of the data located at
/// the address of the 16-bit register.
/// * e.g. the value of `(HL)` would be what is at `memory[cpu.reg.get_hl()]`
/// * Since the value is from memory, the value is an 8-bit integer.
pub struct Instruction {}
impl Instruction {
// *** 8-bit Loads ***
/// `LD nn, n` Store value nn in n.
/// ### Arguments
/// * `nn` Any valid 8-bit or 16-bit register (including `SP`).
/// * `n` An 8-bit immediate value.
pub fn ld_nn_n(nn: u16, n: &mut u8) {
unimplemented!()
}
/// `LD r, r` Store value r2 into r1.
/// ### Arguments
/// * `r1` Any valid 8-bit register (including `A`), and `(HL)`.
/// * `r2` Any valid 8-bit register (including `A`), and `(HL)`.
pub fn ld_r1_r2(r1: &mut u8, r2: u8) {
unimplemented!()
}
/// `LD A, n` Store value n into register A.
/// ### Arguments
/// * `a` The A register
/// * `n` Any valid 8-bit register (including `A`),`(BC)`, `(DE)`, `(HL)`, `(nn)`, and `#`.
/// * `nn` A two byte immediate value (Least significant byte first).
pub fn ld_a_n(a: &mut u8, n: u8) {
unimplemented!()
}
/// `LD n, A` Store register A into n.
/// ### Arguments
/// * `n` Any valid 8-bit register (including `A`), `(BC)`, `(DE)`, `(HL)`, and `(nn)`.
/// * `nn` A two byte immediate value (Least significant byte first).
/// * `a` The A register.
pub fn ld_n_a(n: &mut u8, a: u8) {
unimplemented!()
}
/// `LD A, (C)` Store value at $FF00 + register C in register A.
/// ### Arguments
/// * `a` The A register.
/// * `c` The C register.
pub fn ld_a_c(a: &mut u8, c: u8) {
unimplemented!()
}
/// `LD (C) ,A` Store the value of register A into $FF00 + register C.
/// ### Arguments
/// * `c` The C register.
/// * `a` The A register.
pub fn ld_c_a(c: u8, a: u8) {
unimplemented!()
}
// `LD A, (HLD)` is identical to `LDD A, (HL)`.
// `LD A, (HL-)` is identical to `LDD A, (HL)`.
/// `LDD A, (HL)` Put value at $HL into A, then decrement HL.
///
/// Identical to `LD A, (HLD)`, and `LD A, (HL-)`.
/// ### Arguments
/// * `a` The A register.
/// * `hl` The HL register
pub fn ldd_a_hl(a: &mut u8, hl: u16) {
unimplemented!()
}
// `LD (HLD), A` is identical to `LDD (HL), A`.
// `LD (HL-), A` is identical to `LDD (HL), A`.
/// `LDD (HL), A` Store register A in $HL, then decrement HL.
///
/// Identical to `LD (HLD), A`, and `LD (HL-), A`
/// ### Arguments
/// * `hl` The HL register.
/// * `a` The A register.
pub fn ldd_hl_a(hl: u16, a: u8) {
unimplemented!()
}
// `LD A, (HLI)` is identical to `LDI A, (HL)`.
// `LD A, (HL+)` is identical to `LDI A, (HL)`.
/// `LDI A, (HL)` Store value at $HL in register A, then increment HL.
///
/// Identical to `LD A, (HLI)`, and `LD A, (HL+)`.
/// ### Arguments
/// * `a` The A register.
/// * `hl` The HL register.
pub fn ldi_a_hl(a: &mut u8, hl: u16) {
unimplemented!()
}
// `LD (HLI), A` is identical to `LDI (HL), A`.
// `LD (HL+), A` is identical to `LDI (HL), A`.
/// `LDI (HL), A` Store register A in $HL, then increment HL.
///
/// Identical to `LD (HLI), A`, and `LD (HL+), A`.
/// ### Arguments
/// * `hl` The HL register.
/// * `a` The A register.
pub fn ldi_hl_a(hl: u16, a: u8) {
unimplemented!()
}
/// `LDH (n), A` Store register A into address $FF00 + n.
/// ### Arguments
/// * `n` An 8-bit immediate value.
/// * `a` The A register.
pub fn ldh_n_a(n: u8, a: u8) {
unimplemented!()
}
/// `LDH A, (n)` Store address $FF00 + n in the A register.
/// ### Arguments
/// * `a` The A register.
/// * `n` An 8-bit immediate value
pub fn ldh_a_n(a: &mut u8, n: u8) {
unimplemented!()
}
// *** 16-bit Loads ***
/// `LD n, nn` Store value nn in n.(really?)
/// ### Arguments
/// * `n` Any 16-bit register (including `SP`).
/// * `nn` A 16-bit immediate value.
pub fn ld_n_nn(n: &mut u16, nn: u16) {
unimplemented!()
}
/// `LD SP, HL` Put HL into the stack pointer.
/// ### Arguments
/// * `sp` The stack pointer register.
/// * `hl` The HL register.
pub fn ld_sp_hl(sp: &mut u16, hl: u16) {
unimplemented!()
}
// `LD HL, SP + n` is identical to `LDHL SP, n`.
/// `LDHL SP, n` "Put SP + n effective address into HL".
/// ### Arguments
/// * `hl` The HL register.
/// * `sp` The stack pointer register.
/// * `n` 8-bit **signed** integer.
/// * `f` CPU flags.
///
/// ### Flags
/// * `ZF` Reset.
/// * `N` Reset.
/// * `H` Set / Reset depending on operation.
/// * `CY` Set / Reset depending on operation.
pub fn ldhl_sp_n(hl: &mut u16, sp: u16, n: i8, f: &mut Flag) {
unimplemented!()
}
/// `LD (nn), SP` Store stack pointer at $nn.
/// ### Arguments
/// * `nn` A 16-bit immediate address.
/// * `sp` The stack pointer register.
pub fn ld_nn_sp(nn: u16, sp: u16) {
unimplemented!()
}
/// `PUSH nn` Push 16-bit register onto the stack, then
/// decrement the stack pointer twice.
/// ### Arguments
/// * `nn` Any valid 16-bit address (including `AF`).
/// * `sp` The stack pointer register.
/// * `stack` The stack.
pub fn push_nn(nn: u16, sp: &mut u16, stack: &[u16]) {
unimplemented!()
}
/// `POP nn` Pop two bytes of the stack into register pair nn,
/// then increment the stack pointer twice.
/// ### Arguments
/// `nn` Any valid 16-bit address (including `AF`).
/// `sp` The stack pointer register.
/// `stack` The stack.
pub fn pop_nn(nn: &mut u16, sp: &mut u16, stack: &[u16]) {
unimplemented!()
}
// *** 8-bit ALU ***
/// `ADD A, n` Add n to register A.
/// ### Arguments
/// `A` The A register
/// `nn` Any valid 8-bit register (including `A`), `(HL)`, and `#`.
///
/// ### Flags
/// `ZF` Set if result is zero..
/// `N` Reset.
/// `H` Set if carry from bit 3.
/// `CY` Set if carry from bit 7.
pub fn add_a_n(a: &mut u8, n: u8) {
unimplemented!()
}
/// `ADC A, n` Add n + carry flag to register A.
/// ### Arguments
/// `A` The A register.
/// `n` Any valid 8-bit register (including `A`), `(HL)`, and `#`.
///
/// ### Flags
/// `ZF` Set if result is zero.
/// `N` Reset.
/// `H` Set if carry from bit 3.
/// `CY` Set if carry from bit 7.
pub fn adc_a_n(a: &mut u8, n: u8, f: &mut Flag) {
unimplemented!()
}
/// `SUB n` or `SUB A, n` Subtract n from register A.
/// ### Arguments
/// `A` The A register.
/// `n` Any valid 8-bit register (including `A`), `(HL)`, and `#`.
///
/// ### Flags
/// `ZF` Set if result is 0.
/// `N` Set.
/// `H` Set if no borrow from bit 4.
/// `CY` Set if no borrow.
pub fn sub_a_n(a: &mut u8, n: u8) {
unimplemented!()
}
/// `SBC A, n` Subtract n + carry flag from register A.
/// ### Arguments
/// `A` The A register.
/// `n` Any valid 8-bit register (including `A`), `(HL)`, and `#`.
///
/// ### Flags
/// `ZF` Set if result is 0.
/// `N` Set.
/// `H` Set if no borrow from bit 4.
/// `CY` Set if no borrow.
pub fn sbc_a_n(a: &mut u8, n: u8, f: &mut Flag) {
unimplemented!()
}
/// `AND n` or `AND A, n` AND n with register A,
/// then store the result in register A.
/// ### Arguments
/// `A` The A register.
/// `n` Any valid 8-bit register (including `A`), `(HL)`, and `#`.
///
/// ### Flags
/// `ZF` Set if result is zero.
/// `N` Reset
/// `H` Set
/// `CY` Reset
pub fn and_a_n(a: &mut u8, n: u8, f: &mut Flag) {
unimplemented!()
}
/// `OR n` or `OR A, n` OR n with register A, then store the result in register A
/// ### Arguments
/// `A` The A register.
/// `n` Any valid 8-bit register (including `A`), `(HL)`, and `#`.
///
/// ### Flags
/// `ZF` Set if result is zero.
/// `N` Reset.
/// `H` Reset.
/// `CY` Reset.
pub fn or_a_n(a: &mut u8, n: u8, f: &mut Flag) {
unimplemented!()
}
/// `XOR n` or `XOR A, n` XOR n with register A, then store the result in register A.
/// ### Arguments
/// `A` The A register.
/// `n` Any valid -bit register (including `A`), `(HL)`, and `#`.
///
/// ### Flags
/// `ZF` Set if result is zero.
/// `N` Reset.
/// `H` Reset.
/// `CY` Reset.
pub fn xor_a_n(a: &mut u8, n: u8) {
unimplemented!()
}
/// `CP n` or `CP A, n` Compare register A with n.
///
/// Note: This is equivalent with `SUB A, n` except that the result of the
/// subtraction is discarded. Only the flags are mutated.
/// ### Arguments
/// `A` The A register.
/// `n` Any valid 8-bit register (including `A`), `(HL)`, and `#`.
///
/// ### Flags
/// `ZF` Set if result is zero ( A == n ).
/// `N` Set.
/// `H` Set if no borrow from bit 4.
/// `CY` Set for no borrow. ( A < n ).
pub fn cp_a_n(a: u8, n: u8) {
unimplemented!()
}
/// `INC n` Increment register n.
/// ### Arguments
/// `n` Any valid 8-bit register (including `A`), and `(HL)`.
///
/// ### Flags
/// `ZF` Set if result is zero.
/// `N` Reset.
/// `H` Set if carry from bit 3.
/// `CY` Not affected.
pub fn inc_n(n: &mut u8) {
unimplemented!()
}
/// `DEC n` decrement register n.
/// ### Arguments
/// `n` Any 8-bit register (including `A`), and `(HL)`.
///
/// ### Flags
/// `ZF` Set if result is zero.
/// `N` Set.
/// `H` Set if no borrow from bit 4.
/// `CY` Not affected.
pub fn dec_n(n: &mut u8) {
unimplemented!()
}
// *** 16-bit Arithmetic ***
/// `ADD HL, n` Add n to HL.
/// ### Arguments
/// `hl` The HL register.
/// `n` Any valid 16-bit address (including `SP`).
///
/// ### Flags
/// `ZF` Not affected
/// `N` Reset
/// `H` Set if carry from bit 11.
/// `CY` Set if carry from bit 15.
pub fn add_hl_n(hl: &mut u16, n: u16) {
unimplemented!()
}
/// `ADD SP, n` Add n to the stack pointer.
/// ### Arguments
/// `sp` The stack pointer register.
/// `n` AN 8-bit signed immediate value (#).
///
/// ### Flags
/// `ZF` Reset
/// `N` Reset
/// `H` Set or reset according to operation.
/// `CY` Set or reset according to operation.
pub fn add_sp_n(sp: &mut u16, n: i8) {
unimplemented!()
}
/// `INC nn` Increment register nn
/// ### Arguments
/// `nn` Any valid 16-bit register (including `SP`)
pub fn inc_nn(nn: &mut u16) {
unimplemented!()
}
/// `DEC nn` Increment register nn
/// ### Arguments
/// `nn` Any valid 16-bit register (including `SP`)
pub fn dec_nn(nn: &mut u16) {
unimplemented!()
}
// *** Miscellaneous ***
}

View File

@ -1,2 +1,4 @@
pub use cpu::LR35902;
pub mod bus;
pub mod cpu;
pub mod instructions;