From 8ae96ec8807f5c5c485fdc4015ebb436a8459bb2 Mon Sep 17 00:00:00 2001 From: EliseZeroTwo Date: Thu, 4 Jan 2024 23:23:58 -0700 Subject: [PATCH] feat: timer works much better --- .forgejo/workflows/action.yml | 97 ++-- .github/workflows/action.yml | 97 ++-- generate-action-and-tests.sh | 122 +++++ generate-action.sh | 57 --- meowgb-core/src/gameboy.rs | 417 +++--------------- meowgb-core/src/gameboy/cpu.rs | 21 +- meowgb-core/src/gameboy/cpu/misc.rs | 4 +- meowgb-core/src/gameboy/dma.rs | 39 +- meowgb-core/src/gameboy/joypad.rs | 32 +- meowgb-core/src/gameboy/mapper.rs | 2 + meowgb-core/src/gameboy/mapper/mbc1.rs | 19 +- meowgb-core/src/gameboy/serial.rs | 7 +- meowgb-core/src/gameboy/sound.rs | 2 +- meowgb-core/src/gameboy/timer.rs | 146 ++++-- meowgb-core/src/lib.rs | 4 + meowgb-core/src/ringbuffer.rs | 70 +++ meowgb-opcode/src/lib.rs | 68 +-- meowgb-tests/expected_output/div_timing.bin | 1 + meowgb-tests/expected_output/div_write.bin | 1 + meowgb-tests/expected_output/rapid_toggle.bin | 1 + meowgb-tests/expected_output/tim00.bin | 1 + .../expected_output/tim01_div_trigger.bin | 1 + meowgb-tests/expected_output/tim10.bin | 1 + .../expected_output/tim10_div_trigger.bin | 1 + meowgb-tests/expected_output/tim11.bin | 1 + meowgb-tests/expected_output/tima_reload.bin | 1 + .../expected_output/tima_write_reloading.bin | 1 + .../expected_output/tma_write_reloading.bin | 1 + meowgb/src/main.rs | 16 +- run-test-roms.sh | 370 ++++++++++++++++ .../mooneye-test-suite/roms/div_timing.gb | Bin 0 -> 32768 bytes .../mooneye-test-suite/roms/div_write.gb | Bin 0 -> 32768 bytes .../mooneye-test-suite/roms/rapid_toggle.gb | Bin 0 -> 32768 bytes test-roms/mooneye-test-suite/roms/tim00.gb | Bin 0 -> 32768 bytes .../roms/tim01_div_trigger.gb | Bin 0 -> 32768 bytes test-roms/mooneye-test-suite/roms/tim10.gb | Bin 0 -> 32768 bytes .../roms/tim10_div_trigger.gb | Bin 0 -> 32768 bytes test-roms/mooneye-test-suite/roms/tim11.gb | Bin 0 -> 32768 bytes .../mooneye-test-suite/roms/tima_reload.gb | Bin 0 -> 32768 bytes .../roms/tima_write_reloading.gb | Bin 0 -> 32768 bytes .../roms/tma_write_reloading.gb | Bin 0 -> 32768 bytes tests.md | 48 +- 42 files changed, 1032 insertions(+), 617 deletions(-) create mode 100755 generate-action-and-tests.sh delete mode 100755 generate-action.sh create mode 100644 meowgb-core/src/ringbuffer.rs create mode 100644 meowgb-tests/expected_output/div_timing.bin create mode 100644 meowgb-tests/expected_output/div_write.bin create mode 100644 meowgb-tests/expected_output/rapid_toggle.bin create mode 100644 meowgb-tests/expected_output/tim00.bin create mode 100644 meowgb-tests/expected_output/tim01_div_trigger.bin create mode 100644 meowgb-tests/expected_output/tim10.bin create mode 100644 meowgb-tests/expected_output/tim10_div_trigger.bin create mode 100644 meowgb-tests/expected_output/tim11.bin create mode 100644 meowgb-tests/expected_output/tima_reload.bin create mode 100644 meowgb-tests/expected_output/tima_write_reloading.bin create mode 100644 meowgb-tests/expected_output/tma_write_reloading.bin create mode 100755 run-test-roms.sh create mode 100644 test-roms/mooneye-test-suite/roms/div_timing.gb create mode 100644 test-roms/mooneye-test-suite/roms/div_write.gb create mode 100644 test-roms/mooneye-test-suite/roms/rapid_toggle.gb create mode 100644 test-roms/mooneye-test-suite/roms/tim00.gb create mode 100644 test-roms/mooneye-test-suite/roms/tim01_div_trigger.gb create mode 100644 test-roms/mooneye-test-suite/roms/tim10.gb create mode 100644 test-roms/mooneye-test-suite/roms/tim10_div_trigger.gb create mode 100644 test-roms/mooneye-test-suite/roms/tim11.gb create mode 100644 test-roms/mooneye-test-suite/roms/tima_reload.gb create mode 100644 test-roms/mooneye-test-suite/roms/tima_write_reloading.gb create mode 100644 test-roms/mooneye-test-suite/roms/tma_write_reloading.gb diff --git a/.forgejo/workflows/action.yml b/.forgejo/workflows/action.yml index 191224b..911fbec 100644 --- a/.forgejo/workflows/action.yml +++ b/.forgejo/workflows/action.yml @@ -14,103 +14,150 @@ jobs: - name: Run cargo tests (meowgb-core) run: cargo test -p meowgb-core + + - name: Build release (meowgb-tests) + run: cargo build -p meowgb-tests --release - 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 + run: ./target/release/meowgb-tests 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 + run: ./target/release/meowgb-tests 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 + run: ./target/release/meowgb-tests test-roms/blargg/roms/mem_timing.gb test -m 100000000 -s meowgb-tests/expected_output/mem_timing.bin - name: Run test ROM (mooneye-test-suite basic) if: always() - 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 + run: ./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/basic.gb test -m 100000000 -s meowgb-tests/expected_output/basic.bin - name: Run test ROM (mooneye-test-suite boot_hwio-dmgABCmgb) if: always() - 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 + run: ./target/release/meowgb-tests 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 (mooneye-test-suite boot_regs-dmgABC) if: always() - 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 + run: ./target/release/meowgb-tests 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/mooneye-test-suite/roms/daa.gb test -m 100000000 -s meowgb-tests/expected_output/daa.bin + run: ./target/release/meowgb-tests 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 div_timing) + if: always() + run: ./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/div_timing.gb test -m 100000000 -s meowgb-tests/expected_output/div_timing.bin + + - name: Run test ROM (mooneye-test-suite div_write) + if: always() + run: ./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/div_write.gb test -m 100000000 -s meowgb-tests/expected_output/div_write.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 + run: ./target/release/meowgb-tests 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 + run: ./target/release/meowgb-tests 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 + run: ./target/release/meowgb-tests 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 + run: ./target/release/meowgb-tests 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 + run: ./target/release/meowgb-tests 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 + run: ./target/release/meowgb-tests 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 + run: ./target/release/meowgb-tests 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 + run: ./target/release/meowgb-tests 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 + run: ./target/release/meowgb-tests 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 + run: ./target/release/meowgb-tests 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 rapid_toggle) + if: always() + run: ./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/rapid_toggle.gb test -m 100000000 -s meowgb-tests/expected_output/rapid_toggle.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 + run: ./target/release/meowgb-tests 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 + run: ./target/release/meowgb-tests 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 + run: ./target/release/meowgb-tests 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 + run: ./target/release/meowgb-tests 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) + if: always() + run: ./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/tim00.gb test -m 100000000 -s meowgb-tests/expected_output/tim00.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 + run: ./target/release/meowgb-tests 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 + run: ./target/release/meowgb-tests 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 tim01_div_trigger) + if: always() + run: ./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/tim01_div_trigger.gb test -m 100000000 -s meowgb-tests/expected_output/tim01_div_trigger.bin + + - name: Run test ROM (mooneye-test-suite tim10) + if: always() + run: ./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/tim10.gb test -m 100000000 -s meowgb-tests/expected_output/tim10.bin + + - name: Run test ROM (mooneye-test-suite tim10_div_trigger) + if: always() + run: ./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/tim10_div_trigger.gb test -m 100000000 -s meowgb-tests/expected_output/tim10_div_trigger.bin + + - name: Run test ROM (mooneye-test-suite tim11) + if: always() + run: ./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/tim11.gb test -m 100000000 -s meowgb-tests/expected_output/tim11.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 + run: ./target/release/meowgb-tests 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 tima_reload) + if: always() + run: ./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/tima_reload.gb test -m 100000000 -s meowgb-tests/expected_output/tima_reload.bin + + - name: Run test ROM (mooneye-test-suite tima_write_reloading) + if: always() + run: ./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/tima_write_reloading.gb test -m 100000000 -s meowgb-tests/expected_output/tima_write_reloading.bin + + - name: Run test ROM (mooneye-test-suite tma_write_reloading) + if: always() + run: ./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/tma_write_reloading.gb test -m 100000000 -s meowgb-tests/expected_output/tma_write_reloading.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 + run: ./target/release/meowgb-tests 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/.github/workflows/action.yml b/.github/workflows/action.yml index 191224b..911fbec 100644 --- a/.github/workflows/action.yml +++ b/.github/workflows/action.yml @@ -14,103 +14,150 @@ jobs: - name: Run cargo tests (meowgb-core) run: cargo test -p meowgb-core + + - name: Build release (meowgb-tests) + run: cargo build -p meowgb-tests --release - 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 + run: ./target/release/meowgb-tests 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 + run: ./target/release/meowgb-tests 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 + run: ./target/release/meowgb-tests test-roms/blargg/roms/mem_timing.gb test -m 100000000 -s meowgb-tests/expected_output/mem_timing.bin - name: Run test ROM (mooneye-test-suite basic) if: always() - 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 + run: ./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/basic.gb test -m 100000000 -s meowgb-tests/expected_output/basic.bin - name: Run test ROM (mooneye-test-suite boot_hwio-dmgABCmgb) if: always() - 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 + run: ./target/release/meowgb-tests 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 (mooneye-test-suite boot_regs-dmgABC) if: always() - 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 + run: ./target/release/meowgb-tests 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/mooneye-test-suite/roms/daa.gb test -m 100000000 -s meowgb-tests/expected_output/daa.bin + run: ./target/release/meowgb-tests 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 div_timing) + if: always() + run: ./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/div_timing.gb test -m 100000000 -s meowgb-tests/expected_output/div_timing.bin + + - name: Run test ROM (mooneye-test-suite div_write) + if: always() + run: ./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/div_write.gb test -m 100000000 -s meowgb-tests/expected_output/div_write.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 + run: ./target/release/meowgb-tests 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 + run: ./target/release/meowgb-tests 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 + run: ./target/release/meowgb-tests 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 + run: ./target/release/meowgb-tests 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 + run: ./target/release/meowgb-tests 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 + run: ./target/release/meowgb-tests 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 + run: ./target/release/meowgb-tests 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 + run: ./target/release/meowgb-tests 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 + run: ./target/release/meowgb-tests 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 + run: ./target/release/meowgb-tests 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 rapid_toggle) + if: always() + run: ./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/rapid_toggle.gb test -m 100000000 -s meowgb-tests/expected_output/rapid_toggle.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 + run: ./target/release/meowgb-tests 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 + run: ./target/release/meowgb-tests 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 + run: ./target/release/meowgb-tests 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 + run: ./target/release/meowgb-tests 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) + if: always() + run: ./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/tim00.gb test -m 100000000 -s meowgb-tests/expected_output/tim00.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 + run: ./target/release/meowgb-tests 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 + run: ./target/release/meowgb-tests 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 tim01_div_trigger) + if: always() + run: ./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/tim01_div_trigger.gb test -m 100000000 -s meowgb-tests/expected_output/tim01_div_trigger.bin + + - name: Run test ROM (mooneye-test-suite tim10) + if: always() + run: ./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/tim10.gb test -m 100000000 -s meowgb-tests/expected_output/tim10.bin + + - name: Run test ROM (mooneye-test-suite tim10_div_trigger) + if: always() + run: ./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/tim10_div_trigger.gb test -m 100000000 -s meowgb-tests/expected_output/tim10_div_trigger.bin + + - name: Run test ROM (mooneye-test-suite tim11) + if: always() + run: ./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/tim11.gb test -m 100000000 -s meowgb-tests/expected_output/tim11.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 + run: ./target/release/meowgb-tests 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 tima_reload) + if: always() + run: ./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/tima_reload.gb test -m 100000000 -s meowgb-tests/expected_output/tima_reload.bin + + - name: Run test ROM (mooneye-test-suite tima_write_reloading) + if: always() + run: ./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/tima_write_reloading.gb test -m 100000000 -s meowgb-tests/expected_output/tima_write_reloading.bin + + - name: Run test ROM (mooneye-test-suite tma_write_reloading) + if: always() + run: ./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/tma_write_reloading.gb test -m 100000000 -s meowgb-tests/expected_output/tma_write_reloading.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 + run: ./target/release/meowgb-tests 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/generate-action-and-tests.sh b/generate-action-and-tests.sh new file mode 100755 index 0000000..c2ce06b --- /dev/null +++ b/generate-action-and-tests.sh @@ -0,0 +1,122 @@ +#!/bin/bash +GH_ACTION_OUTPUT_FILE=./.github/workflows/action.yml +FJ_ACTION_OUTPUT_FILE=./.forgejo/workflows/action.yml +TEST_SCRIPT_OUTPUT_FILE=./run-test-roms.sh +TEST_MD_FILE=./tests.md + +cat >$TEST_MD_FILE << EOF +# Passing Tests + +EOF + +cat >$TEST_SCRIPT_OUTPUT_FILE << EOF +echo "Running Test Roms..." + +if ! cargo build -p meowgb-tests --release ; then + exit +fi + +TEST_TOTAL=0 +TEST_SUCCESS=0 +EOF + +chmod +x $TEST_SCRIPT_OUTPUT_FILE + + +tee $GH_ACTION_OUTPUT_FILE $FJ_ACTION_OUTPUT_FILE >/dev/null << 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 + + - name: Build release (meowgb-tests) + run: cargo build -p meowgb-tests --release +EOF + +cat >>$TEST_MD_FILE << EOF +## Blargg's Test ROMs + +EOF + +for full_f in ./test-roms/blargg/roms/* +do + f="${full_f##*/}"; f="${f%.*}"; + TEST_CMD="./target/release/meowgb-tests test-roms/blargg/roms/$f.gb test -m 100000000 -s meowgb-tests/expected_output/$f.bin" + + cat >>$TEST_SCRIPT_OUTPUT_FILE << EOF + +echo "Running test ROM $full_f" + +TEST_TOTAL=\$((TEST_TOTAL + 1)) + +if res=\$($TEST_CMD 2>&1 > /dev/null) ; then + TEST_SUCCESS=\$((TEST_SUCCESS + 1)) +else + echo "Failed: \$res" +fi +EOF + + cat >>$TEST_MD_FILE << EOF +* $f.gb - [ROM]($full_f) - [Expected Serial Output](./meowgb-tests/expected_output/$f.bin) +EOF + + tee -a $GH_ACTION_OUTPUT_FILE $FJ_ACTION_OUTPUT_FILE >/dev/null << EOF + + - name: Run test ROM (blargg $f) + if: always() + run: $TEST_CMD +EOF +done + +cat >>$TEST_MD_FILE << EOF + +## Mooneye Test Suite + +EOF + +for full_f in ./test-roms/mooneye-test-suite/roms/* +do + f="${full_f##*/}"; f="${f%.*}"; + TEST_CMD="./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/$f.gb test -m 100000000 -s meowgb-tests/expected_output/$f.bin" + + cat >>$TEST_SCRIPT_OUTPUT_FILE << EOF + +echo "Running test ROM $full_f" + +TEST_TOTAL=\$((TEST_TOTAL + 1)) + +if res=\$($TEST_CMD 2>&1 > /dev/null) ; then + TEST_SUCCESS=\$((TEST_SUCCESS + 1)) +else + echo "Failed: \$res" +fi +EOF + + cat >>$TEST_MD_FILE << EOF +* $f.gb - [ROM]($full_f) - [Expected Serial Output](./meowgb-tests/expected_output/$f.bin) +EOF + + tee -a $GH_ACTION_OUTPUT_FILE $FJ_ACTION_OUTPUT_FILE >/dev/null << EOF + + - name: Run test ROM (mooneye-test-suite $f) + if: always() + run: $TEST_CMD +EOF +done + +cat >>$TEST_SCRIPT_OUTPUT_FILE << EOF + +echo "Succeeded in running \$TEST_SUCCESS/\$TEST_TOTAL" +EOF diff --git a/generate-action.sh b/generate-action.sh deleted file mode 100755 index d8dfbba..0000000 --- a/generate-action.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/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 - -cp .github/workflows/action.yml .forgejo/workflows/action.yml diff --git a/meowgb-core/src/gameboy.rs b/meowgb-core/src/gameboy.rs index 4177cbe..5fb54a4 100644 --- a/meowgb-core/src/gameboy.rs +++ b/meowgb-core/src/gameboy.rs @@ -10,8 +10,6 @@ pub mod serial; pub mod sound; pub mod timer; -use std::time::{Duration, Instant}; - use interrupts::Interrupts; use joypad::Joypad; use mapper::Mapper; @@ -21,82 +19,12 @@ use timer::Timer; use self::{ cpu::Registers, + dma::DmaState, mapper::{mbc1::MBC1, NoMBC}, serial::{Serial, SerialWriter}, - sound::Sound, dma::DmaState, + sound::Sound, }; -pub struct RingBuffer { - buffer: [T; SIZE], - size: usize, - write_ptr: usize, - read_ptr: usize, -} - -impl RingBuffer { - pub fn new() -> Self { - RingBuffer { buffer: [T::default(); SIZE], size: 0, write_ptr: 0, read_ptr: 0 } - } - - pub fn push(&mut self, value: T) { - self.buffer[self.write_ptr] = value; - if self.size < SIZE { - self.size += 1; - } else { - self.read_ptr += 1; - self.read_ptr %= SIZE; - } - self.write_ptr += 1; - self.write_ptr %= SIZE; - } - - pub fn to_vec(&self) -> Vec { - let mut out = Vec::new(); - let mut offset = self.read_ptr; - - for _ in 0..self.size { - out.push(self.buffer[offset]); - - offset += 1; - offset %= SIZE; - } - - out - } -} - -#[test] -fn test_ringbuffer() { - let mut ringbuffer: RingBuffer = RingBuffer::new(); - - for x in 0..16 { - ringbuffer.push(x); - } - - assert_eq!( - ringbuffer.to_vec().as_slice(), - &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] - ); - ringbuffer.push(16); - assert_eq!( - ringbuffer.to_vec().as_slice(), - &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] - ); - ringbuffer.push(17); - assert_eq!( - ringbuffer.to_vec().as_slice(), - &[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17] - ); - - for x in 18..32 { - ringbuffer.push(x); - } - assert_eq!( - ringbuffer.to_vec().as_slice(), - &[16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31] - ); -} - pub struct Gameboy { pub ppu: Ppu, pub memory: Memory, @@ -109,19 +37,11 @@ pub struct Gameboy { pub dma: DmaState, pub sound: Sound, - pub single_step: bool, - pub breakpoints: [bool; u16::MAX as usize + 1], - pub mem_read_breakpoints: [bool; u16::MAX as usize + 1], - pub mem_write_breakpoints: [bool; u16::MAX as usize + 1], - trigger_bp: bool, - pub log_instructions: bool, pub halt: bool, pub halt_bug: bool, pub used_halt_bug: bool, pub stop: bool, - pub pc_history: RingBuffer, - pub tick_count: u8, } @@ -141,41 +61,14 @@ impl Gameboy { false => Registers::post_rom(), }, sound: Sound::new(), - single_step: false, - breakpoints: [false; u16::MAX as usize + 1], - mem_read_breakpoints: [false; u16::MAX as usize + 1], - mem_write_breakpoints: [false; u16::MAX as usize + 1], - trigger_bp: false, - log_instructions: false, halt: false, halt_bug: false, used_halt_bug: false, stop: false, - pc_history: RingBuffer::new(), tick_count: 0, } } - fn log_next_opcode(&self) { - let op = self.internal_cpu_read_u8(self.registers.pc); - if op == 0xCB { - let op = self.internal_cpu_read_u8(self.registers.pc.overflowing_add(1).0); - log::info!( - "Executing opcode @ {:#X} (prefixed) (cycle {}): {:#X}", - self.registers.pc, - self.registers.cycle, - op - ); - } else { - log::info!( - "Executing opcode @ {:#X} (cycle {}): {:#X}", - self.registers.pc, - self.registers.cycle, - op - ); - } - } - pub fn load_cartridge(&mut self, bytes: Vec) { if bytes.len() < 0x150 { panic!("Bad cartridge (len < 0x150)"); @@ -189,215 +82,31 @@ impl Gameboy { } } - fn log_state(&self) { - log::info!("\n-- Registers --\nAF: {:04X}\nBC: {:04X}\nDE: {:04X}\nHL: {:04X}\nSP: {:04X}\nPC: {:04X}\nZero: {}\nSubtract: {}\nHalf-Carry: {}\nCarry: {}\n-- Interrupts --\nIME: {}\nIE VBlank: {}\nIE LCD Stat: {}\nIE Timer: {}\nIE Serial: {}\nIE Joypad: {}\nIF VBlank: {}\nIF LCD Stat: {}\nIF Timer: {}\nIF Serial: {}\nIF Joypad: {}\n", self.registers.get_af(), self.registers.get_bc(), self.registers.get_de(), self.registers.get_hl(), self.registers.get_sp(), self.registers.pc, self.registers.get_zero(), self.registers.get_subtract(), self.registers.get_half_carry(), self.registers.get_carry(), self.interrupts.ime, self.interrupts.read_ie_vblank(), self.interrupts.read_ie_lcd_stat(), self.interrupts.read_ie_timer(), self.interrupts.read_ie_serial(), self.interrupts.read_ie_joypad(), self.interrupts.read_if_vblank(), self.interrupts.read_if_lcd_stat(), self.interrupts.read_if_timer(), self.interrupts.read_if_serial(), self.interrupts.read_if_joypad()); - } - - pub fn tick_4(&mut self) -> (bool, Option) { + pub fn tick_4(&mut self) -> bool { let mut request_redraw = false; - let mut debug_time = None; for _ in 0..4 { - let (t_request_redraw, t_debug_time) = self.tick(); + let t_request_redraw = self.tick(); request_redraw |= t_request_redraw; - if t_debug_time.is_some() { - assert!(debug_time.is_none()); - debug_time = t_debug_time; - } } - - (request_redraw, debug_time) + request_redraw } - pub fn tick(&mut self) -> (bool, Option) { + pub fn tick(&mut self) -> bool { if self.tick_count == 0 { - if self.breakpoints[self.registers.pc as usize] && !self.single_step { - self.single_step = true; - log::info!("Breakpoint hit @ {:#X}", self.registers.pc); - } - - let mut diff = None; - - if self.trigger_bp || (self.single_step && self.registers.cycle == 0) { - let entered_step = Instant::now(); - self.trigger_bp = false; - self.single_step = true; - let mut input = String::new(); - let mut exit = true; - match std::io::stdin().read_line(&mut input) { - Ok(_) => { - let lower = input.trim_end().to_lowercase(); - let (lhs, rhs) = - lower.split_once(' ').unwrap_or_else(|| (lower.as_str(), "")); - match lhs { - "read" => match u16::from_str_radix(rhs, 16) { - Ok(address) => { - let res = self.internal_cpu_read_u8(address); - log::info!("{:#X}: {:#X} ({:#b})", address, res, res); - } - Err(_) => { - log::error!("Failed to parse input as hex u16 (f.ex 420C)") - } - }, - "regs" => self.log_state(), - "op" => { - self.log_next_opcode(); - } - "bp" => match u16::from_str_radix(rhs, 16) { - Ok(address) => { - let bp = &mut self.breakpoints[address as usize]; - *bp = !*bp; - match *bp { - true => log::info!("Set breakpoint @ {:#X}", address), - false => log::info!("Cleared breakpoint @ {:#X}", address), - } - } - Err(_) => { - log::error!("Failed to parse input as hex u16 (f.ex 420C)") - } - }, - "bpr" => match u16::from_str_radix(rhs, 16) { - Ok(address) => { - let bp = &mut self.mem_read_breakpoints[address as usize]; - *bp = !*bp; - match *bp { - true => { - log::info!("Set breakpoint on read @ {:#X}", address) - } - false => { - log::info!( - "Cleared breakpoint on read @ {:#X}", - address - ) - } - } - } - Err(_) => { - log::error!("Failed to parse input as hex u16 (f.ex 420C)") - } - }, - "bpw" => match u16::from_str_radix(rhs, 16) { - Ok(address) => { - let bp = &mut self.mem_write_breakpoints[address as usize]; - *bp = !*bp; - match *bp { - true => { - log::info!("Set breakpoint on write @ {:#X}", address) - } - false => { - log::info!( - "Cleared breakpoint on write @ {:#X}", - address - ) - } - } - } - Err(_) => { - log::error!("Failed to parse input as hex u16 (f.ex 420C)") - } - }, - "c" => { - self.single_step = false; - log::info!("Continuing"); - exit = false; - } - "timer" => { - println!( - "-- Timer Info --\n{:#?}\n-- End of Timer Info --", - self.timer - ) - } - "p" | "pause" => { - self.single_step = true; - log::info!("Single step activated"); - exit = false; - } - "pch" => { - println!("-- Start of PC History (new to old) --"); - for (idx, pc) in self.pc_history.to_vec().iter().rev().enumerate() { - println!("{}: {:#04X}", idx + 1, pc); - } - println!("-- End of PC History --"); - } - "s" | "step" | "" => { - self.log_next_opcode(); - exit = false; - } - "ls" => { - self.log_state(); - exit = false; - } - "dumpbgtiles" => { - self.ppu.dump_bg_tiles(); - } - "dumpfb" => { - println!("Written to: {}", self.ppu.dump_fb_to_file()); - } - "dumpoam" => { - for x in 0..self.ppu.oam.len() { - if x % 0x10 == 0 { - print!("\n{:X}: ", 0xFE00 + x) - } - - let mem_val = self.ppu.oam[x]; - print!("{:02X} ", mem_val); - } - println!(); - } - "dumpvram" => { - for x in 0..0x200 { - if x % 0x10 == 0 { - print!("\n{:X}: ", 0x8000 + x) - } - - let mem_val = self.ppu.vram[x]; - print!("{:02X} ", mem_val); - } - println!(); - } - "dumptilemap" => { - let base = match (self.ppu.registers.lcdc >> 3) & 0b1 == 1 { - true => 0x1C00, - false => 0x1800, - }; - - for x in 0..0x400 { - if x % 0x10 == 0 { - print!("\n{:X}: ", 0x8000 + base + x) - } - - let mem_val = self.ppu.vram[base + x]; - print!("{:02X} ", mem_val); - } - println!(); - } - _ => {} - } - } - Err(stdin_err) => panic!("Failed to lock stdin: {:?}", stdin_err), - } - - diff = Some(entered_step.elapsed()); - if exit { - return (false, diff); - } - } - if self.timer.tick() { - self.interrupts.write_if_timer(true); - } - cpu::tick_cpu(self); let redraw_requested = self.ppu.tick(&mut self.interrupts); self.dma.tick_dma(&mut self.ppu, &self.memory, self.cartridge.as_deref()); - if self.serial.tick() { - self.interrupts.write_if_serial(true); - } + self.serial.tick(&mut self.interrupts); + self.timer.tick(&mut self.interrupts); + self.tick_count += 1; - (redraw_requested, diff) + redraw_requested } else { let redraw_requested = self.ppu.tick(&mut self.interrupts); + self.timer.tick(&mut self.interrupts); self.tick_count += 1; self.tick_count %= 4; - (redraw_requested, None) + redraw_requested } } @@ -407,9 +116,9 @@ impl Gameboy { 0xFF01 => self.serial.sb, 0xFF02 => self.serial.get_sc(), 0xFF03 => 0xFF, // Unused - 0xFF04 => self.timer.div, - 0xFF05 => self.timer.tima, - 0xFF06 => self.timer.tma, + 0xFF04 => self.timer.read_div(), + 0xFF05 => self.timer.read_tima(), + 0xFF06 => self.timer.read_tma(), 0xFF07 => self.timer.read_tac(), 0xFF08..=0xFF0E => 0xFF, // Unused 0xFF0F => self.interrupts.interrupt_flag, @@ -469,9 +178,9 @@ impl Gameboy { 0xFF01 => self.serial.sb = value, 0xFF02 => self.serial.set_sc(value), 0xFF03 => {} // Unused - 0xFF04 => self.timer.div = 0, - 0xFF05 => self.timer.tima = value, - 0xFF06 => self.timer.tma = value, + 0xFF04 => self.timer.write_div(), + 0xFF05 => self.timer.write_tima(value), + 0xFF06 => self.timer.write_tma(value), 0xFF07 => self.timer.write_tac(value), 0xFF08..=0xFF0E => {} // Unused 0xFF0F => self.interrupts.interrupt_flag = value | !0b1_1111, @@ -485,19 +194,19 @@ impl Gameboy { 0xFF17 => self.sound.nr22 = value, 0xFF18 => self.sound.nr23 = value, 0xFF19 => self.sound.nr24 = value, - 0xFF1A => {}, //self.sound.nr30 = value, - Unwritable on DMG + 0xFF1A => {} //self.sound.nr30 = value, - Unwritable on DMG 0xFF1B => self.sound.nr31 = value, - 0xFF1C => {}, //self.sound.nr32 = value, - Unwritable on DMG + 0xFF1C => {} //self.sound.nr32 = value, - Unwritable on DMG 0xFF1D => self.sound.nr33 = value, 0xFF1E => self.sound.nr34 = value, 0xFF1F => {} - 0xFF20 => {}, //self.sound.nr41 = value, - Unwritable on DMG + 0xFF20 => {} //self.sound.nr41 = value, - Unwritable on DMG 0xFF21 => self.sound.nr42 = value, 0xFF22 => self.sound.nr43 = value, - 0xFF23 => {}, //self.sound.nr44 = value, - Unwritable on DMG + 0xFF23 => {} //self.sound.nr44 = value, - Unwritable on DMG 0xFF24 => self.sound.nr50 = value, 0xFF25 => self.sound.nr51 = value, - 0xFF26 => {}, //self.sound.nr52 = value, - Unwritable on DMG + 0xFF26 => {} //self.sound.nr52 = value, - Unwritable on DMG 0xFF27..=0xFF2F => {} 0xFF30..=0xFF3F => self.sound.wave_pattern_ram[address as usize - 0xFF30] = value, 0xFF40 => { @@ -555,12 +264,12 @@ impl Gameboy { 0..=0xFF if !self.memory.bootrom_disabled => self.memory.bootrom[address as usize], 0..=0x7FFF => match self.cartridge.as_ref() { Some(mapper) => mapper.read_rom_u8(address), - None => 0, + None => 0xFF, }, 0x8000..=0x9FFF => self.ppu.cpu_read_vram(address), 0xA000..=0xBFFF => match self.cartridge.as_ref() { - Some(mapper) => mapper.read_eram_u8(address), - None => 0, + Some(mapper) => mapper.read_eram_u8(address - 0xA000), + None => 0xFF, }, 0xC000..=0xDFFF => self.memory.wram[address as usize - 0xC000], 0xE000..=0xFDFF => self.memory.wram[address as usize - 0xE000], @@ -586,7 +295,7 @@ impl Gameboy { 0x8000..=0x9FFF => self.ppu.cpu_write_vram(address, value), 0xA000..=0xBFFF => { if let Some(mapper) = self.cartridge.as_mut() { - mapper.write_eram_u8(address, value) + mapper.write_eram_u8(address - 0xA000, value) } } 0xC000..=0xDFFF => self.memory.wram[address as usize - 0xC000] = value, @@ -599,18 +308,27 @@ impl Gameboy { } } - fn internal_cpu_read_u8(&self, address: u16) -> u8 { - if !self.ppu.dma_occuring { - match address { + pub fn cpu_read_u8(&mut self, address: u16) { + assert!(!self.registers.mem_op_happened); + assert!(self.registers.mem_read_hold.is_none()); + self.registers.mem_op_happened = true; + let value = match self.ppu.dma_occuring { + true => match address { + 0..=0xFEFF => 0xFF, + 0xFF00..=0xFF7F => self.cpu_read_io(address), + 0xFF80..=0xFFFE => self.memory.hram[address as usize - 0xFF80], + 0xFFFF => self.interrupts.interrupt_enable, + }, + false => match address { 0..=0xFF if !self.memory.bootrom_disabled => self.memory.bootrom[address as usize], 0..=0x7FFF => match self.cartridge.as_ref() { Some(mapper) => mapper.read_rom_u8(address), - None => 0, + None => 0xFF, }, 0x8000..=0x9FFF => self.ppu.cpu_read_vram(address), 0xA000..=0xBFFF => match self.cartridge.as_ref() { - Some(mapper) => mapper.read_eram_u8(address), - None => 0, + Some(mapper) => mapper.read_eram_u8(address - 0xA000), + None => 0xFF, }, 0xC000..=0xDFFF => self.memory.wram[address as usize - 0xC000], 0xE000..=0xFDFF => self.memory.wram[address as usize - 0xE000], @@ -619,41 +337,23 @@ impl Gameboy { 0xFF00..=0xFF7F => self.cpu_read_io(address), 0xFF80..=0xFFFE => self.memory.hram[address as usize - 0xFF80], 0xFFFF => self.interrupts.interrupt_enable, - } - } else { - match address { - 0..=0xFEFF => 0xFF, - 0xFF00..=0xFF7F => self.cpu_read_io(address), - 0xFF80..=0xFFFE => self.memory.hram[address as usize - 0xFF80], - 0xFFFF => self.interrupts.interrupt_enable, - } - } - } - - pub fn cpu_read_u8(&mut self, address: u16) { - assert!(!self.registers.mem_op_happened); - assert!(self.registers.mem_read_hold.is_none()); - self.registers.mem_op_happened = true; - - if self.mem_read_breakpoints[address as usize] { - self.trigger_bp = true; - log::info!("Triggered read bp @ {:#X}", address); - } - - self.registers.mem_read_hold = Some(self.internal_cpu_read_u8(address)); + }, + }; + self.registers.mem_read_hold = Some(value); } pub fn cpu_write_u8(&mut self, address: u16, value: u8) { assert!(!self.registers.mem_op_happened); self.registers.mem_op_happened = true; - if self.mem_write_breakpoints[address as usize] { - self.trigger_bp = true; - log::info!("Triggered write bp @ {:#X} (value: {:#02X})", address, value); - } - - if !self.ppu.dma_occuring { - match address { + match self.ppu.dma_occuring { + true => 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.cpu_set_interrupt_enable(value), + }, + false => match address { 0..=0xFF if !self.memory.bootrom_disabled => {} 0..=0x7FFF => { if let Some(mapper) = self.cartridge.as_mut() { @@ -663,7 +363,7 @@ impl Gameboy { 0x8000..=0x9FFF => self.ppu.cpu_write_vram(address, value), 0xA000..=0xBFFF => { if let Some(mapper) = self.cartridge.as_mut() { - mapper.write_eram_u8(address, value) + mapper.write_eram_u8(address - 0xA000, value) } } 0xC000..=0xDFFF => self.memory.wram[address as usize - 0xC000] = value, @@ -673,14 +373,7 @@ impl Gameboy { 0xFF00..=0xFF7F => self.cpu_write_io(address, value), 0xFF80..=0xFFFE => self.memory.hram[address as usize - 0xFF80] = value, 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.cpu_set_interrupt_enable(value), - } + }, } } diff --git a/meowgb-core/src/gameboy/cpu.rs b/meowgb-core/src/gameboy/cpu.rs index 5c61372..0ebe4d2 100644 --- a/meowgb-core/src/gameboy/cpu.rs +++ b/meowgb-core/src/gameboy/cpu.rs @@ -238,19 +238,16 @@ pub fn tick_cpu(state: &mut Gameboy) { } else { let opcode = match state.registers.current_opcode { Some(opcode) => opcode, - None => { - state.pc_history.push(state.registers.pc); - match state.registers.mem_read_hold.take() { - Some(opcode) => { - state.registers.current_opcode = Some(opcode); - opcode - } - None => { - state.cpu_read_u8(state.registers.pc); - return; - } + None => match state.registers.mem_read_hold.take() { + Some(opcode) => { + state.registers.current_opcode = Some(opcode); + opcode } - } + None => { + state.cpu_read_u8(state.registers.pc); + return; + } + }, }; let result: CycleResult = match opcode { diff --git a/meowgb-core/src/gameboy/cpu/misc.rs b/meowgb-core/src/gameboy/cpu/misc.rs index 5c33229..550f5c2 100644 --- a/meowgb-core/src/gameboy/cpu/misc.rs +++ b/meowgb-core/src/gameboy/cpu/misc.rs @@ -56,12 +56,12 @@ opcode!(stop, 0x10, "STOP", false, 1, { true => { state.registers.pc = state.registers.pc.wrapping_add(1); state.stop = true; - state.timer.div = 0; + state.timer.write_div(); }, false => { state.registers.pc = state.registers.pc.wrapping_add(2); state.stop = true; - state.timer.div = 0; + state.timer.write_div(); } }, } diff --git a/meowgb-core/src/gameboy/dma.rs b/meowgb-core/src/gameboy/dma.rs index c419e98..b774e35 100644 --- a/meowgb-core/src/gameboy/dma.rs +++ b/meowgb-core/src/gameboy/dma.rs @@ -1,11 +1,11 @@ -use super::{ppu::Ppu, memory::Memory, mapper::Mapper}; +use super::{mapper::Mapper, memory::Memory, ppu::Ppu}; #[derive(Debug)] pub struct DmaState { original_base: u8, pub base: u8, pub remaining_cycles: u8, - restarting: Option<(u8, bool)>, + restarting: Option<(u8, bool)>, } impl DmaState { @@ -14,22 +14,27 @@ impl DmaState { } pub fn init_request(&mut self, base: u8) { - self.base = base; - self.restarting = Some((base, false)); + 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 => {}, - } + 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; + ppu.dma_occuring = self.remaining_cycles > 0; if self.remaining_cycles > 0 { let offset = 0xA0 - self.remaining_cycles; @@ -55,7 +60,5 @@ impl DmaState { ppu.dma_write_oam(offset, value); self.remaining_cycles -= 1; } - } - -} \ No newline at end of file +} diff --git a/meowgb-core/src/gameboy/joypad.rs b/meowgb-core/src/gameboy/joypad.rs index 4b5e613..ffc048e 100644 --- a/meowgb-core/src/gameboy/joypad.rs +++ b/meowgb-core/src/gameboy/joypad.rs @@ -57,23 +57,23 @@ impl Joypad { } pub fn cpu_read(&self) -> u8 { - (0b11 << 6) | match self.mode { - JoypadMode::Action => { - (1 << 4) - | ((!self.start as u8) << 3) - | ((!self.select as u8) << 2) - | ((!self.b as u8) << 1) - | (!self.a as u8) + (0b11 << 6) + | match self.mode { + JoypadMode::Action => { + (1 << 4) + | ((!self.start as u8) << 3) + | ((!self.select as u8) << 2) + | ((!self.b as u8) << 1) | (!self.a as u8) + } + JoypadMode::Direction => { + (1 << 5) + | ((!self.down as u8) << 3) + | ((!self.up as u8) << 2) + | ((!self.left as u8) << 1) + | (!self.right as u8) + } + JoypadMode::Both => 0b1111, } - JoypadMode::Direction => { - (1 << 5) - | ((!self.down as u8) << 3) - | ((!self.up as u8) << 2) - | ((!self.left as u8) << 1) - | (!self.right as u8) - } - JoypadMode::Both => 0b1111, - } } joypad_input!(a, Action); diff --git a/meowgb-core/src/gameboy/mapper.rs b/meowgb-core/src/gameboy/mapper.rs index 657b29c..a762fc1 100644 --- a/meowgb-core/src/gameboy/mapper.rs +++ b/meowgb-core/src/gameboy/mapper.rs @@ -4,7 +4,9 @@ pub trait Mapper { fn read_rom_u8(&self, address: u16) -> u8; fn write_rom_u8(&mut self, address: u16, value: u8); + /// The address passed into this function MUST be zero indexed fn read_eram_u8(&self, address: u16) -> u8; + /// The address passed into this function MUST be zero indexed fn write_eram_u8(&mut self, address: u16, value: u8); } diff --git a/meowgb-core/src/gameboy/mapper/mbc1.rs b/meowgb-core/src/gameboy/mapper/mbc1.rs index 3bfa739..f257a6d 100644 --- a/meowgb-core/src/gameboy/mapper/mbc1.rs +++ b/meowgb-core/src/gameboy/mapper/mbc1.rs @@ -99,16 +99,23 @@ impl Mapper for MBC1 { } } - fn read_eram_u8(&self, _address: u16) -> u8 { + fn read_eram_u8(&self, address: u16) -> u8 { match self.ram.as_ref() { - Some(_ram) => 0, - None => 0, + Some(ram) => match self.is_large_rom() { + true => ram[address as usize], + false => ram[(self.extra_2_bit_reg as usize * 0x2000) + address as usize], + }, + None => 0xFF, } } - fn write_eram_u8(&mut self, _address: u16, _value: u8) { - match self.ram.as_ref() { - Some(_ram) => {} + fn write_eram_u8(&mut self, address: u16, value: u8) { + let is_large_rom = self.is_large_rom(); + match self.ram.as_mut() { + Some(ram) => match is_large_rom { + true => ram[address as usize] = value, + false => ram[(self.extra_2_bit_reg as usize * 0x2000) + address as usize] = value, + }, None => {} } } diff --git a/meowgb-core/src/gameboy/serial.rs b/meowgb-core/src/gameboy/serial.rs index a4eca9e..bbee6a3 100644 --- a/meowgb-core/src/gameboy/serial.rs +++ b/meowgb-core/src/gameboy/serial.rs @@ -1,5 +1,7 @@ use std::io::Write; +use super::interrupts::Interrupts; + pub trait SerialWriter { fn write_byte(&mut self, byte: u8); } @@ -53,7 +55,7 @@ impl Serial { self.sc |= conductor as u8; } - pub fn tick(&mut self) -> bool { + pub fn tick(&mut self, interrupts: &mut Interrupts) { if self.get_transfer_in_process() && self.is_conductor() { if self.internal_tick < 128 { self.internal_tick += 1; @@ -62,9 +64,8 @@ impl Serial { self.sb = 0; self.set_transfer_in_process(false); self.internal_tick = 0; - return true; + interrupts.write_if_serial(true); } } - false } } diff --git a/meowgb-core/src/gameboy/sound.rs b/meowgb-core/src/gameboy/sound.rs index 191b71d..714a31d 100644 --- a/meowgb-core/src/gameboy/sound.rs +++ b/meowgb-core/src/gameboy/sound.rs @@ -53,7 +53,7 @@ impl Sound { nr50: 0b0111_0111, nr51: 0b1111_0011, nr52: 0b1111_0001, - wave_pattern_ram: [0u8;16], + wave_pattern_ram: [0u8; 16], } } } diff --git a/meowgb-core/src/gameboy/timer.rs b/meowgb-core/src/gameboy/timer.rs index 00d19bf..4d62165 100644 --- a/meowgb-core/src/gameboy/timer.rs +++ b/meowgb-core/src/gameboy/timer.rs @@ -1,13 +1,14 @@ +use super::interrupts::Interrupts; + #[derive(Debug)] pub struct Timer { - pub enable: bool, - pub clock: TimerClock, - pub div: u8, - pub div_counter: u8, - pub tima: u8, - pub tima_counter: u16, - pub tma: u8, - overflow: bool, + enable: bool, + clock: TimerClock, + div: u16, + tima: u8, + tma: u8, + overflow_begin_div: u16, + overflow: u8, } impl Timer { @@ -17,36 +18,83 @@ impl Timer { clock: TimerClock::C1024, tima: 0, tma: 0, - div: 0xAD, - div_counter: 0, - tima_counter: 0, - overflow: false, + div: 0xAC << 8, + overflow_begin_div: 0, + overflow: 0u8, } } - pub fn tick(&mut self) -> bool { - self.div_counter = self.div_counter.wrapping_add(1); - if self.div_counter == 0 { - self.div = self.div.wrapping_add(1); - } + pub fn tick(&mut self, interrupts: &mut Interrupts) { + self.overflow %= 4; + let old_div = self.div; + self.div = self.div.wrapping_add(1); if self.enable { - self.tima_counter = self.tima_counter.wrapping_add(4); - if self.tima_counter >= self.clock.cycles() { - self.tima_counter = 0; - self.tima = self.tima.wrapping_add(1); - - self.overflow = self.tima == 0; - return false; + if self.div & self.clock.div_falling_edge_bit() == 0 + && old_div & self.clock.div_falling_edge_bit() != 0 + { + self.increment_tima(); + return; } } - if self.overflow { - self.tima = self.tma; - self.overflow = false; - return true; + match self.overflow { + 0 => {} + 1..=2 => { + if self.overflow_begin_div != old_div { + self.overflow += 1; + } + } + 3 => { + self.tima = self.tma; + self.overflow += 1; + interrupts.write_if_timer(true); + } + _ => unreachable!(), } - false + } + + pub fn read_div(&self) -> u8 { + (self.div >> 8) as u8 + } + + pub fn read_tima(&self) -> u8 { + self.tima + } + + pub fn read_tma(&self) -> u8 { + self.tma + } + + pub fn write_tma(&mut self, value: u8) { + self.tma = value; + if self.overflow == 4 { + self.tima = value; + } + } + + pub fn write_tima(&mut self, value: u8) { + if self.overflow < 3 { + self.tima = value; + self.overflow = 0; + } + } + + fn increment_tima(&mut self) { + let (new_tima, overflowed) = self.tima.overflowing_add(1); + self.tima = new_tima; + if overflowed { + self.overflow = 1; + self.overflow_begin_div = self.div; + } + } + + pub fn write_div(&mut self) { + if self.div & self.clock.div_falling_edge_bit() != 0 { + self.increment_tima(); + } + + self.div = 0; } pub fn read_tac(&self) -> u8 { @@ -54,28 +102,38 @@ impl Timer { } pub fn write_tac(&mut self, value: u8) { - self.enable = (value >> 2) & 0b1 == 1; - self.tima_counter = 0; + let new_enable = (value >> 2) & 0b1 == 1; let new_clock = TimerClock::from_tac_clock(value); - if self.clock == TimerClock::C16 && new_clock == TimerClock::C1024 && self.enable { - self.tima = self.tima.wrapping_add(1); - self.overflow = self.tima == 0; + if self.enable { + let should_increment = match new_enable { + true => { + self.div & self.clock.div_falling_edge_bit() != 0 + && self.div & new_clock.div_falling_edge_bit() == 0 + } + false => self.div & self.clock.div_falling_edge_bit() != 0, + }; + + if should_increment { + self.increment_tima(); + } } + + self.enable = new_enable; self.clock = new_clock; } } -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum TimerClock { - C16, - C64, - C256, - C1024, + C16 = 1, + C64 = 2, + C256 = 3, + C1024 = 0, } impl TimerClock { - pub fn cycles(&self) -> u16 { + pub const fn cycles(self) -> u16 { match self { Self::C16 => 16, Self::C64 => 64, @@ -84,7 +142,7 @@ impl TimerClock { } } - pub fn tac_clock(&self) -> u8 { + pub const fn tac_clock(self) -> u8 { match self { Self::C16 => 1, Self::C64 => 2, @@ -93,7 +151,7 @@ impl TimerClock { } } - pub fn from_tac_clock(value: u8) -> Self { + pub const fn from_tac_clock(value: u8) -> Self { match value & 0b11 { 1 => Self::C16, 2 => Self::C64, @@ -102,4 +160,8 @@ impl TimerClock { _ => unreachable!(), } } + + pub const fn div_falling_edge_bit(self) -> u16 { + self.cycles() / 2 + } } diff --git a/meowgb-core/src/lib.rs b/meowgb-core/src/lib.rs index 9e0a2bb..06dd4a4 100644 --- a/meowgb-core/src/lib.rs +++ b/meowgb-core/src/lib.rs @@ -1,5 +1,9 @@ pub mod gameboy; +pub mod ringbuffer; +/// A helper for writing CPU tests in Rust, the emulator returned by this +/// function has already fetched the first instruction. The next tick will be +/// the first tick of the instruction pub fn setup_test_emulator( test_opcodes: [u8; ROM_LENGTH], ) -> gameboy::Gameboy { diff --git a/meowgb-core/src/ringbuffer.rs b/meowgb-core/src/ringbuffer.rs new file mode 100644 index 0000000..8442ce3 --- /dev/null +++ b/meowgb-core/src/ringbuffer.rs @@ -0,0 +1,70 @@ +pub struct RingBuffer { + buffer: [T; SIZE], + size: usize, + write_ptr: usize, + read_ptr: usize, +} + +impl RingBuffer { + pub fn new() -> Self { + RingBuffer { buffer: [T::default(); SIZE], size: 0, write_ptr: 0, read_ptr: 0 } + } + + pub fn push(&mut self, value: T) { + self.buffer[self.write_ptr] = value; + if self.size < SIZE { + self.size += 1; + } else { + self.read_ptr += 1; + self.read_ptr %= SIZE; + } + self.write_ptr += 1; + self.write_ptr %= SIZE; + } + + pub fn to_vec(&self) -> Vec { + let mut out = Vec::new(); + let mut offset = self.read_ptr; + + for _ in 0..self.size { + out.push(self.buffer[offset]); + + offset += 1; + offset %= SIZE; + } + + out + } +} + +#[test] +fn test_ringbuffer() { + let mut ringbuffer: RingBuffer = RingBuffer::new(); + + for x in 0..16 { + ringbuffer.push(x); + } + + assert_eq!( + ringbuffer.to_vec().as_slice(), + &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] + ); + ringbuffer.push(16); + assert_eq!( + ringbuffer.to_vec().as_slice(), + &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] + ); + ringbuffer.push(17); + assert_eq!( + ringbuffer.to_vec().as_slice(), + &[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17] + ); + + for x in 18..32 { + ringbuffer.push(x); + } + assert_eq!( + ringbuffer.to_vec().as_slice(), + &[16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31] + ); +} diff --git a/meowgb-opcode/src/lib.rs b/meowgb-opcode/src/lib.rs index ffc8653..bdaa390 100644 --- a/meowgb-opcode/src/lib.rs +++ b/meowgb-opcode/src/lib.rs @@ -67,17 +67,23 @@ pub fn opcode(item: TokenStream) -> TokenStream { block.push(op_impl.block); } - /*if !cycle.is_empty() { - if cycle[0].base10_parse::().expect("Expected u8") == 0u8 { - block[0].stmts.insert(0, Stmt::Semi(Expr::Macro(ExprMacro::))) - } else { - - } - }*/ - - let regs = quote::quote! { - log::debug!("\nSTART OF {}\n-- Registers --\nAF: {:04X}\nBC: {:04X}\nDE: {:04X}\nHL: {:04X}\nSP: {:04X}\nPC: {:04X}\nZero: {}\nSubtract: {}\nHalf-Carry: {}\nCarry: {}\n-- Interrupts --\nIME: {}\nIE VBlank: {}\nIE LCD Stat: {}\nIE Timer: {}\nIE Serial: {}\nIE Joypad: {}\nIF VBlank: {}\nIF LCD Stat: {}\nIF Timer: {}\nIF Serial: {}\nIF Joypad: {}\nEND OF {}", #name_s, state.registers.get_af(), state.registers.get_bc(), state.registers.get_de(), state.registers.get_hl(), state.registers.get_sp(), state.registers.pc, state.registers.get_zero(), state.registers.get_subtract(), state.registers.get_half_carry(), state.registers.get_carry(), state.interrupts.ime, state.interrupts.read_ie_vblank(), state.interrupts.read_ie_lcd_stat(), state.interrupts.read_ie_timer(), state.interrupts.read_ie_serial(), state.interrupts.read_ie_joypad(), state.interrupts.read_if_vblank(), state.interrupts.read_if_lcd_stat(), state.interrupts.read_if_timer(), state.interrupts.read_if_serial(), state.interrupts.read_if_joypad(), #name_s); - }; + // let regs = quote::quote! { + // log::debug!("\nSTART OF {}\n-- Registers --\nAF: {:04X}\nBC: {:04X}\nDE: + // {:04X}\nHL: {:04X}\nSP: {:04X}\nPC: {:04X}\nZero: {}\nSubtract: + // {}\nHalf-Carry: {}\nCarry: {}\n-- Interrupts --\nIME: {}\nIE VBlank: {}\nIE + // LCD Stat: {}\nIE Timer: {}\nIE Serial: {}\nIE Joypad: {}\nIF VBlank: {}\nIF + // LCD Stat: {}\nIF Timer: {}\nIF Serial: {}\nIF Joypad: {}\nEND OF {}", + // #name_s, state.registers.get_af(), state.registers.get_bc(), + // state.registers.get_de(), state.registers.get_hl(), state.registers.get_sp(), + // state.registers.pc, state.registers.get_zero(), + // state.registers.get_subtract(), state.registers.get_half_carry(), + // state.registers.get_carry(), state.interrupts.ime, + // state.interrupts.read_ie_vblank(), state.interrupts.read_ie_lcd_stat(), + // state.interrupts.read_ie_timer(), state.interrupts.read_ie_serial(), + // state.interrupts.read_ie_joypad(), state.interrupts.read_if_vblank(), + // state.interrupts.read_if_lcd_stat(), state.interrupts.read_if_timer(), + // state.interrupts.read_if_serial(), state.interrupts.read_if_joypad(), + // #name_s); }; let match_statement = quote::quote! { match state.registers.cycle { @@ -88,26 +94,34 @@ pub fn opcode(item: TokenStream) -> TokenStream { } }; - let log = if extended.value { - quote::quote! { - if state.registers.cycle == 1 && state.log_instructions { - log::debug!("(PC: {:#02X}) Prefixed OP {} ({:#02X})", state.registers.pc, #readable, #opcode); - #regs - } - } - } else { - quote::quote! { - if state.registers.cycle == 0 && state.log_instructions { - log::debug!("(PC: {:#02X}) OP {} ({:#02X})", state.registers.pc, #readable, #opcode); - #regs - } - } + // let log = if extended.value { + // quote::quote! { + // if state.registers.cycle == 1 && state.log_instructions { + // log::debug!("(PC: {:#02X}) Prefixed OP {} ({:#02X})", state.registers.pc, + // #readable, #opcode); #regs + // } + // } + // } else { + // quote::quote! { + // if state.registers.cycle == 0 && state.log_instructions { + // log::debug!("(PC: {:#02X}) OP {} ({:#02X})", state.registers.pc, #readable, + // #opcode); #regs + // } + // } + // }; + + let check_opcode = match extended.value { + true => quote::quote! { + assert_eq!(state.registers.current_prefixed_opcode, Some(#opcode), std::concat!("Prefixed instruction ", #name_s, " handler was called with the wrong opcode")); + }, + false => quote::quote! { + assert_eq!(state.registers.current_opcode, Some(#opcode), std::concat!("Instruction \"", #name_s, "\" handler was called with the wrong opcode")); + }, }; let out = quote::quote! { #fn_sig { - #log - + #check_opcode let res: CycleResult = #match_statement; if res != CycleResult::NeedsMore { diff --git a/meowgb-tests/expected_output/div_timing.bin b/meowgb-tests/expected_output/div_timing.bin new file mode 100644 index 0000000..2a02163 --- /dev/null +++ b/meowgb-tests/expected_output/div_timing.bin @@ -0,0 +1 @@ + " \ No newline at end of file diff --git a/meowgb-tests/expected_output/div_write.bin b/meowgb-tests/expected_output/div_write.bin new file mode 100644 index 0000000..2a02163 --- /dev/null +++ b/meowgb-tests/expected_output/div_write.bin @@ -0,0 +1 @@ + " \ No newline at end of file diff --git a/meowgb-tests/expected_output/rapid_toggle.bin b/meowgb-tests/expected_output/rapid_toggle.bin new file mode 100644 index 0000000..2a02163 --- /dev/null +++ b/meowgb-tests/expected_output/rapid_toggle.bin @@ -0,0 +1 @@ + " \ No newline at end of file diff --git a/meowgb-tests/expected_output/tim00.bin b/meowgb-tests/expected_output/tim00.bin new file mode 100644 index 0000000..2a02163 --- /dev/null +++ b/meowgb-tests/expected_output/tim00.bin @@ -0,0 +1 @@ + " \ No newline at end of file diff --git a/meowgb-tests/expected_output/tim01_div_trigger.bin b/meowgb-tests/expected_output/tim01_div_trigger.bin new file mode 100644 index 0000000..2a02163 --- /dev/null +++ b/meowgb-tests/expected_output/tim01_div_trigger.bin @@ -0,0 +1 @@ + " \ No newline at end of file diff --git a/meowgb-tests/expected_output/tim10.bin b/meowgb-tests/expected_output/tim10.bin new file mode 100644 index 0000000..2a02163 --- /dev/null +++ b/meowgb-tests/expected_output/tim10.bin @@ -0,0 +1 @@ + " \ No newline at end of file diff --git a/meowgb-tests/expected_output/tim10_div_trigger.bin b/meowgb-tests/expected_output/tim10_div_trigger.bin new file mode 100644 index 0000000..2a02163 --- /dev/null +++ b/meowgb-tests/expected_output/tim10_div_trigger.bin @@ -0,0 +1 @@ + " \ No newline at end of file diff --git a/meowgb-tests/expected_output/tim11.bin b/meowgb-tests/expected_output/tim11.bin new file mode 100644 index 0000000..2a02163 --- /dev/null +++ b/meowgb-tests/expected_output/tim11.bin @@ -0,0 +1 @@ + " \ No newline at end of file diff --git a/meowgb-tests/expected_output/tima_reload.bin b/meowgb-tests/expected_output/tima_reload.bin new file mode 100644 index 0000000..2a02163 --- /dev/null +++ b/meowgb-tests/expected_output/tima_reload.bin @@ -0,0 +1 @@ + " \ No newline at end of file diff --git a/meowgb-tests/expected_output/tima_write_reloading.bin b/meowgb-tests/expected_output/tima_write_reloading.bin new file mode 100644 index 0000000..2a02163 --- /dev/null +++ b/meowgb-tests/expected_output/tima_write_reloading.bin @@ -0,0 +1 @@ + " \ No newline at end of file diff --git a/meowgb-tests/expected_output/tma_write_reloading.bin b/meowgb-tests/expected_output/tma_write_reloading.bin new file mode 100644 index 0000000..2a02163 --- /dev/null +++ b/meowgb-tests/expected_output/tma_write_reloading.bin @@ -0,0 +1 @@ + " \ No newline at end of file diff --git a/meowgb/src/main.rs b/meowgb/src/main.rs index 9287a2f..e6a2f29 100644 --- a/meowgb/src/main.rs +++ b/meowgb/src/main.rs @@ -28,9 +28,6 @@ pub struct CliArgs { /// game path #[clap(long)] pub rom: Option, - // enter in debu g mode - #[clap(short, long)] - pub debug: bool, } #[derive(Debug, thiserror::Error)] @@ -99,11 +96,6 @@ pub fn run_gameboy( ) -> Result<(), MeowGBError> { let mut gameboy = gameboy_arc.write().unwrap(); - if args.debug { - gameboy.single_step = true; - tx.send(GameboyEvent::Framebuffer(gameboy.ppu.write_fb())).unwrap(); - } - if let Some(rom) = args.rom { if !rom.is_file() { return Err(MeowGBError::GameNotFound); @@ -132,19 +124,15 @@ pub fn run_gameboy( EmulatorWindowEvent::DownToggle => gameboy.joypad.invert_down(), EmulatorWindowEvent::LeftToggle => gameboy.joypad.invert_left(), EmulatorWindowEvent::RightToggle => gameboy.joypad.invert_right(), - EmulatorWindowEvent::PauseToggle => gameboy.single_step = !gameboy.single_step, + EmulatorWindowEvent::PauseToggle => unimplemented!(), EmulatorWindowEvent::Exit => break 'outer, } } - let (redraw_needed, time_spent_debugging) = gameboy.tick_4(); + let redraw_needed = gameboy.tick_4(); drop(gameboy); - if let Some(diff) = time_spent_debugging { - goal = goal + diff; - } - if redraw_needed { let now = time::OffsetDateTime::now_utc(); frame_counter += 1; diff --git a/run-test-roms.sh b/run-test-roms.sh new file mode 100755 index 0000000..f949bb6 --- /dev/null +++ b/run-test-roms.sh @@ -0,0 +1,370 @@ +echo "Running Test Roms..." + +if ! cargo build -p meowgb-tests --release ; then + exit +fi + +TEST_TOTAL=0 +TEST_SUCCESS=0 + +echo "Running test ROM ./test-roms/blargg/roms/cpu_instrs.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/blargg/roms/cpu_instrs.gb test -m 100000000 -s meowgb-tests/expected_output/cpu_instrs.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/blargg/roms/instr_timing.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/blargg/roms/instr_timing.gb test -m 100000000 -s meowgb-tests/expected_output/instr_timing.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/blargg/roms/mem_timing.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/blargg/roms/mem_timing.gb test -m 100000000 -s meowgb-tests/expected_output/mem_timing.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/basic.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/basic.gb test -m 100000000 -s meowgb-tests/expected_output/basic.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/boot_hwio-dmgABCmgb.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/boot_hwio-dmgABCmgb.gb test -m 100000000 -s meowgb-tests/expected_output/boot_hwio-dmgABCmgb.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/boot_regs-dmgABC.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/boot_regs-dmgABC.gb test -m 100000000 -s meowgb-tests/expected_output/boot_regs-dmgABC.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/daa.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/daa.gb test -m 100000000 -s meowgb-tests/expected_output/daa.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/div_timing.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/div_timing.gb test -m 100000000 -s meowgb-tests/expected_output/div_timing.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/div_write.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/div_write.gb test -m 100000000 -s meowgb-tests/expected_output/div_write.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/ei_sequence.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/ei_sequence.gb test -m 100000000 -s meowgb-tests/expected_output/ei_sequence.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/ei_timing.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/ei_timing.gb test -m 100000000 -s meowgb-tests/expected_output/ei_timing.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/halt_ime0_ei.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/halt_ime0_ei.gb test -m 100000000 -s meowgb-tests/expected_output/halt_ime0_ei.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/intr_1_2_timing-GS.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests 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 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/intr_2_0_timing.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/intr_2_0_timing.gb test -m 100000000 -s meowgb-tests/expected_output/intr_2_0_timing.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/mem_oam.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/mem_oam.gb test -m 100000000 -s meowgb-tests/expected_output/mem_oam.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/oam_dma_restart.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/oam_dma_restart.gb test -m 100000000 -s meowgb-tests/expected_output/oam_dma_restart.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/oam_dma_start.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/oam_dma_start.gb test -m 100000000 -s meowgb-tests/expected_output/oam_dma_start.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/oam_dma_timing.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/oam_dma_timing.gb test -m 100000000 -s meowgb-tests/expected_output/oam_dma_timing.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/rapid_di_ei.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/rapid_di_ei.gb test -m 100000000 -s meowgb-tests/expected_output/rapid_di_ei.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/rapid_toggle.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/rapid_toggle.gb test -m 100000000 -s meowgb-tests/expected_output/rapid_toggle.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/reg_f.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/reg_f.gb test -m 100000000 -s meowgb-tests/expected_output/reg_f.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/reg_read.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/reg_read.gb test -m 100000000 -s meowgb-tests/expected_output/reg_read.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/stat_irq_blocking.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/stat_irq_blocking.gb test -m 100000000 -s meowgb-tests/expected_output/stat_irq_blocking.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/stat_lyc_onoff.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/stat_lyc_onoff.gb test -m 100000000 -s meowgb-tests/expected_output/stat_lyc_onoff.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/tim00.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/tim00.gb test -m 100000000 -s meowgb-tests/expected_output/tim00.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/tim00_div_trigger.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/tim00_div_trigger.gb test -m 100000000 -s meowgb-tests/expected_output/tim00_div_trigger.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/tim01.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/tim01.gb test -m 100000000 -s meowgb-tests/expected_output/tim01.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/tim01_div_trigger.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/tim01_div_trigger.gb test -m 100000000 -s meowgb-tests/expected_output/tim01_div_trigger.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/tim10.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/tim10.gb test -m 100000000 -s meowgb-tests/expected_output/tim10.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/tim10_div_trigger.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/tim10_div_trigger.gb test -m 100000000 -s meowgb-tests/expected_output/tim10_div_trigger.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/tim11.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/tim11.gb test -m 100000000 -s meowgb-tests/expected_output/tim11.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/tim11_div_trigger.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/tim11_div_trigger.gb test -m 100000000 -s meowgb-tests/expected_output/tim11_div_trigger.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/tima_reload.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/tima_reload.gb test -m 100000000 -s meowgb-tests/expected_output/tima_reload.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/tima_write_reloading.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/tima_write_reloading.gb test -m 100000000 -s meowgb-tests/expected_output/tima_write_reloading.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/tma_write_reloading.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/tma_write_reloading.gb test -m 100000000 -s meowgb-tests/expected_output/tma_write_reloading.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Running test ROM ./test-roms/mooneye-test-suite/roms/unused_hwio-GS.gb" + +TEST_TOTAL=$((TEST_TOTAL + 1)) + +if res=$(./target/release/meowgb-tests test-roms/mooneye-test-suite/roms/unused_hwio-GS.gb test -m 100000000 -s meowgb-tests/expected_output/unused_hwio-GS.bin 2>&1 > /dev/null) ; then + TEST_SUCCESS=$((TEST_SUCCESS + 1)) +else + echo "Failed: $res" +fi + +echo "Succeeded in running $TEST_SUCCESS/$TEST_TOTAL" diff --git a/test-roms/mooneye-test-suite/roms/div_timing.gb b/test-roms/mooneye-test-suite/roms/div_timing.gb new file mode 100644 index 0000000000000000000000000000000000000000..f72f194a73168e368436b7b076ec011c5f0c8ede GIT binary patch literal 32768 zcmeI4Uq~EB7{KS&tJ$crYfQpwx5?gd$i${%^2XAj8rA0Avf|QX>M6B2`JwwXx-5y@LfB%O| z*RK!t510RR`~JO4pI^VWSNm{eWO(4{z^~HJkLfR~9}3^}mUyJ!7A-Puu70v-YfgUL*Dy&-6;>E*+eP z!H=5DJ_m!PhaRUj^;-LjU2k}LB!C2v01`j~NB{{S0VIF~kN^@u0!RP}AOR$R1dsp{ zKmter2_OL^fCP{L5jpq8a09X|BuI$-z^}n3L&BhHb0g1K7M~Z&Kk^%;`Z%+ zzoL|s1cMOK*EctJ=+L%pJ9icrgI!TnDpgfAHC0v2pXG%yh$u=Dct{ePhfg;Zm-zY(P9+`(dtPU}Vf|!sexAp}$rB0a4Fmky z%>sW-16@&|8r*K~Z<^t7XXof>IBc3=hn1MH6Nf_m{asycZ6PXPH;icXz=8JmmKK&@ zQM{|d?w6g9WdQ%Rc0u6h@9gC3fnAcy%Di3{fBZP?l?hvqorT}$)D-AGDy+U>Uu|t& zUH$!he_&x%2=Sqi*Slp)K3~3G*!cnhcr74|zpk^l<95St;eKT*;%|Raw3WBD!v@|t=24tXqqtV`8&_URnX6F~EXqsVgfA(VF74Z6%Wl0JIBq}VL zkjBQ24%2LGbi3JU0s-LT^MM^|dlhHyeS^+lq$rM#!pVI;zrVh|t`7VmFB8TW<^~6Q zdVo5NL3ZzMXn;#+8rvbiADHXyjYbUvDpl7(Z)$>Sfj21RnAX)bG{CxGW2cv8*gMlD zDHwzu|Qs(&+!eVcykjXL=5;SUDhBk6^1XZj!wp}aE9{+$p^XxF3? zXDZ^Hy5=v-egzA9RI)|hN(T{el}qUeAX6b3D;L+oxYPxUe&LU6fBVe`**jKXWA>nxecj5=SRQgQ4KuHL^p(uA zV=kXp|D^qFu75n9xT2O97nQ%XP29ezX6tURENVt;r2F8|h@Snz3RI70hpnTuP0)6X zwm5B*w8@*tZP!uTHDSAs*{-ckY2D2yV?RhOXc6X>1e`RD*x`7cQ3!0{w5o-Zl<60 zH$ToJ0VIF~kN^@u0!RP}AOR$R1dsp{Kmter2_OL^fCP{L5=!q`rhC2T`lY8r3}>o^&QbT$n(l!ihG7&bKR#U{`S zn{>NP5JeAC4>?!})LU;xk5UvQ6tc8iJcuB+G8c;nl}Hh5mBimSuhWg5TPX7V!f$ro z@BRL~_xZiwl1p}D%HP3$P-oJOR^DTX4?QpFc)wIHKHP=0QL~GNk_c}kQ z_YV#fhWp*Z>&K62Z9(-3=g;LyfCNZ@1W14cNPq-LfCNZ@1W14cNPq-LfCNZ@1W14c zNPq-LfCNZ@1W14cNPq-LfCNZ@1W14cNPq-LfCNZ@1W14cNPq-LfCNZ@1W14cNPq-L zfCNZ@1fC88l`X=5v2QUewEurRaHd;jK9r`JCi=5VTm9%Mm!+ZKH23VuW*w)gDWAuT ziHXI<)2G|o_U&tIgx_&orS|r&uJ(2rFYDqRGEK|E2+NXwe5RDp4}W*J<9MFqba%so z5TNJbDR%NqX28zplivELj5iEf+jV^(KHJV@0;NpGwqcv5ZDVcIbR5|Ed=R8kw(Yu= z&H7L5Ado#UKAVlAa#_}|RD8c&HjKod&%?$JGQLvz_x@N9E%D2{=NU#l2U)qEZ(<9f z#zxzon6Pc(jhGRsL<>uN7y~Pp3q$0iX)+rbhT+oE;^O$Y>pG6Dl*vdG7+)%dAsU{^ z{CTA?%;ge4yotYD_We@HS1Om`uiL^K`_IoWEhY1jd8LA95MaEVEckmKY{x-0q*BTF zFpQ#+k(rq&3Pbp@lSnci7?_+K9W4|Fl;977V)59qp`pP+S>JKe4<+X-`N;|xztwLT zN&X`v$$s!#R!d7dE%Ps4M64p&PjX4lb728?MoH=maTN-qqmz?KeDFvWV*bEDI=y>$ zeZ6|UNPf8-ZVM#*eP8ZQDurlqzMFG*>}VFhW&QX5ViY9nCHGGH@XY58!}A6Q`}<*m z4C=R793O`b$(@$`4JFSDf@Hkh7~F!Ser?;bayd&$W@}ns-|%o4_VuMwl1(lLKA8;s zsO^V1H}5y>PM$@6dq*y}dYeu_VIee9$*O zUMvOyD%JO4_xGb(a0iV|rae8qz1SB%$=S?m>VDL~R$FSovgFReN1}qUXg^vQRj4}!mAOR8}0TLhq5+DH*AOR8} z0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq Q5+DH*AOR8}fky=X0gmAx)&Kwi literal 0 HcmV?d00001 diff --git a/test-roms/mooneye-test-suite/roms/rapid_toggle.gb b/test-roms/mooneye-test-suite/roms/rapid_toggle.gb new file mode 100644 index 0000000000000000000000000000000000000000..387bf0b0d44317478bdbc51621c239a914aee585 GIT binary patch literal 32768 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 literal 0 HcmV?d00001 diff --git a/test-roms/mooneye-test-suite/roms/tim01_div_trigger.gb b/test-roms/mooneye-test-suite/roms/tim01_div_trigger.gb new file mode 100644 index 0000000000000000000000000000000000000000..53092c971d92d2881d06e57bd154fc3c9e0a91f9 GIT binary patch literal 32768 zcmeI4Uq~EB7{K?|(`?ivYfQpwx5;`Oa-^WEpu>iSJ-qt$t(ynUPlktw`cL-n8|*d4`bWp4&Q6Jo@1V5rogbdg7x>u<+s6EH zmd^^ze6}gh{CwyaUtWF(nAXinUVit}1Jf&yf4TGQfW+q6G&{#;*adc;U1As66?WMy zWS1(YSJF#n5xWS3Cr>N9BMWb|yxP}CrzZkLfCvx)B0vO)01+SpM1Tko0U|&IhyW2F z0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+SpM1Tko0U|&IhyW2F z0z`la5CI}U1c(3;AOb{y2)r}|l4}J1ihYfmB>m;%0e8AqlvR-=MS=Mcm$i17NhGkr zyrS&h9SZ4sVPPZ!5j{P#v&W9@+O>CYK>^rx-QZGIR#{nAhW?lr#vqEKs^FojI1itG zE-(-Fsw!PKOl*9Fn=;>S&4)!3wtC2I;?>H$>jR=As;kh z$FXV3a_$V6Id@*6BcXxq(fEErr4xC4lFd9ziICFEevt3<= zq3ar#U=Vi!{_(iuK!aYyPjYdba9G&ED(s1bWyRwbmqY^WIURY!`jeA$b0Qv2o=ie- z+u)Bk3;azJbX|vP@cV_o<3yuvZ6hPmsN;YgRzkrOH#GG1wYN7nH*f*FZTI#bJ=)UJ z)P(tUJ+LZxzj!{(0RC(3vMkQu)+W{iyQ&r!2Lc#>`ZVkn1=qu~i2IzH0zJqD>kIbP z+}z&Y*C+M|7OX;uZ)gYvcI?RI%hd~>FC2!~0)qT43*V0454(l?&BkutT!eO2{r~#~ zFA&Tp-W|?CABo7aX*M<0*MkORpniLMyShLJ!8eWPm${gxZ3};VG4KjR{c4)3hQlfs zjFzOjy4F_5sjKt*@igHu@CgRN4z<0CGyA?l7cWv#Mn>S|!C)v8Rlj#r?osS66SZZ9}D67U=c$P%ZEVe^aZ7i@TXO@qCo zuBwp;>>#&3tW{ZAUXFIC!Q9Umn499#**P$fvqKH6)v*Rt72hoUWQA40U)NQ&hKs5q zf5A#r4BUS)7ex{KgQ(it)>in0Th9sTC6gBi7r2$pzP zZ%E!$%sY28RGj$^7OXI&9okMlh=HqC#76*`idbEezPyy<3U+zRQd6wJI{ zVXdT>J!ko{@el8>Wc%mi@$1Icg1oKyyOiBqDtGP=Xo_hciFI@j4qKUT+;Dk3GvuD+ zZJf7Lyd`*>;7!{eXTFonH_m*gm@mP66U=96%ca@kY2YvxHgZzwF4uHMcPD`r>k7C@-Kr6484g`eDcCVTSI)Z(Gkv-F|Ng!{+Bgd6{Mu{=;(r2W~!N8^Da?Jv)HaP95XkC~Wz zC-u_&l0pX|0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+SpM1Tko r0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-DuD1rX~V3t<5 literal 0 HcmV?d00001 diff --git a/test-roms/mooneye-test-suite/roms/tim10.gb b/test-roms/mooneye-test-suite/roms/tim10.gb new file mode 100644 index 0000000000000000000000000000000000000000..fcd5d987a96de4ebe21a8223045cf81cf4e8094e GIT binary patch literal 32768 zcmeI4T}T{P6o6;Pbu&?8#+ZcBPLp+6WMfS*M#y5flX0Aw)e%g?(^WR^Dup7TP>N{WdW0V2f0kH!7Wxili-)QnGt`Mk;>%U})*dlV7gg zxii=|RQ&6MCy%dPzjOP5@!9b3Q2)vPy@S2}vHsC9sk2k!;yEDgJv8@x-sfd2Y%BA| zSw8a_KDH^&yu9lLA0cjj2bf>Y5g-CYfCvx)B0vO)01+SpM1Tko0U|&IhyW2F0z`la5CI}U1c(3; zAOb{y2oM1xKm>>Y5g-CYfC#+y1d?k6{yTk*nk4=I$3y%Afp{ycB1wt@V<9fWhVM`) zk-!IZMcK706w>vAf=C1+dU|GOj~&~&bI%^15A3?`=TcTySy@(w{+Ji~Ac~@@;GwEG z4sS0P7zcY*m986xu2)ro1_BE-3}{got%v|U5)q@hH~Pym=Jxwd6Kt9m3|d@*K}`c) zQ8W#5D~hgz9*J0%*Q;rMe==MDLboiO1N=jwXf%<){K=$gCK9qN?2!oQFa!E0lk4Y) zeDDZ6_68r9%x1UBp2HbhlL%i!k$Q&W;||kNhH9Y(~&pKKRG!!C*on} z$t1Lv1^#%lz~3-H*LA1{uUGinb~M`7HZl^8+BVo>CKTLpLqlI*dwX+p0~fGcR&Vdo zqb)5>O_*QT1FM4Pi~GY2;J?-`%VPg+ZDKyKt7=hEAb|0wPs3VKa6a6NIM1mm(1TpC zzF=L=&F$@dePVrJ!77CKhK4|3`}SPET)p7_!eO{AAjsb|@$PuNuv$3ZZ0zREg=kmR z|K4Bl0>OOZ-r*Ruk%%lCMpILLJ!n7%>bJMIs|$1xywkXUnTugqmhi_L1GhlbucoPL zIIMEPXi2K8Yi+gdx;n2HcM}c+pI{K|P}{3Gv-cZxaU&IFWCV5|42D8AHPzMN4|!3L zFN_Tgban!D=!5LrS6d5*jvB5|oDYn3b@ldI7F4Qff?i(_)dF`=&N8j8uC0Z6!G^on zG*~<8sv3#F3Uc$qT$PpOttq}3hC<< zjJ#c8uB4Y;d-<~eZ{A+XwlDkRH~q!FyyEEnE-n{@@&eimz6#9+ zD9J_Sk-nQ^9%G8h^Y6h;^#7Gw+PYj2mhW%6UlT}GsFNj<>2WtL+;t|Fc0b!4IXnC? zn5vK_J(7QZ;YVkl$*#OKwRkY~B7HD3;rzZZ;l#gPEDw|xYJYU_-gux;`_r`_-8hu` zAro`%rC$3lC$s?~Km>>Y5g-CYfCvx)B0vO)01+SpM1Tko0U|&IhyW2F0z`la5CI}U u1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+SpM1Tko0V42*6ZjVvzDHsJ literal 0 HcmV?d00001 diff --git a/test-roms/mooneye-test-suite/roms/tim10_div_trigger.gb b/test-roms/mooneye-test-suite/roms/tim10_div_trigger.gb new file mode 100644 index 0000000000000000000000000000000000000000..1148f6f8cd1df926be2bc7ac20d86d06d38395b4 GIT binary patch literal 32768 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 OAM intr timing) -* mts/acceptance/ppu/intr_2_0_timing.gb (VBlank intr -> HBlank intr timing) (I think this shouldn't pass, i believe i'm triggering the HBlank IRQ one CPU cycle late) -* mts/acceptance/ppu/stat_lyc_onoff.gb (LY==LYC handling with PPU being enabled and disabled) -* mts/acceptance/ppu/stat_irq_blocking.gb (LCD status IRQ blocking) \ No newline at end of file +## Blargg's Test ROMs + +* cpu_instrs.gb - [ROM](./test-roms/blargg/roms/cpu_instrs.gb) - [Expected Serial Output](./meowgb-tests/expected_output/cpu_instrs.bin) +* instr_timing.gb - [ROM](./test-roms/blargg/roms/instr_timing.gb) - [Expected Serial Output](./meowgb-tests/expected_output/instr_timing.bin) +* mem_timing.gb - [ROM](./test-roms/blargg/roms/mem_timing.gb) - [Expected Serial Output](./meowgb-tests/expected_output/mem_timing.bin) + +## Mooneye Test Suite + +* basic.gb - [ROM](./test-roms/mooneye-test-suite/roms/basic.gb) - [Expected Serial Output](./meowgb-tests/expected_output/basic.bin) +* boot_hwio-dmgABCmgb.gb - [ROM](./test-roms/mooneye-test-suite/roms/boot_hwio-dmgABCmgb.gb) - [Expected Serial Output](./meowgb-tests/expected_output/boot_hwio-dmgABCmgb.bin) +* boot_regs-dmgABC.gb - [ROM](./test-roms/mooneye-test-suite/roms/boot_regs-dmgABC.gb) - [Expected Serial Output](./meowgb-tests/expected_output/boot_regs-dmgABC.bin) +* daa.gb - [ROM](./test-roms/mooneye-test-suite/roms/daa.gb) - [Expected Serial Output](./meowgb-tests/expected_output/daa.bin) +* div_timing.gb - [ROM](./test-roms/mooneye-test-suite/roms/div_timing.gb) - [Expected Serial Output](./meowgb-tests/expected_output/div_timing.bin) +* div_write.gb - [ROM](./test-roms/mooneye-test-suite/roms/div_write.gb) - [Expected Serial Output](./meowgb-tests/expected_output/div_write.bin) +* ei_sequence.gb - [ROM](./test-roms/mooneye-test-suite/roms/ei_sequence.gb) - [Expected Serial Output](./meowgb-tests/expected_output/ei_sequence.bin) +* ei_timing.gb - [ROM](./test-roms/mooneye-test-suite/roms/ei_timing.gb) - [Expected Serial Output](./meowgb-tests/expected_output/ei_timing.bin) +* halt_ime0_ei.gb - [ROM](./test-roms/mooneye-test-suite/roms/halt_ime0_ei.gb) - [Expected Serial Output](./meowgb-tests/expected_output/halt_ime0_ei.bin) +* intr_1_2_timing-GS.gb - [ROM](./test-roms/mooneye-test-suite/roms/intr_1_2_timing-GS.gb) - [Expected Serial Output](./meowgb-tests/expected_output/intr_1_2_timing-GS.bin) +* intr_2_0_timing.gb - [ROM](./test-roms/mooneye-test-suite/roms/intr_2_0_timing.gb) - [Expected Serial Output](./meowgb-tests/expected_output/intr_2_0_timing.bin) +* mem_oam.gb - [ROM](./test-roms/mooneye-test-suite/roms/mem_oam.gb) - [Expected Serial Output](./meowgb-tests/expected_output/mem_oam.bin) +* oam_dma_restart.gb - [ROM](./test-roms/mooneye-test-suite/roms/oam_dma_restart.gb) - [Expected Serial Output](./meowgb-tests/expected_output/oam_dma_restart.bin) +* oam_dma_start.gb - [ROM](./test-roms/mooneye-test-suite/roms/oam_dma_start.gb) - [Expected Serial Output](./meowgb-tests/expected_output/oam_dma_start.bin) +* oam_dma_timing.gb - [ROM](./test-roms/mooneye-test-suite/roms/oam_dma_timing.gb) - [Expected Serial Output](./meowgb-tests/expected_output/oam_dma_timing.bin) +* rapid_di_ei.gb - [ROM](./test-roms/mooneye-test-suite/roms/rapid_di_ei.gb) - [Expected Serial Output](./meowgb-tests/expected_output/rapid_di_ei.bin) +* rapid_toggle.gb - [ROM](./test-roms/mooneye-test-suite/roms/rapid_toggle.gb) - [Expected Serial Output](./meowgb-tests/expected_output/rapid_toggle.bin) +* reg_f.gb - [ROM](./test-roms/mooneye-test-suite/roms/reg_f.gb) - [Expected Serial Output](./meowgb-tests/expected_output/reg_f.bin) +* reg_read.gb - [ROM](./test-roms/mooneye-test-suite/roms/reg_read.gb) - [Expected Serial Output](./meowgb-tests/expected_output/reg_read.bin) +* stat_irq_blocking.gb - [ROM](./test-roms/mooneye-test-suite/roms/stat_irq_blocking.gb) - [Expected Serial Output](./meowgb-tests/expected_output/stat_irq_blocking.bin) +* stat_lyc_onoff.gb - [ROM](./test-roms/mooneye-test-suite/roms/stat_lyc_onoff.gb) - [Expected Serial Output](./meowgb-tests/expected_output/stat_lyc_onoff.bin) +* tim00.gb - [ROM](./test-roms/mooneye-test-suite/roms/tim00.gb) - [Expected Serial Output](./meowgb-tests/expected_output/tim00.bin) +* tim00_div_trigger.gb - [ROM](./test-roms/mooneye-test-suite/roms/tim00_div_trigger.gb) - [Expected Serial Output](./meowgb-tests/expected_output/tim00_div_trigger.bin) +* tim01.gb - [ROM](./test-roms/mooneye-test-suite/roms/tim01.gb) - [Expected Serial Output](./meowgb-tests/expected_output/tim01.bin) +* tim01_div_trigger.gb - [ROM](./test-roms/mooneye-test-suite/roms/tim01_div_trigger.gb) - [Expected Serial Output](./meowgb-tests/expected_output/tim01_div_trigger.bin) +* tim10.gb - [ROM](./test-roms/mooneye-test-suite/roms/tim10.gb) - [Expected Serial Output](./meowgb-tests/expected_output/tim10.bin) +* tim10_div_trigger.gb - [ROM](./test-roms/mooneye-test-suite/roms/tim10_div_trigger.gb) - [Expected Serial Output](./meowgb-tests/expected_output/tim10_div_trigger.bin) +* tim11.gb - [ROM](./test-roms/mooneye-test-suite/roms/tim11.gb) - [Expected Serial Output](./meowgb-tests/expected_output/tim11.bin) +* tim11_div_trigger.gb - [ROM](./test-roms/mooneye-test-suite/roms/tim11_div_trigger.gb) - [Expected Serial Output](./meowgb-tests/expected_output/tim11_div_trigger.bin) +* tima_reload.gb - [ROM](./test-roms/mooneye-test-suite/roms/tima_reload.gb) - [Expected Serial Output](./meowgb-tests/expected_output/tima_reload.bin) +* tima_write_reloading.gb - [ROM](./test-roms/mooneye-test-suite/roms/tima_write_reloading.gb) - [Expected Serial Output](./meowgb-tests/expected_output/tima_write_reloading.bin) +* tma_write_reloading.gb - [ROM](./test-roms/mooneye-test-suite/roms/tma_write_reloading.gb) - [Expected Serial Output](./meowgb-tests/expected_output/tma_write_reloading.bin) +* unused_hwio-GS.gb - [ROM](./test-roms/mooneye-test-suite/roms/unused_hwio-GS.gb) - [Expected Serial Output](./meowgb-tests/expected_output/unused_hwio-GS.bin)