fix: implement 0xff41 and fix CALL instruciton

This commit is contained in:
Rekai Nyangadzayi Musuka 2021-01-18 02:22:45 -06:00
parent 386a780a6f
commit 9203b61533
5 changed files with 84 additions and 19 deletions

View File

@ -108,6 +108,10 @@ impl Bus {
0xFF25 => self.sound.control.select.into(), 0xFF25 => self.sound.control.select.into(),
0xFF26 => self.sound.control.status.into(), 0xFF26 => self.sound.control.status.into(),
0xFF40 => self.ppu.lcd_control.into(), 0xFF40 => self.ppu.lcd_control.into(),
0xFF41 => self.ppu.stat.into(),
0xFF42 => self.ppu.pos.scroll_y,
0xFF43 => self.ppu.pos.scroll_x,
0xFF44 => self.ppu.pos.line_y,
0xFF47 => self.ppu.monochrome.bg_palette.into(), 0xFF47 => self.ppu.monochrome.bg_palette.into(),
_ => unimplemented!("Unable to read {:#06X} in I/O Registers", addr), _ => unimplemented!("Unable to read {:#06X} in I/O Registers", addr),
} }
@ -172,6 +176,10 @@ impl Bus {
0xFF25 => self.sound.control.select = byte.into(), 0xFF25 => self.sound.control.select = byte.into(),
0xFF26 => self.sound.control.status = byte.into(), // FIXME: Should we control which bytes are written to here? 0xFF26 => self.sound.control.status = byte.into(), // FIXME: Should we control which bytes are written to here?
0xFF40 => self.ppu.lcd_control = byte.into(), 0xFF40 => self.ppu.lcd_control = byte.into(),
0xFF41 => self.ppu.stat = byte.into(),
0xFF42 => self.ppu.pos.scroll_y = byte,
0xFF43 => self.ppu.pos.scroll_x = byte,
0xFF44 => self.ppu.pos.line_y = byte,
0xFF47 => self.ppu.monochrome.bg_palette = byte.into(), 0xFF47 => self.ppu.monochrome.bg_palette = byte.into(),
_ => unimplemented!("Unable to write to {:#06X} in I/O Registers", addr), _ => unimplemented!("Unable to write to {:#06X} in I/O Registers", addr),
}; };

View File

@ -70,10 +70,10 @@ impl Cpu {
let hl = self.register_pair(RegisterPair::HL); let hl = self.register_pair(RegisterPair::HL);
let sp = self.register_pair(RegisterPair::SP); let sp = self.register_pair(RegisterPair::SP);
println!( // println!(
"A: {:#04X} | BC: {:#06X} | DE: {:#06X} | HL: {:#06X} | SP: {:#06X} | {}", // "A: {:#04X} | BC: {:#06X} | DE: {:#06X} | HL: {:#06X} | SP: {:#06X} | {}",
a, bc, de, hl, sp, flag // a, bc, de, hl, sp, flag
); // );
// Get info from serial port // Get info from serial port
// if self.bus.read_byte(0xFF02) == 0x81 { // if self.bus.read_byte(0xFF02) == 0x81 {

View File

@ -61,7 +61,7 @@ pub enum Registers {
Word(RegisterPair), Word(RegisterPair),
} }
#[derive(Debug, Copy, Clone)] #[derive(Copy, Clone)]
pub enum MATHTarget { pub enum MATHTarget {
HL, HL,
SP, SP,
@ -1026,39 +1026,39 @@ impl Instruction {
match cond { match cond {
JumpCondition::NotZero => { JumpCondition::NotZero => {
if !flags.z { if !flags.z {
Self::push(cpu, nn); Self::push(cpu, pc);
cpu.set_register_pair(RegisterPair::PC, pc + 1); cpu.set_register_pair(RegisterPair::PC, nn);
return Cycles(24); return Cycles(24);
} }
Cycles(12) Cycles(12)
} }
JumpCondition::Zero => { JumpCondition::Zero => {
if flags.z { if flags.z {
Self::push(cpu, nn); Self::push(cpu, pc);
cpu.set_register_pair(RegisterPair::PC, pc + 1); cpu.set_register_pair(RegisterPair::PC, nn);
return Cycles(24); return Cycles(24);
} }
Cycles(12) Cycles(12)
} }
JumpCondition::NotCarry => { JumpCondition::NotCarry => {
if !flags.c { if !flags.c {
Self::push(cpu, nn); Self::push(cpu, pc);
cpu.set_register_pair(RegisterPair::PC, pc + 1); cpu.set_register_pair(RegisterPair::PC, nn);
return Cycles(24); return Cycles(24);
} }
Cycles(12) Cycles(12)
} }
JumpCondition::Carry => { JumpCondition::Carry => {
if flags.c { if flags.c {
Self::push(cpu, nn); Self::push(cpu, pc);
cpu.set_register_pair(RegisterPair::PC, pc + 1); cpu.set_register_pair(RegisterPair::PC, nn);
return Cycles(24); return Cycles(24);
} }
Cycles(12) Cycles(12)
} }
JumpCondition::Always => { JumpCondition::Always => {
Self::push(cpu, nn); Self::push(cpu, pc);
cpu.set_register_pair(RegisterPair::PC, pc + 1); cpu.set_register_pair(RegisterPair::PC, nn);
Cycles(24) Cycles(24)
} }
} }
@ -2038,14 +2038,26 @@ impl std::fmt::Debug for LDTarget {
match *self { match *self {
LDTarget::IndirectC => f.write_str("IndirectC"), LDTarget::IndirectC => f.write_str("IndirectC"),
LDTarget::Register(reg) => write!(f, "{:?}", reg), LDTarget::Register(reg) => write!(f, "{:?}", reg),
LDTarget::IndirectRegister(pair) => write!(f, "{:?}", pair), LDTarget::IndirectRegister(pair) => write!(f, "[{:?}]", pair),
LDTarget::ByteAtAddress(addr) => write!(f, "{:#06X}", addr), LDTarget::ByteAtAddress(addr) => write!(f, "[{:#06X}]", addr),
LDTarget::ImmediateWord(word) => write!(f, "{:#06X}", word), LDTarget::ImmediateWord(word) => write!(f, "{:#06X}", word),
LDTarget::ImmediateByte(byte) => write!(f, "{:#04X}", byte), LDTarget::ImmediateByte(byte) => write!(f, "{:#04X}", byte),
LDTarget::RegisterPair(pair) => write!(f, "{:?}", pair), LDTarget::RegisterPair(pair) => write!(f, "{:?}", pair),
LDTarget::ByteAtAddressWithOffset(byte) => { LDTarget::ByteAtAddressWithOffset(byte) => {
write!(f, "{:#04X}", 0xFF00 + byte as u16) write!(f, "[0xFF00 + {:#04X}, {:#06X}]", byte, 0xFF00 + byte as u16)
} }
} }
} }
} }
impl std::fmt::Debug for MATHTarget {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match *self {
MATHTarget::HL => f.write_str("HL"),
MATHTarget::SP => f.write_str("SP"),
MATHTarget::Register(reg) => write!(f, "{:?}", reg),
MATHTarget::RegisterPair(pair) => write!(f, "{:?}", pair),
MATHTarget::ImmediateByte(byte) => write!(f, "{:#04X}", byte),
}
}
}

