From e4b8b67b793be4545ff96e5598c2c39b2b444b7f Mon Sep 17 00:00:00 2001 From: EliseZeroTwo Date: Thu, 4 Jan 2024 02:02:23 -0700 Subject: [PATCH] test: add much more tests, fix up a few broken things --- .forgejo/workflows/action.yml | 1 + .github/workflows/action.yml | 98 ++++++++++++++++-- .gitignore | 3 +- generate-action.sh | 55 ++++++++++ meowgb-core/src/gameboy.rs | 87 ++++------------ meowgb-core/src/gameboy/dma.rs | 61 +++++++++++ meowgb-core/src/gameboy/interrupts.rs | 8 +- meowgb-core/src/gameboy/joypad.rs | 6 +- meowgb-core/src/gameboy/memory.rs | 7 ++ meowgb-core/src/gameboy/ppu.rs | 24 +++-- meowgb-core/src/gameboy/serial.rs | 10 +- meowgb-core/src/gameboy/sound.rs | 31 +++++- meowgb-core/src/gameboy/timer.rs | 4 +- meowgb-tests/expected_output/basic.bin | 1 + meowgb-tests/expected_output/basic.gb | 1 + .../expected_output/boot_hwio-dmgABCmgb.bin | 1 + .../expected_output/boot_regs-dmgABC.bin | 1 + meowgb-tests/expected_output/daa.bin | 1 + meowgb-tests/expected_output/ei_sequence.bin | 1 + meowgb-tests/expected_output/ei_timing.bin | 1 + meowgb-tests/expected_output/halt_ime0_ei.bin | 1 + meowgb-tests/expected_output/mem_oam.bin | 1 + .../expected_output/oam_dma_restart.bin | 1 + .../expected_output/oam_dma_start.bin | 1 + .../expected_output/oam_dma_timing.bin | 1 + meowgb-tests/expected_output/rapid_di_ei.bin | 1 + meowgb-tests/expected_output/reg_f.bin | 1 + meowgb-tests/expected_output/reg_read.bin | 1 + .../expected_output/tim00_div_trigger.bin | 1 + meowgb-tests/expected_output/tim01.bin | 1 + .../expected_output/tim11_div_trigger.bin | 1 + .../expected_output/unused_hwio-GS.bin | 1 + test-roms/mooneye-test-suite/LICENSE | 19 ++++ test-roms/mooneye-test-suite/README.md | 5 + test-roms/mooneye-test-suite/roms/basic.gb | Bin 0 -> 32768 bytes .../roms/boot_hwio-dmgABCmgb.gb | Bin 0 -> 32768 bytes .../roms/boot_regs-dmgABC.gb | Bin 0 -> 32768 bytes test-roms/mooneye-test-suite/roms/daa.gb | Bin 0 -> 32768 bytes .../mooneye-test-suite/roms/ei_sequence.gb | Bin 0 -> 32768 bytes .../mooneye-test-suite/roms/ei_timing.gb | Bin 0 -> 32768 bytes .../mooneye-test-suite/roms/halt_ime0_ei.gb | Bin 0 -> 32768 bytes .../roms/intr_1_2_timing-GS.gb | Bin .../roms/intr_2_0_timing.gb | Bin test-roms/mooneye-test-suite/roms/mem_oam.gb | Bin 0 -> 32768 bytes .../roms/oam_dma_restart.gb | Bin 0 -> 32768 bytes .../mooneye-test-suite/roms/oam_dma_start.gb | Bin 0 -> 32768 bytes .../mooneye-test-suite/roms/oam_dma_timing.gb | Bin 0 -> 32768 bytes .../mooneye-test-suite/roms/rapid_di_ei.gb | Bin 0 -> 32768 bytes test-roms/mooneye-test-suite/roms/reg_f.gb | Bin 0 -> 32768 bytes test-roms/mooneye-test-suite/roms/reg_read.gb | Bin 0 -> 32768 bytes .../roms/stat_irq_blocking.gb | Bin .../roms/stat_lyc_onoff.gb | Bin .../roms/tim00_div_trigger.gb | Bin 0 -> 32768 bytes test-roms/mooneye-test-suite/roms/tim01.gb | Bin 0 -> 32768 bytes .../roms/tim11_div_trigger.gb | Bin 0 -> 32768 bytes .../mooneye-test-suite/roms/unused_hwio-GS.gb | Bin 0 -> 32768 bytes 56 files changed, 339 insertions(+), 99 deletions(-) create mode 120000 .forgejo/workflows/action.yml create mode 100755 generate-action.sh create mode 100644 meowgb-core/src/gameboy/dma.rs create mode 100644 meowgb-tests/expected_output/basic.bin create mode 100644 meowgb-tests/expected_output/basic.gb create mode 100644 meowgb-tests/expected_output/boot_hwio-dmgABCmgb.bin create mode 100644 meowgb-tests/expected_output/boot_regs-dmgABC.bin create mode 100644 meowgb-tests/expected_output/daa.bin create mode 100644 meowgb-tests/expected_output/ei_sequence.bin create mode 100644 meowgb-tests/expected_output/ei_timing.bin create mode 100644 meowgb-tests/expected_output/halt_ime0_ei.bin create mode 100644 meowgb-tests/expected_output/mem_oam.bin create mode 100644 meowgb-tests/expected_output/oam_dma_restart.bin create mode 100644 meowgb-tests/expected_output/oam_dma_start.bin create mode 100644 meowgb-tests/expected_output/oam_dma_timing.bin create mode 100644 meowgb-tests/expected_output/rapid_di_ei.bin create mode 100644 meowgb-tests/expected_output/reg_f.bin create mode 100644 meowgb-tests/expected_output/reg_read.bin create mode 100644 meowgb-tests/expected_output/tim00_div_trigger.bin create mode 100644 meowgb-tests/expected_output/tim01.bin create mode 100644 meowgb-tests/expected_output/tim11_div_trigger.bin create mode 100644 meowgb-tests/expected_output/unused_hwio-GS.bin create mode 100644 test-roms/mooneye-test-suite/LICENSE create mode 100644 test-roms/mooneye-test-suite/README.md create mode 100644 test-roms/mooneye-test-suite/roms/basic.gb create mode 100644 test-roms/mooneye-test-suite/roms/boot_hwio-dmgABCmgb.gb create mode 100644 test-roms/mooneye-test-suite/roms/boot_regs-dmgABC.gb create mode 100644 test-roms/mooneye-test-suite/roms/daa.gb create mode 100644 test-roms/mooneye-test-suite/roms/ei_sequence.gb create mode 100644 test-roms/mooneye-test-suite/roms/ei_timing.gb create mode 100644 test-roms/mooneye-test-suite/roms/halt_ime0_ei.gb rename test-roms/{mealybug-tearoom-tests => mooneye-test-suite}/roms/intr_1_2_timing-GS.gb (100%) rename test-roms/{mealybug-tearoom-tests => mooneye-test-suite}/roms/intr_2_0_timing.gb (100%) create mode 100644 test-roms/mooneye-test-suite/roms/mem_oam.gb create mode 100644 test-roms/mooneye-test-suite/roms/oam_dma_restart.gb create mode 100644 test-roms/mooneye-test-suite/roms/oam_dma_start.gb create mode 100644 test-roms/mooneye-test-suite/roms/oam_dma_timing.gb create mode 100644 test-roms/mooneye-test-suite/roms/rapid_di_ei.gb create mode 100644 test-roms/mooneye-test-suite/roms/reg_f.gb create mode 100644 test-roms/mooneye-test-suite/roms/reg_read.gb rename test-roms/{mealybug-tearoom-tests => mooneye-test-suite}/roms/stat_irq_blocking.gb (100%) rename test-roms/{mealybug-tearoom-tests => mooneye-test-suite}/roms/stat_lyc_onoff.gb (100%) create mode 100644 test-roms/mooneye-test-suite/roms/tim00_div_trigger.gb create mode 100644 test-roms/mooneye-test-suite/roms/tim01.gb create mode 100644 test-roms/mooneye-test-suite/roms/tim11_div_trigger.gb create mode 100644 test-roms/mooneye-test-suite/roms/unused_hwio-GS.gb diff --git a/.forgejo/workflows/action.yml b/.forgejo/workflows/action.yml new file mode 120000 index 0000000..f8bb030 --- /dev/null +++ b/.forgejo/workflows/action.yml @@ -0,0 +1 @@ +./.github/workflows/action.yml \ No newline at end of file diff --git a/.github/workflows/action.yml b/.github/workflows/action.yml index c164e33..191224b 100644 --- a/.github/workflows/action.yml +++ b/.github/workflows/action.yml @@ -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 diff --git a/.gitignore b/.gitignore index 98d60c8..53bf464 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ /bmp/ config.toml /.vscode/ -out \ No newline at end of file +out +generate-output.sh \ No newline at end of file diff --git a/generate-action.sh b/generate-action.sh new file mode 100755 index 0000000..7afd84f --- /dev/null +++ b/generate-action.sh @@ -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 diff --git a/meowgb-core/src/gameboy.rs b/meowgb-core/src/gameboy.rs index 21341fa..4177cbe 100644 --- a/meowgb-core/src/gameboy.rs +++ b/meowgb-core/src/gameboy.rs @@ -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 { buffer: [T; SIZE], size: usize, @@ -155,7 +140,7 @@ impl Gameboy { 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 Gameboy { 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 Gameboy { } } - 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 Gameboy { 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 Gameboy { 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 Gameboy { 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 Gameboy { 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 Gameboy { 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 Gameboy { 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 Gameboy { } } 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 Gameboy { 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 Gameboy { 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), } } } diff --git a/meowgb-core/src/gameboy/dma.rs b/meowgb-core/src/gameboy/dma.rs new file mode 100644 index 0000000..c419e98 --- /dev/null +++ b/meowgb-core/src/gameboy/dma.rs @@ -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; + } + + } + +} \ No newline at end of file diff --git a/meowgb-core/src/gameboy/interrupts.rs b/meowgb-core/src/gameboy/interrupts.rs index 7e934c0..6d61bbe 100644 --- a/meowgb-core/src/gameboy/interrupts.rs +++ b/meowgb-core/src/gameboy/interrupts.rs @@ -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; + } } diff --git a/meowgb-core/src/gameboy/joypad.rs b/meowgb-core/src/gameboy/joypad.rs index bf0a8e5..4b5e613 100644 --- a/meowgb-core/src/gameboy/joypad.rs +++ b/meowgb-core/src/gameboy/joypad.rs @@ -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, } } diff --git a/meowgb-core/src/gameboy/memory.rs b/meowgb-core/src/gameboy/memory.rs index b0901ee..c830095 100644 --- a/meowgb-core/src/gameboy/memory.rs +++ b/meowgb-core/src/gameboy/memory.rs @@ -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, + } + } } diff --git a/meowgb-core/src/gameboy/ppu.rs b/meowgb-core/src/gameboy/ppu.rs index e6533d3..4ad8dc0 100644 --- a/meowgb-core/src/gameboy/ppu.rs +++ b/meowgb-core/src/gameboy/ppu.rs @@ -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, } ); diff --git a/meowgb-core/src/gameboy/serial.rs b/meowgb-core/src/gameboy/serial.rs index a1acf03..a4eca9e 100644 --- a/meowgb-core/src/gameboy/serial.rs +++ b/meowgb-core/src/gameboy/serial.rs @@ -15,7 +15,7 @@ impl SerialWriter for T { pub struct Serial { pub sb: u8, - pub sc: u8, + sc: u8, internal_tick: u16, writer: S, @@ -39,6 +39,14 @@ impl Serial { 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; diff --git a/meowgb-core/src/gameboy/sound.rs b/meowgb-core/src/gameboy/sound.rs index 74d40f2..191b71d 100644 --- a/meowgb-core/src/gameboy/sound.rs +++ b/meowgb-core/src/gameboy/sound.rs @@ -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], + } + } +} diff --git a/meowgb-core/src/gameboy/timer.rs b/meowgb-core/src/gameboy/timer.rs index 99c39b6..00d19bf 100644 --- a/meowgb-core/src/gameboy/timer.rs +++ b/meowgb-core/src/gameboy/timer.rs @@ -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) { diff --git a/meowgb-tests/expected_output/basic.bin b/meowgb-tests/expected_output/basic.bin new file mode 100644 index 0000000..2a02163 --- /dev/null +++ b/meowgb-tests/expected_output/basic.bin @@ -0,0 +1 @@ + " \ No newline at end of file diff --git a/meowgb-tests/expected_output/basic.gb b/meowgb-tests/expected_output/basic.gb new file mode 100644 index 0000000..2a02163 --- /dev/null +++ b/meowgb-tests/expected_output/basic.gb @@ -0,0 +1 @@ + " \ No newline at end of file diff --git a/meowgb-tests/expected_output/boot_hwio-dmgABCmgb.bin b/meowgb-tests/expected_output/boot_hwio-dmgABCmgb.bin new file mode 100644 index 0000000..2a02163 --- /dev/null +++ b/meowgb-tests/expected_output/boot_hwio-dmgABCmgb.bin @@ -0,0 +1 @@ + " \ No newline at end of file diff --git a/meowgb-tests/expected_output/boot_regs-dmgABC.bin b/meowgb-tests/expected_output/boot_regs-dmgABC.bin new file mode 100644 index 0000000..2a02163 --- /dev/null +++ b/meowgb-tests/expected_output/boot_regs-dmgABC.bin @@ -0,0 +1 @@ + " \ No newline at end of file diff --git a/meowgb-tests/expected_output/daa.bin b/meowgb-tests/expected_output/daa.bin new file mode 100644 index 0000000..2a02163 --- /dev/null +++ b/meowgb-tests/expected_output/daa.bin @@ -0,0 +1 @@ + " \ No newline at end of file diff --git a/meowgb-tests/expected_output/ei_sequence.bin b/meowgb-tests/expected_output/ei_sequence.bin new file mode 100644 index 0000000..2a02163 --- /dev/null +++ b/meowgb-tests/expected_output/ei_sequence.bin @@ -0,0 +1 @@ + " \ No newline at end of file diff --git a/meowgb-tests/expected_output/ei_timing.bin b/meowgb-tests/expected_output/ei_timing.bin new file mode 100644 index 0000000..2a02163 --- /dev/null +++ b/meowgb-tests/expected_output/ei_timing.bin @@ -0,0 +1 @@ + " \ No newline at end of file diff --git a/meowgb-tests/expected_output/halt_ime0_ei.bin b/meowgb-tests/expected_output/halt_ime0_ei.bin new file mode 100644 index 0000000..2a02163 --- /dev/null +++ b/meowgb-tests/expected_output/halt_ime0_ei.bin @@ -0,0 +1 @@ + " \ No newline at end of file diff --git a/meowgb-tests/expected_output/mem_oam.bin b/meowgb-tests/expected_output/mem_oam.bin new file mode 100644 index 0000000..2a02163 --- /dev/null +++ b/meowgb-tests/expected_output/mem_oam.bin @@ -0,0 +1 @@ + " \ No newline at end of file diff --git a/meowgb-tests/expected_output/oam_dma_restart.bin b/meowgb-tests/expected_output/oam_dma_restart.bin new file mode 100644 index 0000000..2a02163 --- /dev/null +++ b/meowgb-tests/expected_output/oam_dma_restart.bin @@ -0,0 +1 @@ + " \ No newline at end of file diff --git a/meowgb-tests/expected_output/oam_dma_start.bin b/meowgb-tests/expected_output/oam_dma_start.bin new file mode 100644 index 0000000..2a02163 --- /dev/null +++ b/meowgb-tests/expected_output/oam_dma_start.bin @@ -0,0 +1 @@ + " \ No newline at end of file diff --git a/meowgb-tests/expected_output/oam_dma_timing.bin b/meowgb-tests/expected_output/oam_dma_timing.bin new file mode 100644 index 0000000..2a02163 --- /dev/null +++ b/meowgb-tests/expected_output/oam_dma_timing.bin @@ -0,0 +1 @@ + " \ No newline at end of file diff --git a/meowgb-tests/expected_output/rapid_di_ei.bin b/meowgb-tests/expected_output/rapid_di_ei.bin new file mode 100644 index 0000000..2a02163 --- /dev/null +++ b/meowgb-tests/expected_output/rapid_di_ei.bin @@ -0,0 +1 @@ + " \ No newline at end of file diff --git a/meowgb-tests/expected_output/reg_f.bin b/meowgb-tests/expected_output/reg_f.bin new file mode 100644 index 0000000..2a02163 --- /dev/null +++ b/meowgb-tests/expected_output/reg_f.bin @@ -0,0 +1 @@ + " \ No newline at end of file diff --git a/meowgb-tests/expected_output/reg_read.bin b/meowgb-tests/expected_output/reg_read.bin new file mode 100644 index 0000000..2a02163 --- /dev/null +++ b/meowgb-tests/expected_output/reg_read.bin @@ -0,0 +1 @@ + " \ No newline at end of file diff --git a/meowgb-tests/expected_output/tim00_div_trigger.bin b/meowgb-tests/expected_output/tim00_div_trigger.bin new file mode 100644 index 0000000..2a02163 --- /dev/null +++ b/meowgb-tests/expected_output/tim00_div_trigger.bin @@ -0,0 +1 @@ + " \ No newline at end of file diff --git a/meowgb-tests/expected_output/tim01.bin b/meowgb-tests/expected_output/tim01.bin new file mode 100644 index 0000000..2a02163 --- /dev/null +++ b/meowgb-tests/expected_output/tim01.bin @@ -0,0 +1 @@ + " \ No newline at end of file diff --git a/meowgb-tests/expected_output/tim11_div_trigger.bin b/meowgb-tests/expected_output/tim11_div_trigger.bin new file mode 100644 index 0000000..2a02163 --- /dev/null +++ b/meowgb-tests/expected_output/tim11_div_trigger.bin @@ -0,0 +1 @@ + " \ No newline at end of file diff --git a/meowgb-tests/expected_output/unused_hwio-GS.bin b/meowgb-tests/expected_output/unused_hwio-GS.bin new file mode 100644 index 0000000..2a02163 --- /dev/null +++ b/meowgb-tests/expected_output/unused_hwio-GS.bin @@ -0,0 +1 @@ + " \ No newline at end of file diff --git a/test-roms/mooneye-test-suite/LICENSE b/test-roms/mooneye-test-suite/LICENSE new file mode 100644 index 0000000..87f7a8e --- /dev/null +++ b/test-roms/mooneye-test-suite/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2014-2022 Joonas Javanainen + +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. diff --git a/test-roms/mooneye-test-suite/README.md b/test-roms/mooneye-test-suite/README.md new file mode 100644 index 0000000..21a9de6 --- /dev/null +++ b/test-roms/mooneye-test-suite/README.md @@ -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). diff --git a/test-roms/mooneye-test-suite/roms/basic.gb b/test-roms/mooneye-test-suite/roms/basic.gb new file mode 100644 index 0000000000000000000000000000000000000000..c6d08bb54fd51d09bf592f34bc722629273a64cd GIT binary patch literal 32768 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 S0T2KI5C8!X0D=EFfxiL2d7O6u literal 0 HcmV?d00001 diff --git a/test-roms/mooneye-test-suite/roms/boot_regs-dmgABC.gb b/test-roms/mooneye-test-suite/roms/boot_regs-dmgABC.gb new file mode 100644 index 0000000000000000000000000000000000000000..8ea19f0decc9cf64eb8c441847639b42bf280a10 GIT binary patch literal 32768 zcmeI4UrZE77{K?IE3SZa5hV-V%HHKdPKpMR#0$M{mu10&r9GmhCX_@91vG7e2u%== z6KZY2e_(@2O-SmSNndD_rpB0o`$gvB=3&ENa_Zfp?pbB2XuLV>VBkc!HuriH>gHwKpP-u?Of zl`H){1BJicxO?aPmsc+D)IS^?9OymVyRE-l8|fV$5jr{qDz2TvHoaUro7#~~tvouL zN+z|B9(|rlrnG?v4|hzZ?)`XeWrsi($P_t2rpYOClAIx@$t;=CUF3vkDiy!3e@&*L zb5j?{Dd^nRi^)mo{7Og8KxbM1iJXSceHt|joj>$9$P9Fn4?WKA#aCJ$dVX=ySK^$V zxNSGT`F4G4v!(5A(`cu?Q7AEE&-aPr?vVfzKmter2_OL^fCP{L5NrG`dmDP3_iA2}~ zx-@roy5Hp|-ZQ)v{`9-EOv?=JyMXO;YLT=*UT6WOa6^4_AUC=8?Eo%gCF$1C&U)^IaB*-2;~)T z@Nb1+fi`uT;7o>{6PNu3iErUcG#*XZq->_0Ft{rDv2yr_d*Tmx{!p?Lyacnh^ zU~f8s$rBt4JEyWq5Pv5f*TCaG4m&5aiOWpflTKjq1job9nQRio-%rOi^0-gJ&gpF8 zG7}G{6NGqz&%(}ZHVNWK(s8Xk?$fX{lTF;>Ih%gG$ko_#?Ox)R9ax{(Zzo>06VtXw z_#y@)FMAC72_nZz&S;NlJDYBw^v5o0g}FI}FO*1IHdJih?o}k++#TMxzkkq3d}Rm9 zMiT?}Vfu{G=Lmfw^ckm*vT>BS4incHaUCJ92yu-Qm!Tw!)5TLyYpjeG*Gp-w>9JN^ zOd&A`bB#m8(+<`ehsLKJLTemaS3ATOh)EiVOo3H%kShp{{ z9{WBKwy)uLo}SG=xo}lT00|%gB!C2v01`j~NB{{S0VIF~kN^@u0!RP}AOR$R1dsp{ yKmter2_OL^fCP{L5!Q_y6phS~yrg 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 literal 0 HcmV?d00001 diff --git a/test-roms/mooneye-test-suite/roms/reg_f.gb b/test-roms/mooneye-test-suite/roms/reg_f.gb new file mode 100644 index 0000000000000000000000000000000000000000..21b9b7cfd6b573a1cdfe58be45f1074fbc381fbe GIT binary patch literal 32768 zcmeI4Uq~EB7{KS&tJ$bY*O-LWZq0feae+Q;0|<%iD~OBwHe zx$|P*NkVA7hv%0MVWVK?wzKM zeJ6B!B0vO)01+SpM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CY zfCvx)B0vO)01+SpM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>@uMkJ6} zCGc15tJDPPuOAP%)72uc2xGDg^C2#)?JyIMV}p5FE-ej(G%YVL5`l=0j_K)R$9C@A zy*oD-?3$)?DK0KAFD^!Z%nM@>SymMAP!ybpPd^u!2YW?@rWuB&RaAfm0vj|8=usEF zhyXnj5wqD(^p_;et?Q-Js)8=dstUPfS<^s|L@dkiS5;k4Wa?k&mW6A8 ze<&1<#^abjkuc48T#|%65&<1nK>tKy?fQ@pny};8FeE8^2F#p2uh5ZDZmz0!bf_xw zhCRbhakrqM4SYZghix0q!x%=x32l33W_r54UDq{D|ho4c-%BcMocd8IM}l~@`m-t$7g0lJe)j{fZnpeA8!`;8wTi_2G!vA3xC^=Mq642 z2cuEj20N^Tf+w!4>*{K4ZEURL0(Q&l>^yw9si~m>^J`jQMeu&{e3$|JSKB2?oWG?- ztOs^QDJTd8F#gmj*eeRIhi4J@IWYlxkPFrq?5nY{wY95D><=thg%Dp?7YJZDa(U{aPnX<6soGKtOS3^i-LS%uBWH14XDEyWbfYUYPfXNaEIc4V6MHr zv(vJmQcV-|+FGayFW@4}Vt)`-UESOapK$A0 z0ljd1Ieo=RKXMLt_x249cOM^Op!1&}n|SX{-U#jC*1Dmg?&HIK1N|?}R&?}6XdA|U z$p7n&-t%$aXWgH$Zy}>35yHqNla;ASd9=)z_&CS{R z#!k6(OZkqy0aZ4vL$M=Adk4()cTTuuB;D_v;BAz*lf1=w8{chdF6 zUEi4NGu5S{O!3t58Y|(&^;Sk}Ska1#I3#qi);QF^>R_*NIQXhVbd5vvYKP>kYq|BV z<2D(Eu4(-19-6!6o3)KTCiFxFax}9`=#)K=)z6UQ+|2w(x=2Bi* zy0__GRUlcWj2AM~=WUw1?Tjt#dbTTaX5c|ES;oeFOrM?m$(eN}Pg>Y5g-CYfCvx)B0vO)01+SpM1Tko0U|&IhyW2F0z`la5CI}U1c(3; VAOb{y2oM1xKm>>Y5qO;l{0B!_a!>#O literal 0 HcmV?d00001 diff --git a/test-roms/mooneye-test-suite/roms/reg_read.gb b/test-roms/mooneye-test-suite/roms/reg_read.gb new file mode 100644 index 0000000000000000000000000000000000000000..fc756e9595afe7beb2497ea3b023c6e0e70859cf GIT binary patch literal 32768 zcmeI4-%A`<6vyw38#_^B$2OHwrpfHG$VQAL8{00jnT*q6GbTbLtppaKb|soZ8l}m@ z#%wk#rO-Yl4^kQs>|5R{eJr7cDuPS0r4J=gh-F?H^3WgKhW-kz_MSbCYwJHyn(u*` zz2|<NVYG!?5>7HV{+;*3KR4C?>sx)oI$OuiXMXb9^QI+(fsx;U18$9m% zQom|D+&;GSiux$JqAXXBSIT}x48AIJu}+;7?V|iBx>oPcy#B`de(SBnqTQ9kuRDY! z3s0+CGi{DI!a`z)(8t2S4&enBvO9zqNeD8HiCxxT^0T_tIvRF9*~bvog8&GC00@8p z2!H?xfB*=900@8p2!H?xfB*=900@8p2!H?xfB*=900@8p2!H?xfB*=900@8p2!H?x zfB*=900@8p2!H?xfB*=900@8p2!H?xfB*=9z(#SK(SNaTbBpl*e>`YUx0|+ULTDQG zC!}rHsi#ojhx#>b-@Zh`G@F{zX&Ny$HaBD}F?Y1^jR-Ax`DC1~69W(nqkD_ zuC#dEFv!<5!=Sk}%{0kRr(HJ^F$~Kp*3N(EyDqOm@ri`*7YaOovFJF3f~tmkI!!*U z!12Z6Ki8-E=m~Xh+qSCKYv7sd^@ctZYHT!&u`$D7-jp+C%Gr{~8pV*8N_igDBLt78 z3O#Rrer|4b)Ur&|kQR?~78IY)dmcUX4#$_Id0r|N>ZFExq2M_Ayd$kpAieH0Z(6@p znx7BHQ{}}Xy)264X@_0OvICQ9| zhvI2oHs(ux6BF4iQKvRpZ*MY5o6a6*814`CjgIDWu1hD?amerQr_(}rP^~fT=}9JO zUDCLE!=T*R*Y$LoGN`XlYjt&XcCt=qu>So*eY4WC*@=m|PG?}d&u2i_`OeZeE3HED zrm5?Pr0F{I4_SpLhW5Wjnx=*M(Wqo{Xox;(*Xu^U{Cygw$zS=l^4L%9mcLX}x#Cwo z^`qj0GW9$kbvEv-SH1P?)?@j;QG0K-XKq=ojSa24+O>Uqx}NKe8Jg`LKXvA{$tkDu zji2hwS3dGD%V$PDSL9QW&sF&t&*TH;a-hrv%9TJV1j^Mwag6oFzztpwP6j9Jw!pFf z42~~<tQ;uzY@jY4rAn+n%2B=4CLE>u)bd0B z>Vy41>`%Wl^<}&q6(vPji_1Uxi-B5IAIz@4RL+0A+8KMc+4${@Y|X@)jo+)@y$_F- zKd)T(SIYQ95ClK~1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`; sKmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;{#yk82F6;SbN~PV literal 0 HcmV?d00001 diff --git a/test-roms/mealybug-tearoom-tests/roms/stat_irq_blocking.gb b/test-roms/mooneye-test-suite/roms/stat_irq_blocking.gb similarity index 100% rename from test-roms/mealybug-tearoom-tests/roms/stat_irq_blocking.gb rename to test-roms/mooneye-test-suite/roms/stat_irq_blocking.gb diff --git a/test-roms/mealybug-tearoom-tests/roms/stat_lyc_onoff.gb b/test-roms/mooneye-test-suite/roms/stat_lyc_onoff.gb similarity index 100% rename from test-roms/mealybug-tearoom-tests/roms/stat_lyc_onoff.gb rename to test-roms/mooneye-test-suite/roms/stat_lyc_onoff.gb diff --git a/test-roms/mooneye-test-suite/roms/tim00_div_trigger.gb b/test-roms/mooneye-test-suite/roms/tim00_div_trigger.gb new file mode 100644 index 0000000000000000000000000000000000000000..697ba03a0e07d8859f2f5b6f12fbe17d9864e7c3 GIT binary patch literal 32768 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 literal 0 HcmV?d00001