test: add much more tests, fix up a few broken things

This commit is contained in:
EliseZeroTwo 2024-01-04 02:02:23 -07:00
parent d1586b5fce
commit e4b8b67b79
Signed by: elise
GPG key ID: FA8F56FFFE6E8B3E
56 changed files with 339 additions and 99 deletions

View file

@ -0,0 +1 @@
./.github/workflows/action.yml

View file

@ -14,27 +14,103 @@ jobs:
- name: Run cargo tests (meowgb-core)
run: cargo test -p meowgb-core
- name: Run test ROM (blargg cpu_instrs)
if: always()
run: cargo run -p meowgb-tests --release -- test-roms/blargg/roms/cpu_instrs.gb test -m 100000000 -s meowgb-tests/expected_output/cpu_instrs.bin
- name: Run test ROM (blargg instr_timing)
if: always()
run: cargo run -p meowgb-tests --release -- test-roms/blargg/roms/instr_timing.gb test -m 100000000 -s meowgb-tests/expected_output/instr_timing.bin
- name: Run test ROM (blargg mem_timing)
if: always()
run: cargo run -p meowgb-tests --release -- test-roms/blargg/roms/mem_timing.gb test -m 100000000 -s meowgb-tests/expected_output/mem_timing.bin
- name: Run test ROM (mealybug-tearoom-tests intr_1_2_timing)
- name: Run test ROM (mooneye-test-suite basic)
if: always()
run: cargo run -p meowgb-tests --release -- test-roms/mealybug-tearoom-tests/roms/intr_1_2_timing-GS.gb test -m 100000000 -s meowgb-tests/expected_output/intr_1_2_timing-GS.bin
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/basic.gb test -m 100000000 -s meowgb-tests/expected_output/basic.bin
- name: Run test ROM (mealybug-tearoom-tests intr_2_0_timing)
- name: Run test ROM (mooneye-test-suite boot_hwio-dmgABCmgb)
if: always()
run: cargo run -p meowgb-tests --release -- test-roms/mealybug-tearoom-tests/roms/intr_2_0_timing.gb test -m 100000000 -s meowgb-tests/expected_output/intr_2_0_timing.bin
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/boot_hwio-dmgABCmgb.gb test -m 100000000 -s meowgb-tests/expected_output/boot_hwio-dmgABCmgb.bin
- name: Run test ROM (mealybug-tearoom-tests stat_lyc_onoff)
- name: Run test ROM (mooneye-test-suite boot_regs-dmgABC)
if: always()
run: cargo run -p meowgb-tests --release -- test-roms/mealybug-tearoom-tests/roms/stat_lyc_onoff.gb test -m 100000000 -s meowgb-tests/expected_output/stat_lyc_onoff.bin
- name: Run test ROM (mealybug-tearoom-tests stat_irq_blocking)
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/boot_regs-dmgABC.gb test -m 100000000 -s meowgb-tests/expected_output/boot_regs-dmgABC.bin
- name: Run test ROM (mooneye-test-suite daa)
if: always()
run: cargo run -p meowgb-tests --release -- test-roms/mealybug-tearoom-tests/roms/stat_irq_blocking.gb test -m 100000000 -s meowgb-tests/expected_output/stat_irq_blocking.bin
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/daa.gb test -m 100000000 -s meowgb-tests/expected_output/daa.bin
- name: Run test ROM (mooneye-test-suite ei_sequence)
if: always()
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/ei_sequence.gb test -m 100000000 -s meowgb-tests/expected_output/ei_sequence.bin
- name: Run test ROM (mooneye-test-suite ei_timing)
if: always()
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/ei_timing.gb test -m 100000000 -s meowgb-tests/expected_output/ei_timing.bin
- name: Run test ROM (mooneye-test-suite halt_ime0_ei)
if: always()
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/halt_ime0_ei.gb test -m 100000000 -s meowgb-tests/expected_output/halt_ime0_ei.bin
- name: Run test ROM (mooneye-test-suite intr_1_2_timing-GS)
if: always()
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/intr_1_2_timing-GS.gb test -m 100000000 -s meowgb-tests/expected_output/intr_1_2_timing-GS.bin
- name: Run test ROM (mooneye-test-suite intr_2_0_timing)
if: always()
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/intr_2_0_timing.gb test -m 100000000 -s meowgb-tests/expected_output/intr_2_0_timing.bin
- name: Run test ROM (mooneye-test-suite mem_oam)
if: always()
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/mem_oam.gb test -m 100000000 -s meowgb-tests/expected_output/mem_oam.bin
- name: Run test ROM (mooneye-test-suite oam_dma_restart)
if: always()
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/oam_dma_restart.gb test -m 100000000 -s meowgb-tests/expected_output/oam_dma_restart.bin
- name: Run test ROM (mooneye-test-suite oam_dma_start)
if: always()
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/oam_dma_start.gb test -m 100000000 -s meowgb-tests/expected_output/oam_dma_start.bin
- name: Run test ROM (mooneye-test-suite oam_dma_timing)
if: always()
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/oam_dma_timing.gb test -m 100000000 -s meowgb-tests/expected_output/oam_dma_timing.bin
- name: Run test ROM (mooneye-test-suite rapid_di_ei)
if: always()
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/rapid_di_ei.gb test -m 100000000 -s meowgb-tests/expected_output/rapid_di_ei.bin
- name: Run test ROM (mooneye-test-suite reg_f)
if: always()
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/reg_f.gb test -m 100000000 -s meowgb-tests/expected_output/reg_f.bin
- name: Run test ROM (mooneye-test-suite reg_read)
if: always()
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/reg_read.gb test -m 100000000 -s meowgb-tests/expected_output/reg_read.bin
- name: Run test ROM (mooneye-test-suite stat_irq_blocking)
if: always()
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/stat_irq_blocking.gb test -m 100000000 -s meowgb-tests/expected_output/stat_irq_blocking.bin
- name: Run test ROM (mooneye-test-suite stat_lyc_onoff)
if: always()
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/stat_lyc_onoff.gb test -m 100000000 -s meowgb-tests/expected_output/stat_lyc_onoff.bin
- name: Run test ROM (mooneye-test-suite tim00_div_trigger)
if: always()
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/tim00_div_trigger.gb test -m 100000000 -s meowgb-tests/expected_output/tim00_div_trigger.bin
- name: Run test ROM (mooneye-test-suite tim01)
if: always()
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/tim01.gb test -m 100000000 -s meowgb-tests/expected_output/tim01.bin
- name: Run test ROM (mooneye-test-suite tim11_div_trigger)
if: always()
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/tim11_div_trigger.gb test -m 100000000 -s meowgb-tests/expected_output/tim11_div_trigger.bin
- name: Run test ROM (mooneye-test-suite unused_hwio-GS)
if: always()
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/unused_hwio-GS.gb test -m 100000000 -s meowgb-tests/expected_output/unused_hwio-GS.bin

3
.gitignore vendored
View file

@ -3,4 +3,5 @@
/bmp/
config.toml
/.vscode/
out
out
generate-output.sh

55
generate-action.sh Executable file
View file

@ -0,0 +1,55 @@
#!/bin/bash
OUTPUT_FILE=./.github/workflows/action.yml
cat >$OUTPUT_FILE << EOF
on:
- push
jobs:
main_test:
name: Test changes to main
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install toolchain
run: curl https://sh.rustup.rs -sSf | sh -s -- --profile minimal --default-toolchain stable -y && echo "\$HOME/.cargo/bin" >> \$GITHUB_PATH
- name: Run cargo tests (meowgb-core)
run: cargo test -p meowgb-core
EOF
for f in ./test-roms/blargg/roms/*
do
f="${f##*/}"; f="${f%.*}";
cat >>$OUTPUT_FILE << EOF
- name: Run test ROM (blargg $f)
if: always()
run: cargo run -p meowgb-tests --release -- test-roms/blargg/roms/$f.gb test -m 100000000 -s meowgb-tests/expected_output/$f.bin
EOF
done
# for f in ./test-roms/mealybug-tearoom-tests/roms/*
# do
# f="${f##*/}"; f="${f%.*}";
# cat >>$OUTPUT_FILE << EOF
# - name: Run test ROM (mealybug-tearoom-tests $f)
# if: always()
# run: cargo run -p meowgb-tests --release -- test-roms/mealybug-tearoom-tests/roms/$f.gb test -m 100000000 -s meowgb-tests/expected_output/$f.bin
# EOF
# done
for f in ./test-roms/mooneye-test-suite/roms/*
do
f="${f##*/}"; f="${f%.*}";
cat >>$OUTPUT_FILE << EOF
- name: Run test ROM (mooneye-test-suite $f)
if: always()
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/$f.gb test -m 100000000 -s meowgb-tests/expected_output/$f.bin
EOF
done