View File

@ -11,7 +11,7 @@ fn main() {
let instruction = game_boy.decode(opcode); let instruction = game_boy.decode(opcode);
println!( println!(
"\nAddr: {:#06X} | Opcode: {:#04X} | Instr: {:X?}", "Addr: {:#06X} | Opcode: {:#04X} | Instr: {:X?}",
pc, opcode, instruction pc, opcode, instruction
); );

View File

@ -2,7 +2,9 @@
pub struct PPU { pub struct PPU {
pub lcd_control: LCDControl, pub lcd_control: LCDControl,
pub monochrome: Monochrome, pub monochrome: Monochrome,
pub pos: ScreenPosition,
pub vram: Box<[u8]>, pub vram: Box<[u8]>,
pub stat: LCDStatus,
} }
impl Default for PPU { impl Default for PPU {
@ -10,11 +12,54 @@ impl Default for PPU {
Self { Self {
lcd_control: Default::default(), lcd_control: Default::default(),
monochrome: Default::default(), monochrome: Default::default(),
pos: Default::default(),
stat: Default::default(),
vram: vec![0; 8192].into_boxed_slice(), vram: vec![0; 8192].into_boxed_slice(),
} }
} }
} }
#[derive(Debug, Clone, Copy, Default)]
pub struct LCDStatus {
lyc_eq_ly: bool,
mode2_stat: bool,
mode1_stat: bool,
mode0_stat: bool,
coincidence: bool,
ppu_mode: u8,
}
impl From<u8> for LCDStatus {
fn from(byte: u8) -> Self {
Self {
lyc_eq_ly: (byte >> 6) & 0x01 == 0x01,
mode2_stat: (byte >> 5) & 0x01 == 0x01,
mode1_stat: (byte >> 4) & 0x01 == 0x01,
mode0_stat: (byte >> 3) & 0x01 == 0x01,
coincidence: (byte >> 2) & 0x01 == 0x01,
ppu_mode: byte & 0x03,
}
}
}
impl From<LCDStatus> for u8 {
fn from(status: LCDStatus) -> Self {
0x80 | (status.lyc_eq_ly as u8) << 6
| (status.mode2_stat as u8) << 5
| (status.mode1_stat as u8) << 4
| (status.mode0_stat as u8) << 3
| (status.coincidence as u8) << 2
| (status.ppu_mode & 0x03)
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct ScreenPosition {
pub scroll_y: u8,
pub scroll_x: u8,
pub line_y: u8,
}
#[derive(Debug, Clone, Copy, Default)] #[derive(Debug, Clone, Copy, Default)]
pub struct Monochrome { pub struct Monochrome {
pub bg_palette: BackgroundPalette, pub bg_palette: BackgroundPalette,