fix: implement 0xff41 and fix CALL instruciton
This commit is contained in:
parent
386a780a6f
commit
9203b61533
|
@ -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),
|
||||||
};
|
};
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
45
src/ppu.rs
45
src/ppu.rs
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue