use log::{error, info};
use super::helpers::Splitu16;
#[cfg(test)]
mod tests {
#[allow(unused_imports)]
use super::*;
}
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct GbCore<'rom> {
cpu: Cpu,
memory: Memory<8, 8>,
screen: Screen,
rom: Option<&'rom [u8]>,
}
#[derive(PartialEq, Eq, Clone, Debug)]
struct Screen;
#[derive(PartialEq, Eq, Clone, Debug)]
struct Cpu {
registers: Registers,
}
#[derive(PartialEq, Eq, Clone, Debug)]
struct Memory<const W: usize, const V: usize> {
wram: [u8; W],
vram: [u8; V],
}
impl<const W: usize, const V: usize> Default for Memory<W, V> {
fn default() -> Self {
Memory::<W, V> {
wram: [0x0; W],
vram: [0x0; V],
}
}
}
#[allow(non_snake_case)]
#[derive(PartialEq, Eq, Clone, Debug)]
struct Registers {
AF: Splitu16,
BC: Splitu16,
DE: Splitu16,
HL: Splitu16,
SP: u16,
PC: u16,
}
impl<'rom> GbCore<'rom> {
pub fn new() -> GbCore<'rom> {
GbCore {
cpu: Cpu {
registers: Registers {
AF: Splitu16::from(0x01B0),
BC: Splitu16::from(0x0013),
DE: Splitu16::from(0x00D8),
HL: Splitu16::from(0x014D),
SP: 0xFFFE,
PC: 0x0100,
}
},
memory: Memory::<8, 8>::default(),
screen: Screen,
rom: None,
}
}
pub fn load(&mut self, rom: &'rom [u8]) -> &mut GbCore<'rom> {
self.rom = Some(rom);
self
}
pub fn fetch(&self) -> u8 {
debug_assert!(self.rom.is_some());
self.rom.unwrap()[usize::from(self.cpu.registers.PC)]
}
pub fn fetch_op(&mut self) -> TranslatedOpCode {
let op = self.fetch();
match op & 0xF0 {
0x00 =>
match op & 0xF {
0x0 => TranslatedOpCode::Noop,
_ => {error!("Unkown Op Code {:#04X}", op); todo!();}
},
0x60 =>
match op & 0xF {
0x6 => TranslatedOpCode::LoadHFromHL,
_ => {error!("Unkown Op Code {:#04X}", op); todo!();}
}
0xC0 =>
match op & 0xF {
0x3 => {
let immediate1 = self.inc_pc().fetch();
let immediate2 = self.inc_pc().fetch();
TranslatedOpCode::Jmp(immediate1, immediate2)
},
0xC => {
let address1 = self.inc_pc().fetch();
let address2 = self.inc_pc().fetch();
TranslatedOpCode::CallIfZero(address1, address2)
}
0xE => {
let immediate = self.inc_pc().fetch();
TranslatedOpCode::AccummulatorAdd(immediate)
}
_ => {error!("Unkown Op Code {:#04X}", op); todo!();}
},
_ => {
error!("Unknown Op Code {:#04X}", op);
todo!();
}
}
}
pub fn inc_pc(&mut self) -> &mut GbCore<'rom> {
self.cpu.registers.PC += 1;
self
}
pub fn test(&mut self) {
let mut counter = 1;
loop {
let op = self.fetch_op();
info!("Op {}: {:#?}", counter, op);
self.inc_pc();
counter += 1;
}
}
}
impl Default for GbCore<'_> {
fn default() -> Self {
Self::new()
}
}
#[allow(clippy::upper_case_acronyms)]
#[derive(Clone, Debug)]
pub enum TranslatedOpCode {
Noop,
LoadBC(u8, u8),
StoreAatBC,
IncBC,
IncB,
DecB,
LoadB(u8),
LeftShiftA,
StoreSP(u8, u8),
AddBCtoHL,
LoadAFromBC,
DecBC,
IncC,
DecC,
LoadC(u8),
RightShiftA,
Stop,
LoadDE(u8, u8),
StoreAatDE,
IncDE,
IncD,
DecD,
LoadD(u8),
LeftShiftAWithCary,
JmpForward(u8),
AddDEtoHL,
LoadAFromDE,
DecDE,
IncE,
DecE,
LoadE(u8),
RightShiftAwithCarry,
JmpForwardIfNotZero(u8),
LoadHL(u8, u8),
StoreAatHLandInc,
IncHL,
IncH,
DecH,
LoadH(u8),
DecimalAdjustAfterAddition,
JmpForwardIfZero(u8),
AddHLtoHL,
LoadAFromHLandInc,
DecHL,
IncL,
DecL,
LoadL(u8),
FlipA,
LoadHFromHL,
Jmp(u8, u8),
CallIfZero(u8, u8),
AccummulatorAdd(u8),
}