View file

@ -1,5 +1,6 @@
pub mod bootrom;
pub mod cpu;
pub mod dma;
pub mod interrupts;
pub mod joypad;
pub mod mapper;
@ -22,25 +23,9 @@ use self::{
cpu::Registers,
mapper::{mbc1::MBC1, NoMBC},
serial::{Serial, SerialWriter},
sound::Sound,
sound::Sound, dma::DmaState,
};
pub struct DmaState {
pub base: u8,
pub remaining_cycles: u8,
}
impl DmaState {
pub fn new() -> Self {
Self { base: 0, remaining_cycles: 0 }
}
pub fn init_request(&mut self, base: u8) {
self.base = base;
self.remaining_cycles = 0xA0;
}
}
pub struct RingBuffer<T: std::fmt::Debug + Copy + Default, const SIZE: usize> {
buffer: [T; SIZE],
size: usize,
@ -155,7 +140,7 @@ impl<S: SerialWriter> Gameboy<S> {
true => Registers::default(),
false => Registers::post_rom(),
},
sound: Sound::default(),
sound: Sound::new(),
single_step: false,
breakpoints: [false; u16::MAX as usize + 1],
mem_read_breakpoints: [false; u16::MAX as usize + 1],
@ -402,7 +387,7 @@ impl<S: SerialWriter> Gameboy<S> {
cpu::tick_cpu(self);
let redraw_requested = self.ppu.tick(&mut self.interrupts);
self.tick_dma();
self.dma.tick_dma(&mut self.ppu, &self.memory, self.cartridge.as_deref());
if self.serial.tick() {
self.interrupts.write_if_serial(true);
}
@ -416,39 +401,11 @@ impl<S: SerialWriter> Gameboy<S> {
}
}
fn tick_dma(&mut self) {
self.ppu.dma_occuring = self.dma.remaining_cycles > 0;
if self.dma.remaining_cycles > 0 {
let offset = 0xA0 - self.dma.remaining_cycles;
let value = if self.dma.base <= 0x7F {
match self.cartridge.as_ref() {
Some(cart) => cart.read_rom_u8((self.dma.base as u16) << 8 | offset as u16),
None => 0xFF,
}
} else if self.dma.base <= 0x9F {
let address = (((self.dma.base as usize) << 8) | offset as usize) - 0x8000;
self.ppu.vram[address]
} else if self.dma.base <= 0xDF {
let address = ((self.dma.base as usize) << 8 | offset as usize) - 0xC000;
self.memory.wram[address]
} else if self.dma.base <= 0xFD {
let address = ((self.dma.base as usize) << 8 | offset as usize) - 0xE000;
self.memory.wram[address]
} else {
0xFF
};
self.ppu.dma_write_oam(offset, value);
self.dma.remaining_cycles -= 1;
}
}
fn cpu_read_io(&self, address: u16) -> u8 {
match address {
0xFF00 => self.joypad.cpu_read(),
0xFF01 => self.serial.sb,
0xFF02 => self.serial.sc,
0xFF02 => self.serial.get_sc(),
0xFF03 => 0xFF, // Unused
0xFF04 => self.timer.div,
0xFF05 => self.timer.tima,
@ -495,7 +452,7 @@ impl<S: SerialWriter> Gameboy<S> {
0xFF4B => self.ppu.registers.wx,
0xFF4C..=0xFF4E => 0xFF, // Unused
0xFF4F => 0xFF, // CGB VRAM Bank Select
0xFF50 => self.memory.bootrom_disabled as u8,
0xFF50 => self.memory.get_bootrom_disabled(),
0xFF51..=0xFF55 => 0xFF, // CGB VRAM DMA
0xFF56..=0xFF67 => 0xFF, // Unused
0xFF68..=0xFF69 => 0xFF, // BJ/OBJ Palettes
@ -510,7 +467,7 @@ impl<S: SerialWriter> Gameboy<S> {
match address {
0xFF00 => self.joypad.cpu_write(value),
0xFF01 => self.serial.sb = value,
0xFF02 => self.serial.sc = value,
0xFF02 => self.serial.set_sc(value),
0xFF03 => {} // Unused
0xFF04 => self.timer.div = 0,
0xFF05 => self.timer.tima = value,
@ -518,7 +475,7 @@ impl<S: SerialWriter> Gameboy<S> {
0xFF07 => self.timer.write_tac(value),
0xFF08..=0xFF0E => {} // Unused
0xFF0F => self.interrupts.interrupt_flag = value | !0b1_1111,
0xFF10 => self.sound.nr10 = value,
0xFF10 => {} //self.sound.nr10 = value, - Unwritable on DMG
0xFF11 => self.sound.nr11 = value,
0xFF12 => self.sound.nr12 = value,
0xFF13 => self.sound.nr13 = value,
@ -528,19 +485,19 @@ impl<S: SerialWriter> Gameboy<S> {
0xFF17 => self.sound.nr22 = value,
0xFF18 => self.sound.nr23 = value,
0xFF19 => self.sound.nr24 = value,
0xFF1A => self.sound.nr30 = value,
0xFF1A => {}, //self.sound.nr30 = value, - Unwritable on DMG
0xFF1B => self.sound.nr31 = value,
0xFF1C => self.sound.nr32 = value,
0xFF1C => {}, //self.sound.nr32 = value, - Unwritable on DMG
0xFF1D => self.sound.nr33 = value,
0xFF1E => self.sound.nr34 = value,
0xFF1F => {}
0xFF20 => self.sound.nr41 = value,
0xFF20 => {}, //self.sound.nr41 = value, - Unwritable on DMG
0xFF21 => self.sound.nr42 = value,
0xFF22 => self.sound.nr43 = value,
0xFF23 => self.sound.nr44 = value,
0xFF23 => {}, //self.sound.nr44 = value, - Unwritable on DMG
0xFF24 => self.sound.nr50 = value,
0xFF25 => self.sound.nr51 = value,
0xFF26 => self.sound.nr52 = value,
0xFF26 => {}, //self.sound.nr52 = value, - Unwritable on DMG
0xFF27..=0xFF2F => {}
0xFF30..=0xFF3F => self.sound.wave_pattern_ram[address as usize - 0xFF30] = value,
0xFF40 => {
@ -558,11 +515,7 @@ impl<S: SerialWriter> Gameboy<S> {
0xFF43 => self.ppu.registers.scx = value,
0xFF44 => {} // LY is read only
0xFF45 => self.ppu.set_lyc(&mut self.interrupts, value),
0xFF46 => {
if self.dma.remaining_cycles == 0 {
self.dma.init_request(value);
}
}
0xFF46 => self.dma.init_request(value),
0xFF47 => self.ppu.bgp.write_bgp(value),
0xFF48 => self.ppu.obp[0].write_obp(value),
0xFF49 => self.ppu.obp[1].write_obp(value),
@ -642,12 +595,12 @@ impl<S: SerialWriter> Gameboy<S> {
0xFEA0..=0xFEFF => {}
0xFF00..=0xFF7F => self.cpu_write_io(address, value),
0xFF80..=0xFFFE => self.memory.hram[address as usize - 0xFF80] = value,
0xFFFF => self.interrupts.interrupt_enable = value & 0b1_1111,
0xFFFF => self.interrupts.cpu_set_interrupt_enable(value),
}
}
fn internal_cpu_read_u8(&self, address: u16) -> u8 {
if self.dma.remaining_cycles == 0 {
if !self.ppu.dma_occuring {
match address {
0..=0xFF if !self.memory.bootrom_disabled => self.memory.bootrom[address as usize],
0..=0x7FFF => match self.cartridge.as_ref() {
@ -669,7 +622,7 @@ impl<S: SerialWriter> Gameboy<S> {
}
} else {
match address {
0..=0xFEFF => 0,
0..=0xFEFF => 0xFF,
0xFF00..=0xFF7F => self.cpu_read_io(address),
0xFF80..=0xFFFE => self.memory.hram[address as usize - 0xFF80],
0xFFFF => self.interrupts.interrupt_enable,
@ -699,7 +652,7 @@ impl<S: SerialWriter> Gameboy<S> {
log::info!("Triggered write bp @ {:#X} (value: {:#02X})", address, value);
}
if self.dma.remaining_cycles == 0 {
if !self.ppu.dma_occuring {
match address {
0..=0xFF if !self.memory.bootrom_disabled => {}
0..=0x7FFF => {
@ -719,14 +672,14 @@ impl<S: SerialWriter> Gameboy<S> {
0xFEA0..=0xFEFF => {}
0xFF00..=0xFF7F => self.cpu_write_io(address, value),
0xFF80..=0xFFFE => self.memory.hram[address as usize - 0xFF80] = value,
0xFFFF => self.interrupts.interrupt_enable = value & 0b1_1111,
0xFFFF => self.interrupts.cpu_set_interrupt_enable(value),
}
} else {
match address {
0..=0xFEFF => {}
0xFF00..=0xFF7F => self.cpu_write_io(address, value),
0xFF80..=0xFFFE => self.memory.hram[address as usize - 0xFF80] = value,
0xFFFF => self.interrupts.interrupt_enable = value & 0b1_1111,
0xFFFF => self.interrupts.cpu_set_interrupt_enable(value),
}
}
}

View file

@ -0,0 +1,61 @@
use super::{ppu::Ppu, memory::Memory, mapper::Mapper};
#[derive(Debug)]
pub struct DmaState {
original_base: u8,
pub base: u8,
pub remaining_cycles: u8,
restarting: Option<(u8, bool)>,
}
impl DmaState {
pub fn new() -> Self {
Self { original_base: 0, base: 0, remaining_cycles: 0, restarting: None }
}
pub fn init_request(&mut self, base: u8) {
self.base = base;
self.restarting = Some((base, false));
}
pub fn tick_dma(&mut self, ppu: &mut Ppu, memory: &Memory, cartridge: Option<&(dyn Mapper + Send + Sync)>) {
match self.restarting {
Some((base, false)) => self.restarting = Some((base, true)),
Some((base, true)) => {
self.original_base = base;
self.remaining_cycles = 0xA0;
self.restarting = None;
}
None => {},
}
ppu.dma_occuring = self.remaining_cycles > 0;
if self.remaining_cycles > 0 {
let offset = 0xA0 - self.remaining_cycles;
let value = if self.original_base <= 0x7F {
match cartridge {
Some(cart) => cart.read_rom_u8((self.base as u16) << 8 | offset as u16),
None => 0xFF,
}
} else if self.original_base <= 0x9F {
let address = (((self.original_base as usize) << 8) | offset as usize) - 0x8000;
ppu.vram[address]
} else if self.original_base <= 0xDF {
let address = ((self.original_base as usize) << 8 | offset as usize) - 0xC000;
memory.wram[address]
} else if self.original_base <= 0xFD {
let address = ((self.original_base as usize) << 8 | offset as usize) - 0xE000;
memory.wram[address]
} else {
0xFF
};
ppu.dma_write_oam(offset, value);
self.remaining_cycles -= 1;
}
}
}

View file

@ -27,8 +27,8 @@ impl Interrupts {
pub fn new() -> Self {
Self {
ime: false,
interrupt_enable: 0,
interrupt_flag: 0b11100000,
interrupt_enable: 0b0000_0000,
interrupt_flag: 0b1110_0001,
ei_queued: false,
cycle_passed: false,
}
@ -51,4 +51,8 @@ impl Interrupts {
self.ime = false;
}
}
pub fn cpu_set_interrupt_enable(&mut self, value: u8) {
self.interrupt_enable = value;
}
}

View file

@ -43,7 +43,7 @@ pub struct Joypad {
impl Joypad {
pub fn new() -> Self {
Self {
mode: JoypadMode::Direction,
mode: JoypadMode::Both,
down: false,
up: false,
left: false,
@ -57,7 +57,7 @@ impl Joypad {
}
pub fn cpu_read(&self) -> u8 {
match self.mode {
(0b11 << 6) | match self.mode {
JoypadMode::Action => {
(1 << 4)
| ((!self.start as u8) << 3)
@ -72,7 +72,7 @@ impl Joypad {
| ((!self.left as u8) << 1)
| (!self.right as u8)
}
JoypadMode::Both => 0x3F,
JoypadMode::Both => 0b1111,
}
}

View file

@ -15,4 +15,11 @@ impl Memory {
bootrom_disabled: bootrom.is_none(),
}
}
pub fn get_bootrom_disabled(&self) -> u8 {
match self.bootrom_disabled {
true => 0xFF,
false => 0x00,
}
}
}

View file

@ -3,6 +3,10 @@ use super::interrupts::Interrupts;
pub const FB_HEIGHT: u32 = 144;
pub const FB_WIDTH: u32 = 160;
pub const PIXEL_SIZE: usize = 4; // RGBA
/// Helper for debugging PPU timings that allows read/writes to PPU memory no
/// matter what mode it is in. This also allows the PPU to bypass a DMA
/// currently occuring which is blocking access to the memory bus.
const OVERRIDE_PPU_MEMORY_ACCESS: bool = false;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Palette {
@ -36,7 +40,7 @@ enum LineDrawingState {
impl Palette {
pub fn new_bgp() -> Self {
Self { id0: Color::White, id1: Color::LGray, id2: Color::DGray, id3: Color::Black }
Self { id0: Color::White, id1: Color::Black, id2: Color::Black, id3: Color::Black }
}
pub fn new_obp() -> Self {
@ -325,7 +329,7 @@ impl Ppu {
pub fn new(bootrom_ran: bool) -> Self {
Self {
registers: PpuRegisters {
lcdc: (!bootrom_ran).then_some(0b1000_0000).unwrap_or_default(),
lcdc: (!bootrom_ran).then_some(0b1001_0001).unwrap_or_default(),
stat_flags: StatFlags::default(),
mode: PPUMode::HBlank,
scy: 0,
@ -445,7 +449,7 @@ impl Ppu {
}
fn internal_read_oam(&mut self, offset: usize) -> u8 {
match self.dma_occuring {
match self.dma_occuring && !OVERRIDE_PPU_MEMORY_ACCESS {
true => 0xFF,
false => self.oam[offset as usize],
}
@ -458,7 +462,7 @@ impl Ppu {
pub fn cpu_read_oam(&self, address: u16) -> u8 {
let decoded_address = address - 0xFE00;
if self.enabled() && !self.first_frame {
if self.enabled() && !self.first_frame && !OVERRIDE_PPU_MEMORY_ACCESS {
match self.mode() {
PPUMode::HBlank | PPUMode::VBlank => self.oam[decoded_address as usize],
PPUMode::SearchingOAM | PPUMode::TransferringData => 0xFF,
@ -470,7 +474,7 @@ impl Ppu {
pub fn cpu_write_oam(&mut self, address: u16, value: u8) {
let decoded_address = address - 0xFE00;
if self.enabled() && !self.first_frame {
if self.enabled() && !self.first_frame && !OVERRIDE_PPU_MEMORY_ACCESS {
match self.mode() {
PPUMode::HBlank | PPUMode::VBlank => self.oam[decoded_address as usize] = value,
PPUMode::SearchingOAM | PPUMode::TransferringData => {}
@ -482,7 +486,7 @@ impl Ppu {
pub fn cpu_read_vram(&self, address: u16) -> u8 {
let decoded_address = address - 0x8000;
if self.enabled() && !self.first_frame {
if self.enabled() && !self.first_frame && !OVERRIDE_PPU_MEMORY_ACCESS {
match self.mode() {
PPUMode::HBlank | PPUMode::VBlank | PPUMode::SearchingOAM => {
self.vram[decoded_address as usize]
@ -496,7 +500,7 @@ impl Ppu {
pub fn cpu_write_vram(&mut self, address: u16, value: u8) {
let decoded_address = address - 0x8000;
if self.enabled() && !self.first_frame {
if self.enabled() && !self.first_frame && !OVERRIDE_PPU_MEMORY_ACCESS {
match self.mode() {
PPUMode::HBlank | PPUMode::VBlank | PPUMode::SearchingOAM => {
self.vram[decoded_address as usize] = value
@ -629,9 +633,7 @@ impl Ppu {
false
}
PPUMode::HBlank => {
if self.first_line && self.current_dot == 16 && self.dot_target == 0 {
// Special case for resets
// self.handle_stat_irq(interrupts, false);
if self.first_line && self.current_dot == 64 && self.dot_target == 0 {
self.set_mode(interrupts, PPUMode::TransferringData);
} else if self.dot_target != 0 && self.current_dot == self.dot_target {
self.set_scanline(interrupts, self.registers.ly + 1);
@ -639,7 +641,7 @@ impl Ppu {
assert_eq!(
self.total_dots,
match self.first_frame && self.first_line {
true => 456 - (80 - 16),
true => 456 - (80 - 64),
false => 456,
}
);

View file

@ -15,7 +15,7 @@ impl<T: Write> SerialWriter for T {
pub struct Serial<S: SerialWriter> {
pub sb: u8,
pub sc: u8,
sc: u8,
internal_tick: u16,
writer: S,
@ -39,6 +39,14 @@ impl<S: SerialWriter> Serial<S> {
self.sc & 0b1 == 1
}
pub fn set_sc(&mut self, value: u8) {
self.sc = value | (0b0111_1110);
}
pub fn get_sc(&self) -> u8 {
self.sc | (0b0111_1110)
}
#[allow(unused)]
pub fn set_side(&mut self, conductor: bool) {
self.sc &= !0b1;

View file

@ -1,4 +1,4 @@
#[derive(Debug, Default)]
#[derive(Debug)]
pub struct Sound {
pub nr10: u8,
pub nr11: u8,
@ -28,3 +28,32 @@ pub struct Sound {
pub wave_pattern_ram: [u8; 0x10],
}
impl Sound {
pub fn new() -> Self {
Self {
nr10: 0b1000_0000,
nr11: 0b1011_1111,
nr12: 0b1111_0011,
nr13: 0b1111_1111,
nr14: 0b1011_1111,
nr21: 0b0011_1111,
nr22: 0b0000_0000,
nr23: 0b1111_1111,
nr24: 0b1011_1111,
nr30: 0b0111_1111,
nr31: 0b1111_1111,
nr32: 0b1001_1111,
nr33: 0b1111_1111,
nr34: 0b1011_1111,
nr41: 0b1111_1111,
nr42: 0b0000_0000,
nr43: 0b0000_0000,
nr44: 0b1011_1111,
nr50: 0b0111_0111,
nr51: 0b1111_0011,
nr52: 0b1111_0001,
wave_pattern_ram: [0u8;16],
}
}
}

View file

@ -17,7 +17,7 @@ impl Timer {
clock: TimerClock::C1024,
tima: 0,
tma: 0,
div: 0,
div: 0xAD,
div_counter: 0,
tima_counter: 0,
overflow: false,
@ -50,7 +50,7 @@ impl Timer {
}
pub fn read_tac(&self) -> u8 {
((self.enable as u8) << 2) | self.clock.tac_clock()
((self.enable as u8) << 2) | self.clock.tac_clock() | 0b1111_1000
}
pub fn write_tac(&mut self, value: u8) {

View file

@ -0,0 +1 @@
 "

View file

@ -0,0 +1 @@
 "

View file

@ -0,0 +1 @@
 "

View file

@ -0,0 +1 @@
 "

View file

@ -0,0 +1 @@
 "

View file

@ -0,0 +1 @@
 "

View file

@ -0,0 +1 @@
 "

View file

@ -0,0 +1 @@
 "

View file

@ -0,0 +1 @@
 "

View file

@ -0,0 +1 @@
 "

View file

@ -0,0 +1 @@
 "

View file

@ -0,0 +1 @@
 "

View file

@ -0,0 +1 @@
 "

View file

@ -0,0 +1 @@
 "

View file

@ -0,0 +1 @@
 "

View file

@ -0,0 +1 @@
 "

View file

@ -0,0 +1 @@
 "

View file

@ -0,0 +1 @@
 "

View file

@ -0,0 +1 @@
 "

View file

@ -0,0 +1,19 @@
Copyright (c) 2014-2022 Joonas Javanainen <joonas.javanainen@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,5 @@
# Mooneye Test Suite
These test ROMs were written by "Gekkio", and are licensed by them under the MIT license, a copy of their license is in [LICENSE](./LICENSE).
The original source code can be found at [https://github.com/Gekkio/mooneye-test-suite](https://github.com/Gekkio/mooneye-test-suite).

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.