feat: timer works much better

This commit is contained in:
EliseZeroTwo 2024-01-04 23:23:58 -07:00
parent 99eb507cf1
commit 8ae96ec880
Signed by: elise
GPG key ID: FA8F56FFFE6E8B3E
42 changed files with 1032 additions and 617 deletions

View file

@ -14,103 +14,150 @@ jobs:
- name: Run cargo tests (meowgb-core) - name: Run cargo tests (meowgb-core)
run: cargo test -p 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) - name: Run test ROM (blargg cpu_instrs)
if: always() 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) - name: Run test ROM (blargg instr_timing)
if: always() 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) - name: Run test ROM (blargg mem_timing)
if: always() 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) - name: Run test ROM (mooneye-test-suite basic)
if: always() 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) - name: Run test ROM (mooneye-test-suite boot_hwio-dmgABCmgb)
if: always() 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) - name: Run test ROM (mooneye-test-suite boot_regs-dmgABC)
if: always() 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) - name: Run test ROM (mooneye-test-suite daa)
if: always() 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) - name: Run test ROM (mooneye-test-suite ei_sequence)
if: always() 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) - name: Run test ROM (mooneye-test-suite ei_timing)
if: always() 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) - name: Run test ROM (mooneye-test-suite halt_ime0_ei)
if: always() 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) - name: Run test ROM (mooneye-test-suite intr_1_2_timing-GS)
if: always() 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) - name: Run test ROM (mooneye-test-suite intr_2_0_timing)
if: always() 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) - name: Run test ROM (mooneye-test-suite mem_oam)
if: always() 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) - name: Run test ROM (mooneye-test-suite oam_dma_restart)
if: always() 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) - name: Run test ROM (mooneye-test-suite oam_dma_start)
if: always() 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) - name: Run test ROM (mooneye-test-suite oam_dma_timing)
if: always() 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) - name: Run test ROM (mooneye-test-suite rapid_di_ei)
if: always() 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) - name: Run test ROM (mooneye-test-suite reg_f)
if: always() 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) - name: Run test ROM (mooneye-test-suite reg_read)
if: always() 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) - name: Run test ROM (mooneye-test-suite stat_irq_blocking)
if: always() 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) - name: Run test ROM (mooneye-test-suite stat_lyc_onoff)
if: always() 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) - name: Run test ROM (mooneye-test-suite tim00_div_trigger)
if: always() 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) - name: Run test ROM (mooneye-test-suite tim01)
if: always() 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) - name: Run test ROM (mooneye-test-suite tim11_div_trigger)
if: always() 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) - name: Run test ROM (mooneye-test-suite unused_hwio-GS)
if: always() 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

View file

@ -14,103 +14,150 @@ jobs:
- name: Run cargo tests (meowgb-core) - name: Run cargo tests (meowgb-core)
run: cargo test -p 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) - name: Run test ROM (blargg cpu_instrs)
if: always() 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) - name: Run test ROM (blargg instr_timing)
if: always() 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) - name: Run test ROM (blargg mem_timing)
if: always() 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) - name: Run test ROM (mooneye-test-suite basic)
if: always() 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) - name: Run test ROM (mooneye-test-suite boot_hwio-dmgABCmgb)
if: always() 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) - name: Run test ROM (mooneye-test-suite boot_regs-dmgABC)
if: always() 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) - name: Run test ROM (mooneye-test-suite daa)
if: always() 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) - name: Run test ROM (mooneye-test-suite ei_sequence)
if: always() 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) - name: Run test ROM (mooneye-test-suite ei_timing)
if: always() 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) - name: Run test ROM (mooneye-test-suite halt_ime0_ei)
if: always() 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) - name: Run test ROM (mooneye-test-suite intr_1_2_timing-GS)
if: always() 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) - name: Run test ROM (mooneye-test-suite intr_2_0_timing)
if: always() 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) - name: Run test ROM (mooneye-test-suite mem_oam)
if: always() 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) - name: Run test ROM (mooneye-test-suite oam_dma_restart)
if: always() 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) - name: Run test ROM (mooneye-test-suite oam_dma_start)
if: always() 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) - name: Run test ROM (mooneye-test-suite oam_dma_timing)
if: always() 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) - name: Run test ROM (mooneye-test-suite rapid_di_ei)
if: always() 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) - name: Run test ROM (mooneye-test-suite reg_f)
if: always() 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) - name: Run test ROM (mooneye-test-suite reg_read)
if: always() 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) - name: Run test ROM (mooneye-test-suite stat_irq_blocking)
if: always() 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) - name: Run test ROM (mooneye-test-suite stat_lyc_onoff)
if: always() 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) - name: Run test ROM (mooneye-test-suite tim00_div_trigger)
if: always() 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) - name: Run test ROM (mooneye-test-suite tim01)
if: always() 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) - name: Run test ROM (mooneye-test-suite tim11_div_trigger)
if: always() 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) - name: Run test ROM (mooneye-test-suite unused_hwio-GS)
if: always() 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

122
generate-action-and-tests.sh Executable file
View file

@ -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

View file

@ -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

View file

@ -10,8 +10,6 @@ pub mod serial;
pub mod sound; pub mod sound;
pub mod timer; pub mod timer;
use std::time::{Duration, Instant};
use interrupts::Interrupts; use interrupts::Interrupts;
use joypad::Joypad; use joypad::Joypad;
use mapper::Mapper; use mapper::Mapper;
@ -21,82 +19,12 @@ use timer::Timer;
use self::{ use self::{
cpu::Registers, cpu::Registers,
dma::DmaState,
mapper::{mbc1::MBC1, NoMBC}, mapper::{mbc1::MBC1, NoMBC},
serial::{Serial, SerialWriter}, serial::{Serial, SerialWriter},
sound::Sound, dma::DmaState, sound::Sound,
}; };
pub struct RingBuffer<T: std::fmt::Debug + Copy + Default, const SIZE: usize> {
buffer: [T; SIZE],
size: usize,
write_ptr: usize,
read_ptr: usize,
}
impl<T: std::fmt::Debug + Copy + Default, const SIZE: usize> RingBuffer<T, SIZE> {
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<T> {
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<u8, 16> = 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<S: SerialWriter> { pub struct Gameboy<S: SerialWriter> {
pub ppu: Ppu, pub ppu: Ppu,
pub memory: Memory, pub memory: Memory,
@ -109,19 +37,11 @@ pub struct Gameboy<S: SerialWriter> {
pub dma: DmaState, pub dma: DmaState,
pub sound: Sound, 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: bool,
pub halt_bug: bool, pub halt_bug: bool,
pub used_halt_bug: bool, pub used_halt_bug: bool,
pub stop: bool, pub stop: bool,
pub pc_history: RingBuffer<u16, 0x200>,
pub tick_count: u8, pub tick_count: u8,
} }
@ -141,41 +61,14 @@ impl<S: SerialWriter> Gameboy<S> {
false => Registers::post_rom(), false => Registers::post_rom(),
}, },
sound: Sound::new(), 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: false,
halt_bug: false, halt_bug: false,
used_halt_bug: false, used_halt_bug: false,
stop: false, stop: false,
pc_history: RingBuffer::new(),
tick_count: 0, 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<u8>) { pub fn load_cartridge(&mut self, bytes: Vec<u8>) {
if bytes.len() < 0x150 { if bytes.len() < 0x150 {
panic!("Bad cartridge (len < 0x150)"); panic!("Bad cartridge (len < 0x150)");
@ -189,215 +82,31 @@ impl<S: SerialWriter> Gameboy<S> {
} }
} }
fn log_state(&self) { pub fn tick_4(&mut self) -> bool {
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<Duration>) {
let mut request_redraw = false; let mut request_redraw = false;
let mut debug_time = None;
for _ in 0..4 { for _ in 0..4 {
let (t_request_redraw, t_debug_time) = self.tick(); let t_request_redraw = self.tick();
request_redraw |= t_request_redraw; request_redraw |= t_request_redraw;
if t_debug_time.is_some() {
assert!(debug_time.is_none());
debug_time = t_debug_time;
}
} }
request_redraw
(request_redraw, debug_time)
} }
pub fn tick(&mut self) -> (bool, Option<Duration>) { pub fn tick(&mut self) -> bool {
if self.tick_count == 0 { 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); cpu::tick_cpu(self);
let redraw_requested = self.ppu.tick(&mut self.interrupts); let redraw_requested = self.ppu.tick(&mut self.interrupts);
self.dma.tick_dma(&mut self.ppu, &self.memory, self.cartridge.as_deref()); self.dma.tick_dma(&mut self.ppu, &self.memory, self.cartridge.as_deref());
if self.serial.tick() { self.serial.tick(&mut self.interrupts);
self.interrupts.write_if_serial(true); self.timer.tick(&mut self.interrupts);
}
self.tick_count += 1; self.tick_count += 1;
(redraw_requested, diff) redraw_requested
} else { } else {
let redraw_requested = self.ppu.tick(&mut self.interrupts); let redraw_requested = self.ppu.tick(&mut self.interrupts);
self.timer.tick(&mut self.interrupts);
self.tick_count += 1; self.tick_count += 1;
self.tick_count %= 4; self.tick_count %= 4;
(redraw_requested, None) redraw_requested
} }
} }
@ -407,9 +116,9 @@ impl<S: SerialWriter> Gameboy<S> {
0xFF01 => self.serial.sb, 0xFF01 => self.serial.sb,
0xFF02 => self.serial.get_sc(), 0xFF02 => self.serial.get_sc(),
0xFF03 => 0xFF, // Unused 0xFF03 => 0xFF, // Unused
0xFF04 => self.timer.div, 0xFF04 => self.timer.read_div(),
0xFF05 => self.timer.tima, 0xFF05 => self.timer.read_tima(),
0xFF06 => self.timer.tma, 0xFF06 => self.timer.read_tma(),
0xFF07 => self.timer.read_tac(), 0xFF07 => self.timer.read_tac(),
0xFF08..=0xFF0E => 0xFF, // Unused 0xFF08..=0xFF0E => 0xFF, // Unused
0xFF0F => self.interrupts.interrupt_flag, 0xFF0F => self.interrupts.interrupt_flag,
@ -469,9 +178,9 @@ impl<S: SerialWriter> Gameboy<S> {
0xFF01 => self.serial.sb = value, 0xFF01 => self.serial.sb = value,
0xFF02 => self.serial.set_sc(value), 0xFF02 => self.serial.set_sc(value),
0xFF03 => {} // Unused 0xFF03 => {} // Unused
0xFF04 => self.timer.div = 0, 0xFF04 => self.timer.write_div(),
0xFF05 => self.timer.tima = value, 0xFF05 => self.timer.write_tima(value),
0xFF06 => self.timer.tma = value, 0xFF06 => self.timer.write_tma(value),
0xFF07 => self.timer.write_tac(value), 0xFF07 => self.timer.write_tac(value),
0xFF08..=0xFF0E => {} // Unused 0xFF08..=0xFF0E => {} // Unused
0xFF0F => self.interrupts.interrupt_flag = value | !0b1_1111, 0xFF0F => self.interrupts.interrupt_flag = value | !0b1_1111,
@ -485,19 +194,19 @@ impl<S: SerialWriter> Gameboy<S> {
0xFF17 => self.sound.nr22 = value, 0xFF17 => self.sound.nr22 = value,
0xFF18 => self.sound.nr23 = value, 0xFF18 => self.sound.nr23 = value,
0xFF19 => self.sound.nr24 = 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, 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, 0xFF1D => self.sound.nr33 = value,
0xFF1E => self.sound.nr34 = value, 0xFF1E => self.sound.nr34 = value,
0xFF1F => {} 0xFF1F => {}
0xFF20 => {}, //self.sound.nr41 = value, - Unwritable on DMG 0xFF20 => {} //self.sound.nr41 = value, - Unwritable on DMG
0xFF21 => self.sound.nr42 = value, 0xFF21 => self.sound.nr42 = value,
0xFF22 => self.sound.nr43 = 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, 0xFF24 => self.sound.nr50 = value,
0xFF25 => self.sound.nr51 = value, 0xFF25 => self.sound.nr51 = value,
0xFF26 => {}, //self.sound.nr52 = value, - Unwritable on DMG 0xFF26 => {} //self.sound.nr52 = value, - Unwritable on DMG
0xFF27..=0xFF2F => {} 0xFF27..=0xFF2F => {}
0xFF30..=0xFF3F => self.sound.wave_pattern_ram[address as usize - 0xFF30] = value, 0xFF30..=0xFF3F => self.sound.wave_pattern_ram[address as usize - 0xFF30] = value,
0xFF40 => { 0xFF40 => {
@ -555,12 +264,12 @@ impl<S: SerialWriter> Gameboy<S> {
0..=0xFF if !self.memory.bootrom_disabled => self.memory.bootrom[address as usize], 0..=0xFF if !self.memory.bootrom_disabled => self.memory.bootrom[address as usize],
0..=0x7FFF => match self.cartridge.as_ref() { 0..=0x7FFF => match self.cartridge.as_ref() {
Some(mapper) => mapper.read_rom_u8(address), Some(mapper) => mapper.read_rom_u8(address),
None => 0, None => 0xFF,
}, },
0x8000..=0x9FFF => self.ppu.cpu_read_vram(address), 0x8000..=0x9FFF => self.ppu.cpu_read_vram(address),
0xA000..=0xBFFF => match self.cartridge.as_ref() { 0xA000..=0xBFFF => match self.cartridge.as_ref() {
Some(mapper) => mapper.read_eram_u8(address), Some(mapper) => mapper.read_eram_u8(address - 0xA000),
None => 0, None => 0xFF,
}, },
0xC000..=0xDFFF => self.memory.wram[address as usize - 0xC000], 0xC000..=0xDFFF => self.memory.wram[address as usize - 0xC000],
0xE000..=0xFDFF => self.memory.wram[address as usize - 0xE000], 0xE000..=0xFDFF => self.memory.wram[address as usize - 0xE000],
@ -586,7 +295,7 @@ impl<S: SerialWriter> Gameboy<S> {
0x8000..=0x9FFF => self.ppu.cpu_write_vram(address, value), 0x8000..=0x9FFF => self.ppu.cpu_write_vram(address, value),
0xA000..=0xBFFF => { 0xA000..=0xBFFF => {
if let Some(mapper) = self.cartridge.as_mut() { 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, 0xC000..=0xDFFF => self.memory.wram[address as usize - 0xC000] = value,
@ -599,18 +308,27 @@ impl<S: SerialWriter> Gameboy<S> {
} }
} }
fn internal_cpu_read_u8(&self, address: u16) -> u8 { pub fn cpu_read_u8(&mut self, address: u16) {
if !self.ppu.dma_occuring { assert!(!self.registers.mem_op_happened);
match address { 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..=0xFF if !self.memory.bootrom_disabled => self.memory.bootrom[address as usize],
0..=0x7FFF => match self.cartridge.as_ref() { 0..=0x7FFF => match self.cartridge.as_ref() {
Some(mapper) => mapper.read_rom_u8(address), Some(mapper) => mapper.read_rom_u8(address),
None => 0, None => 0xFF,
}, },
0x8000..=0x9FFF => self.ppu.cpu_read_vram(address), 0x8000..=0x9FFF => self.ppu.cpu_read_vram(address),
0xA000..=0xBFFF => match self.cartridge.as_ref() { 0xA000..=0xBFFF => match self.cartridge.as_ref() {
Some(mapper) => mapper.read_eram_u8(address), Some(mapper) => mapper.read_eram_u8(address - 0xA000),
None => 0, None => 0xFF,
}, },
0xC000..=0xDFFF => self.memory.wram[address as usize - 0xC000], 0xC000..=0xDFFF => self.memory.wram[address as usize - 0xC000],
0xE000..=0xFDFF => self.memory.wram[address as usize - 0xE000], 0xE000..=0xFDFF => self.memory.wram[address as usize - 0xE000],
@ -619,41 +337,23 @@ impl<S: SerialWriter> Gameboy<S> {
0xFF00..=0xFF7F => self.cpu_read_io(address), 0xFF00..=0xFF7F => self.cpu_read_io(address),
0xFF80..=0xFFFE => self.memory.hram[address as usize - 0xFF80], 0xFF80..=0xFFFE => self.memory.hram[address as usize - 0xFF80],
0xFFFF => self.interrupts.interrupt_enable, 0xFFFF => self.interrupts.interrupt_enable,
} },
} else { };
match address { self.registers.mem_read_hold = Some(value);
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));
} }
pub fn cpu_write_u8(&mut self, address: u16, value: u8) { pub fn cpu_write_u8(&mut self, address: u16, value: u8) {
assert!(!self.registers.mem_op_happened); assert!(!self.registers.mem_op_happened);
self.registers.mem_op_happened = true; self.registers.mem_op_happened = true;
if self.mem_write_breakpoints[address as usize] { match self.ppu.dma_occuring {
self.trigger_bp = true; true => match address {
log::info!("Triggered write bp @ {:#X} (value: {:#02X})", address, value); 0..=0xFEFF => {}
} 0xFF00..=0xFF7F => self.cpu_write_io(address, value),
0xFF80..=0xFFFE => self.memory.hram[address as usize - 0xFF80] = value,
if !self.ppu.dma_occuring { 0xFFFF => self.interrupts.cpu_set_interrupt_enable(value),
match address { },
false => match address {
0..=0xFF if !self.memory.bootrom_disabled => {} 0..=0xFF if !self.memory.bootrom_disabled => {}
0..=0x7FFF => { 0..=0x7FFF => {
if let Some(mapper) = self.cartridge.as_mut() { if let Some(mapper) = self.cartridge.as_mut() {
@ -663,7 +363,7 @@ impl<S: SerialWriter> Gameboy<S> {
0x8000..=0x9FFF => self.ppu.cpu_write_vram(address, value), 0x8000..=0x9FFF => self.ppu.cpu_write_vram(address, value),
0xA000..=0xBFFF => { 0xA000..=0xBFFF => {
if let Some(mapper) = self.cartridge.as_mut() { 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, 0xC000..=0xDFFF => self.memory.wram[address as usize - 0xC000] = value,
@ -673,14 +373,7 @@ impl<S: SerialWriter> Gameboy<S> {
0xFF00..=0xFF7F => self.cpu_write_io(address, value), 0xFF00..=0xFF7F => self.cpu_write_io(address, value),
0xFF80..=0xFFFE => self.memory.hram[address as usize - 0xFF80] = value, 0xFF80..=0xFFFE => self.memory.hram[address as usize - 0xFF80] = value,
0xFFFF => self.interrupts.cpu_set_interrupt_enable(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),
}
} }
} }

View file

@ -238,19 +238,16 @@ pub fn tick_cpu(state: &mut Gameboy<impl SerialWriter>) {
} else { } else {
let opcode = match state.registers.current_opcode { let opcode = match state.registers.current_opcode {
Some(opcode) => opcode, Some(opcode) => opcode,
None => { None => match state.registers.mem_read_hold.take() {
state.pc_history.push(state.registers.pc); Some(opcode) => {
match state.registers.mem_read_hold.take() { state.registers.current_opcode = Some(opcode);
Some(opcode) => { opcode
state.registers.current_opcode = Some(opcode);
opcode
}
None => {
state.cpu_read_u8(state.registers.pc);
return;
}
} }
} None => {
state.cpu_read_u8(state.registers.pc);
return;
}
},
}; };
let result: CycleResult = match opcode { let result: CycleResult = match opcode {

View file

@ -56,12 +56,12 @@ opcode!(stop, 0x10, "STOP", false, 1, {
true => { true => {
state.registers.pc = state.registers.pc.wrapping_add(1); state.registers.pc = state.registers.pc.wrapping_add(1);
state.stop = true; state.stop = true;
state.timer.div = 0; state.timer.write_div();
}, },
false => { false => {
state.registers.pc = state.registers.pc.wrapping_add(2); state.registers.pc = state.registers.pc.wrapping_add(2);
state.stop = true; state.stop = true;
state.timer.div = 0; state.timer.write_div();
} }
}, },
} }

View file

@ -1,11 +1,11 @@
use super::{ppu::Ppu, memory::Memory, mapper::Mapper}; use super::{mapper::Mapper, memory::Memory, ppu::Ppu};
#[derive(Debug)] #[derive(Debug)]
pub struct DmaState { pub struct DmaState {
original_base: u8, original_base: u8,
pub base: u8, pub base: u8,
pub remaining_cycles: u8, pub remaining_cycles: u8,
restarting: Option<(u8, bool)>, restarting: Option<(u8, bool)>,
} }
impl DmaState { impl DmaState {
@ -14,22 +14,27 @@ impl DmaState {
} }
pub fn init_request(&mut self, base: u8) { pub fn init_request(&mut self, base: u8) {
self.base = base; self.base = base;
self.restarting = Some((base, false)); self.restarting = Some((base, false));
} }
pub fn tick_dma(&mut self, ppu: &mut Ppu, memory: &Memory, cartridge: Option<&(dyn Mapper + Send + Sync)>) { pub fn tick_dma(
match self.restarting { &mut self,
Some((base, false)) => self.restarting = Some((base, true)), ppu: &mut Ppu,
Some((base, true)) => { memory: &Memory,
self.original_base = base; cartridge: Option<&(dyn Mapper + Send + Sync)>,
self.remaining_cycles = 0xA0; ) {
self.restarting = None; match self.restarting {
} Some((base, false)) => self.restarting = Some((base, true)),
None => {}, 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 { if self.remaining_cycles > 0 {
let offset = 0xA0 - self.remaining_cycles; let offset = 0xA0 - self.remaining_cycles;
@ -55,7 +60,5 @@ impl DmaState {
ppu.dma_write_oam(offset, value); ppu.dma_write_oam(offset, value);
self.remaining_cycles -= 1; self.remaining_cycles -= 1;
} }
} }
}
}

View file

@ -57,23 +57,23 @@ impl Joypad {
} }
pub fn cpu_read(&self) -> u8 { pub fn cpu_read(&self) -> u8 {
(0b11 << 6) | match self.mode { (0b11 << 6)
JoypadMode::Action => { | match self.mode {
(1 << 4) JoypadMode::Action => {
| ((!self.start as u8) << 3) (1 << 4)
| ((!self.select as u8) << 2) | ((!self.start as u8) << 3)
| ((!self.b as u8) << 1) | ((!self.select as u8) << 2)
| (!self.a as u8) | ((!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); joypad_input!(a, Action);

View file

@ -4,7 +4,9 @@ pub trait Mapper {
fn read_rom_u8(&self, address: u16) -> u8; fn read_rom_u8(&self, address: u16) -> u8;
fn write_rom_u8(&mut self, address: u16, value: 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; 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); fn write_eram_u8(&mut self, address: u16, value: u8);
} }

View file

@ -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() { match self.ram.as_ref() {
Some(_ram) => 0, Some(ram) => match self.is_large_rom() {
None => 0, 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) { fn write_eram_u8(&mut self, address: u16, value: u8) {
match self.ram.as_ref() { let is_large_rom = self.is_large_rom();
Some(_ram) => {} 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 => {} None => {}
} }
} }

View file

@ -1,5 +1,7 @@
use std::io::Write; use std::io::Write;
use super::interrupts::Interrupts;
pub trait SerialWriter { pub trait SerialWriter {
fn write_byte(&mut self, byte: u8); fn write_byte(&mut self, byte: u8);
} }
@ -53,7 +55,7 @@ impl<S: SerialWriter> Serial<S> {
self.sc |= conductor as u8; 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.get_transfer_in_process() && self.is_conductor() {
if self.internal_tick < 128 { if self.internal_tick < 128 {
self.internal_tick += 1; self.internal_tick += 1;
@ -62,9 +64,8 @@ impl<S: SerialWriter> Serial<S> {
self.sb = 0; self.sb = 0;
self.set_transfer_in_process(false); self.set_transfer_in_process(false);
self.internal_tick = 0; self.internal_tick = 0;
return true; interrupts.write_if_serial(true);
} }
} }
false
} }
} }

View file

@ -53,7 +53,7 @@ impl Sound {
nr50: 0b0111_0111, nr50: 0b0111_0111,
nr51: 0b1111_0011, nr51: 0b1111_0011,
nr52: 0b1111_0001, nr52: 0b1111_0001,
wave_pattern_ram: [0u8;16], wave_pattern_ram: [0u8; 16],
} }
} }
} }

View file

@ -1,13 +1,14 @@
use super::interrupts::Interrupts;
#[derive(Debug)] #[derive(Debug)]
pub struct Timer { pub struct Timer {
pub enable: bool, enable: bool,
pub clock: TimerClock, clock: TimerClock,
pub div: u8, div: u16,
pub div_counter: u8, tima: u8,
pub tima: u8, tma: u8,
pub tima_counter: u16, overflow_begin_div: u16,
pub tma: u8, overflow: u8,
overflow: bool,
} }
impl Timer { impl Timer {
@ -17,36 +18,83 @@ impl Timer {
clock: TimerClock::C1024, clock: TimerClock::C1024,
tima: 0, tima: 0,
tma: 0, tma: 0,
div: 0xAD, div: 0xAC << 8,
div_counter: 0, overflow_begin_div: 0,
tima_counter: 0, overflow: 0u8,
overflow: false,
} }
} }
pub fn tick(&mut self) -> bool { pub fn tick(&mut self, interrupts: &mut Interrupts) {
self.div_counter = self.div_counter.wrapping_add(1); self.overflow %= 4;
if self.div_counter == 0 { let old_div = self.div;
self.div = self.div.wrapping_add(1); self.div = self.div.wrapping_add(1);
}
if self.enable { if self.enable {
self.tima_counter = self.tima_counter.wrapping_add(4); if self.div & self.clock.div_falling_edge_bit() == 0
if self.tima_counter >= self.clock.cycles() { && old_div & self.clock.div_falling_edge_bit() != 0
self.tima_counter = 0; {
self.tima = self.tima.wrapping_add(1); self.increment_tima();
return;
self.overflow = self.tima == 0;
return false;
} }
} }
if self.overflow { match self.overflow {
self.tima = self.tma; 0 => {}
self.overflow = false; 1..=2 => {
return true; 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 { pub fn read_tac(&self) -> u8 {
@ -54,28 +102,38 @@ impl Timer {
} }
pub fn write_tac(&mut self, value: u8) { pub fn write_tac(&mut self, value: u8) {
self.enable = (value >> 2) & 0b1 == 1; let new_enable = (value >> 2) & 0b1 == 1;
self.tima_counter = 0;
let new_clock = TimerClock::from_tac_clock(value); 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; self.clock = new_clock;
} }
} }
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TimerClock { pub enum TimerClock {
C16, C16 = 1,
C64, C64 = 2,
C256, C256 = 3,
C1024, C1024 = 0,
} }
impl TimerClock { impl TimerClock {
pub fn cycles(&self) -> u16 { pub const fn cycles(self) -> u16 {
match self { match self {
Self::C16 => 16, Self::C16 => 16,
Self::C64 => 64, Self::C64 => 64,
@ -84,7 +142,7 @@ impl TimerClock {
} }
} }
pub fn tac_clock(&self) -> u8 { pub const fn tac_clock(self) -> u8 {
match self { match self {
Self::C16 => 1, Self::C16 => 1,
Self::C64 => 2, 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 { match value & 0b11 {
1 => Self::C16, 1 => Self::C16,
2 => Self::C64, 2 => Self::C64,
@ -102,4 +160,8 @@ impl TimerClock {
_ => unreachable!(), _ => unreachable!(),
} }
} }
pub const fn div_falling_edge_bit(self) -> u16 {
self.cycles() / 2
}
} }

View file

@ -1,5 +1,9 @@
pub mod gameboy; 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<const ROM_LENGTH: usize>( pub fn setup_test_emulator<const ROM_LENGTH: usize>(
test_opcodes: [u8; ROM_LENGTH], test_opcodes: [u8; ROM_LENGTH],
) -> gameboy::Gameboy<std::io::Stdout> { ) -> gameboy::Gameboy<std::io::Stdout> {

View file

@ -0,0 +1,70 @@
pub struct RingBuffer<T: std::fmt::Debug + Copy + Default, const SIZE: usize> {
buffer: [T; SIZE],
size: usize,
write_ptr: usize,
read_ptr: usize,
}
impl<T: std::fmt::Debug + Copy + Default, const SIZE: usize> RingBuffer<T, SIZE> {
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<T> {
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<u8, 16> = 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]
);
}

View file

@ -67,17 +67,23 @@ pub fn opcode(item: TokenStream) -> TokenStream {
block.push(op_impl.block); block.push(op_impl.block);
} }
/*if !cycle.is_empty() { // let regs = quote::quote! {
if cycle[0].base10_parse::<u8>().expect("Expected u8") == 0u8 { // log::debug!("\nSTART OF {}\n-- Registers --\nAF: {:04X}\nBC: {:04X}\nDE:
block[0].stmts.insert(0, Stmt::Semi(Expr::Macro(ExprMacro::))) // {:04X}\nHL: {:04X}\nSP: {:04X}\nPC: {:04X}\nZero: {}\nSubtract:
} else { // {}\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(),
let regs = quote::quote! { // state.registers.pc, state.registers.get_zero(),
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); // 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! { let match_statement = quote::quote! {
match state.registers.cycle { match state.registers.cycle {
@ -88,26 +94,34 @@ pub fn opcode(item: TokenStream) -> TokenStream {
} }
}; };
let log = if extended.value { // let log = if extended.value {
quote::quote! { // quote::quote! {
if state.registers.cycle == 1 && state.log_instructions { // if state.registers.cycle == 1 && state.log_instructions {
log::debug!("(PC: {:#02X}) Prefixed OP {} ({:#02X})", state.registers.pc, #readable, #opcode); // log::debug!("(PC: {:#02X}) Prefixed OP {} ({:#02X})", state.registers.pc,
#regs // #readable, #opcode); #regs
} // }
} // }
} else { // } else {
quote::quote! { // quote::quote! {
if state.registers.cycle == 0 && state.log_instructions { // if state.registers.cycle == 0 && state.log_instructions {
log::debug!("(PC: {:#02X}) OP {} ({:#02X})", state.registers.pc, #readable, #opcode); // log::debug!("(PC: {:#02X}) OP {} ({:#02X})", state.registers.pc, #readable,
#regs // #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! { let out = quote::quote! {
#fn_sig { #fn_sig {
#log #check_opcode
let res: CycleResult = #match_statement; let res: CycleResult = #match_statement;
if res != CycleResult::NeedsMore { if res != CycleResult::NeedsMore {

View file

@ -0,0 +1 @@
 "

View file

@ -0,0 +1 @@
 "

View file

@ -0,0 +1 @@
 "

View file

@ -0,0 +1 @@
 "

View file

@ -0,0 +1 @@
 "

View file

@ -0,0 +1 @@
 "

View file

@ -0,0 +1 @@
 "

View file

@ -0,0 +1 @@
 "

View file

@ -0,0 +1 @@
 "

View file

@ -0,0 +1 @@
 "

View file

@ -0,0 +1 @@
 "

View file

@ -28,9 +28,6 @@ pub struct CliArgs {
/// game path /// game path
#[clap(long)] #[clap(long)]
pub rom: Option<PathBuf>, pub rom: Option<PathBuf>,
// enter in debu g mode
#[clap(short, long)]
pub debug: bool,
} }
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
@ -99,11 +96,6 @@ pub fn run_gameboy(
) -> Result<(), MeowGBError> { ) -> Result<(), MeowGBError> {
let mut gameboy = gameboy_arc.write().unwrap(); 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 let Some(rom) = args.rom {
if !rom.is_file() { if !rom.is_file() {
return Err(MeowGBError::GameNotFound); return Err(MeowGBError::GameNotFound);
@ -132,19 +124,15 @@ pub fn run_gameboy(
EmulatorWindowEvent::DownToggle => gameboy.joypad.invert_down(), EmulatorWindowEvent::DownToggle => gameboy.joypad.invert_down(),
EmulatorWindowEvent::LeftToggle => gameboy.joypad.invert_left(), EmulatorWindowEvent::LeftToggle => gameboy.joypad.invert_left(),
EmulatorWindowEvent::RightToggle => gameboy.joypad.invert_right(), EmulatorWindowEvent::RightToggle => gameboy.joypad.invert_right(),
EmulatorWindowEvent::PauseToggle => gameboy.single_step = !gameboy.single_step, EmulatorWindowEvent::PauseToggle => unimplemented!(),
EmulatorWindowEvent::Exit => break 'outer, EmulatorWindowEvent::Exit => break 'outer,
} }
} }
let (redraw_needed, time_spent_debugging) = gameboy.tick_4(); let redraw_needed = gameboy.tick_4();
drop(gameboy); drop(gameboy);
if let Some(diff) = time_spent_debugging {
goal = goal + diff;
}
if redraw_needed { if redraw_needed {
let now = time::OffsetDateTime::now_utc(); let now = time::OffsetDateTime::now_utc();
frame_counter += 1; frame_counter += 1;

370
run-test-roms.sh Executable file
View file

@ -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"

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,9 +1,43 @@
# Passing Tests # Passing Tests
* blargg/cpu_instrs.gb ## Blargg's Test ROMs
* blargg/instr_timing.gb
* blargg/mem_timing.gb * cpu_instrs.gb - [ROM](./test-roms/blargg/roms/cpu_instrs.gb) - [Expected Serial Output](./meowgb-tests/expected_output/cpu_instrs.bin)
* mts/acceptance/ppu/intr_1_2_timing-GS.gb (VBlank intr -> OAM intr timing) * instr_timing.gb - [ROM](./test-roms/blargg/roms/instr_timing.gb) - [Expected Serial Output](./meowgb-tests/expected_output/instr_timing.bin)
* 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) * mem_timing.gb - [ROM](./test-roms/blargg/roms/mem_timing.gb) - [Expected Serial Output](./meowgb-tests/expected_output/mem_timing.bin)
* 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) ## 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)