test: add much more tests, fix up a few broken things
This commit is contained in:
parent
d1586b5fce
commit
e4b8b67b79
56 changed files with 339 additions and 99 deletions
1
.forgejo/workflows/action.yml
Symbolic link
1
.forgejo/workflows/action.yml
Symbolic link
|
@ -0,0 +1 @@
|
|||
./.github/workflows/action.yml
|
98
.github/workflows/action.yml
vendored
98
.github/workflows/action.yml
vendored
|
@ -14,27 +14,103 @@ jobs:
|
|||
|
||||
- name: Run cargo tests (meowgb-core)
|
||||
run: cargo test -p meowgb-core
|
||||
|
||||
|
||||
- name: Run test ROM (blargg cpu_instrs)
|
||||
if: always()
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/blargg/roms/cpu_instrs.gb test -m 100000000 -s meowgb-tests/expected_output/cpu_instrs.bin
|
||||
|
||||
|
||||
- name: Run test ROM (blargg instr_timing)
|
||||
if: always()
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/blargg/roms/instr_timing.gb test -m 100000000 -s meowgb-tests/expected_output/instr_timing.bin
|
||||
|
||||
- name: Run test ROM (blargg mem_timing)
|
||||
if: always()
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/blargg/roms/mem_timing.gb test -m 100000000 -s meowgb-tests/expected_output/mem_timing.bin
|
||||
|
||||
- name: Run test ROM (mealybug-tearoom-tests intr_1_2_timing)
|
||||
- name: Run test ROM (mooneye-test-suite basic)
|
||||
if: always()
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/mealybug-tearoom-tests/roms/intr_1_2_timing-GS.gb test -m 100000000 -s meowgb-tests/expected_output/intr_1_2_timing-GS.bin
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/basic.gb test -m 100000000 -s meowgb-tests/expected_output/basic.bin
|
||||
|
||||
- name: Run test ROM (mealybug-tearoom-tests intr_2_0_timing)
|
||||
- name: Run test ROM (mooneye-test-suite boot_hwio-dmgABCmgb)
|
||||
if: always()
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/mealybug-tearoom-tests/roms/intr_2_0_timing.gb test -m 100000000 -s meowgb-tests/expected_output/intr_2_0_timing.bin
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/boot_hwio-dmgABCmgb.gb test -m 100000000 -s meowgb-tests/expected_output/boot_hwio-dmgABCmgb.bin
|
||||
|
||||
- name: Run test ROM (mealybug-tearoom-tests stat_lyc_onoff)
|
||||
- name: Run test ROM (mooneye-test-suite boot_regs-dmgABC)
|
||||
if: always()
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/mealybug-tearoom-tests/roms/stat_lyc_onoff.gb test -m 100000000 -s meowgb-tests/expected_output/stat_lyc_onoff.bin
|
||||
|
||||
- name: Run test ROM (mealybug-tearoom-tests stat_irq_blocking)
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/boot_regs-dmgABC.gb test -m 100000000 -s meowgb-tests/expected_output/boot_regs-dmgABC.bin
|
||||
|
||||
- name: Run test ROM (mooneye-test-suite daa)
|
||||
if: always()
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/mealybug-tearoom-tests/roms/stat_irq_blocking.gb test -m 100000000 -s meowgb-tests/expected_output/stat_irq_blocking.bin
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/daa.gb test -m 100000000 -s meowgb-tests/expected_output/daa.bin
|
||||
|
||||
- name: Run test ROM (mooneye-test-suite ei_sequence)
|
||||
if: always()
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/ei_sequence.gb test -m 100000000 -s meowgb-tests/expected_output/ei_sequence.bin
|
||||
|
||||
- name: Run test ROM (mooneye-test-suite ei_timing)
|
||||
if: always()
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/ei_timing.gb test -m 100000000 -s meowgb-tests/expected_output/ei_timing.bin
|
||||
|
||||
- name: Run test ROM (mooneye-test-suite halt_ime0_ei)
|
||||
if: always()
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/halt_ime0_ei.gb test -m 100000000 -s meowgb-tests/expected_output/halt_ime0_ei.bin
|
||||
|
||||
- name: Run test ROM (mooneye-test-suite intr_1_2_timing-GS)
|
||||
if: always()
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/intr_1_2_timing-GS.gb test -m 100000000 -s meowgb-tests/expected_output/intr_1_2_timing-GS.bin
|
||||
|
||||
- name: Run test ROM (mooneye-test-suite intr_2_0_timing)
|
||||
if: always()
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/intr_2_0_timing.gb test -m 100000000 -s meowgb-tests/expected_output/intr_2_0_timing.bin
|
||||
|
||||
- name: Run test ROM (mooneye-test-suite mem_oam)
|
||||
if: always()
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/mem_oam.gb test -m 100000000 -s meowgb-tests/expected_output/mem_oam.bin
|
||||
|
||||
- name: Run test ROM (mooneye-test-suite oam_dma_restart)
|
||||
if: always()
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/oam_dma_restart.gb test -m 100000000 -s meowgb-tests/expected_output/oam_dma_restart.bin
|
||||
|
||||
- name: Run test ROM (mooneye-test-suite oam_dma_start)
|
||||
if: always()
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/oam_dma_start.gb test -m 100000000 -s meowgb-tests/expected_output/oam_dma_start.bin
|
||||
|
||||
- name: Run test ROM (mooneye-test-suite oam_dma_timing)
|
||||
if: always()
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/oam_dma_timing.gb test -m 100000000 -s meowgb-tests/expected_output/oam_dma_timing.bin
|
||||
|
||||
- name: Run test ROM (mooneye-test-suite rapid_di_ei)
|
||||
if: always()
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/rapid_di_ei.gb test -m 100000000 -s meowgb-tests/expected_output/rapid_di_ei.bin
|
||||
|
||||
- name: Run test ROM (mooneye-test-suite reg_f)
|
||||
if: always()
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/reg_f.gb test -m 100000000 -s meowgb-tests/expected_output/reg_f.bin
|
||||
|
||||
- name: Run test ROM (mooneye-test-suite reg_read)
|
||||
if: always()
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/reg_read.gb test -m 100000000 -s meowgb-tests/expected_output/reg_read.bin
|
||||
|
||||
- name: Run test ROM (mooneye-test-suite stat_irq_blocking)
|
||||
if: always()
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/stat_irq_blocking.gb test -m 100000000 -s meowgb-tests/expected_output/stat_irq_blocking.bin
|
||||
|
||||
- name: Run test ROM (mooneye-test-suite stat_lyc_onoff)
|
||||
if: always()
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/stat_lyc_onoff.gb test -m 100000000 -s meowgb-tests/expected_output/stat_lyc_onoff.bin
|
||||
|
||||
- name: Run test ROM (mooneye-test-suite tim00_div_trigger)
|
||||
if: always()
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/tim00_div_trigger.gb test -m 100000000 -s meowgb-tests/expected_output/tim00_div_trigger.bin
|
||||
|
||||
- name: Run test ROM (mooneye-test-suite tim01)
|
||||
if: always()
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/tim01.gb test -m 100000000 -s meowgb-tests/expected_output/tim01.bin
|
||||
|
||||
- name: Run test ROM (mooneye-test-suite tim11_div_trigger)
|
||||
if: always()
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/tim11_div_trigger.gb test -m 100000000 -s meowgb-tests/expected_output/tim11_div_trigger.bin
|
||||
|
||||
- name: Run test ROM (mooneye-test-suite unused_hwio-GS)
|
||||
if: always()
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/unused_hwio-GS.gb test -m 100000000 -s meowgb-tests/expected_output/unused_hwio-GS.bin
|
||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -3,4 +3,5 @@
|
|||
/bmp/
|
||||
config.toml
|
||||
/.vscode/
|
||||
out
|
||||
out
|
||||
generate-output.sh
|
55
generate-action.sh
Executable file
55
generate-action.sh
Executable file
|
@ -0,0 +1,55 @@
|
|||
#!/bin/bash
|
||||
OUTPUT_FILE=./.github/workflows/action.yml
|
||||
|
||||
cat >$OUTPUT_FILE << EOF
|
||||
on:
|
||||
- push
|
||||
|
||||
jobs:
|
||||
main_test:
|
||||
name: Test changes to main
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install toolchain
|
||||
run: curl https://sh.rustup.rs -sSf | sh -s -- --profile minimal --default-toolchain stable -y && echo "\$HOME/.cargo/bin" >> \$GITHUB_PATH
|
||||
|
||||
- name: Run cargo tests (meowgb-core)
|
||||
run: cargo test -p meowgb-core
|
||||
EOF
|
||||
|
||||
|
||||
for f in ./test-roms/blargg/roms/*
|
||||
do
|
||||
f="${f##*/}"; f="${f%.*}";
|
||||
cat >>$OUTPUT_FILE << EOF
|
||||
|
||||
- name: Run test ROM (blargg $f)
|
||||
if: always()
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/blargg/roms/$f.gb test -m 100000000 -s meowgb-tests/expected_output/$f.bin
|
||||
EOF
|
||||
done
|
||||
|
||||
# for f in ./test-roms/mealybug-tearoom-tests/roms/*
|
||||
# do
|
||||
# f="${f##*/}"; f="${f%.*}";
|
||||
# cat >>$OUTPUT_FILE << EOF
|
||||
|
||||
# - name: Run test ROM (mealybug-tearoom-tests $f)
|
||||
# if: always()
|
||||
# run: cargo run -p meowgb-tests --release -- test-roms/mealybug-tearoom-tests/roms/$f.gb test -m 100000000 -s meowgb-tests/expected_output/$f.bin
|
||||
# EOF
|
||||
# done
|
||||
|
||||
for f in ./test-roms/mooneye-test-suite/roms/*
|
||||
do
|
||||
f="${f##*/}"; f="${f%.*}";
|
||||
cat >>$OUTPUT_FILE << EOF
|
||||
|
||||
- name: Run test ROM (mooneye-test-suite $f)
|
||||
if: always()
|
||||
run: cargo run -p meowgb-tests --release -- test-roms/mooneye-test-suite/roms/$f.gb test -m 100000000 -s meowgb-tests/expected_output/$f.bin
|
||||
EOF
|
||||
done
|
|
@ -1,5 +1,6 @@
|
|||
pub mod bootrom;
|
||||
pub mod cpu;
|
||||
pub mod dma;
|
||||
pub mod interrupts;
|
||||
pub mod joypad;
|
||||
pub mod mapper;
|
||||
|
@ -22,25 +23,9 @@ use self::{
|
|||
cpu::Registers,
|
||||
mapper::{mbc1::MBC1, NoMBC},
|
||||
serial::{Serial, SerialWriter},
|
||||
sound::Sound,
|
||||
sound::Sound, dma::DmaState,
|
||||
};
|
||||
|
||||
pub struct DmaState {
|
||||
pub base: u8,
|
||||
pub remaining_cycles: u8,
|
||||
}
|
||||
|
||||
impl DmaState {
|
||||
pub fn new() -> Self {
|
||||
Self { base: 0, remaining_cycles: 0 }
|
||||
}
|
||||
|
||||
pub fn init_request(&mut self, base: u8) {
|
||||
self.base = base;
|
||||
self.remaining_cycles = 0xA0;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RingBuffer<T: std::fmt::Debug + Copy + Default, const SIZE: usize> {
|
||||
buffer: [T; SIZE],
|
||||
size: usize,
|
||||
|
@ -155,7 +140,7 @@ impl<S: SerialWriter> Gameboy<S> {
|
|||
true => Registers::default(),
|
||||
false => Registers::post_rom(),
|
||||
},
|
||||
sound: Sound::default(),
|
||||
sound: Sound::new(),
|
||||
single_step: false,
|
||||
breakpoints: [false; u16::MAX as usize + 1],
|
||||
mem_read_breakpoints: [false; u16::MAX as usize + 1],
|
||||
|
@ -402,7 +387,7 @@ impl<S: SerialWriter> Gameboy<S> {
|
|||
|
||||
cpu::tick_cpu(self);
|
||||
let redraw_requested = self.ppu.tick(&mut self.interrupts);
|
||||
self.tick_dma();
|
||||
self.dma.tick_dma(&mut self.ppu, &self.memory, self.cartridge.as_deref());
|
||||
if self.serial.tick() {
|
||||
self.interrupts.write_if_serial(true);
|
||||
}
|
||||
|
@ -416,39 +401,11 @@ impl<S: SerialWriter> Gameboy<S> {
|
|||
}
|
||||
}
|
||||
|
||||
fn tick_dma(&mut self) {
|
||||
self.ppu.dma_occuring = self.dma.remaining_cycles > 0;
|
||||
if self.dma.remaining_cycles > 0 {
|
||||
let offset = 0xA0 - self.dma.remaining_cycles;
|
||||
|
||||
let value = if self.dma.base <= 0x7F {
|
||||
match self.cartridge.as_ref() {
|
||||
Some(cart) => cart.read_rom_u8((self.dma.base as u16) << 8 | offset as u16),
|
||||
None => 0xFF,
|
||||
}
|
||||
} else if self.dma.base <= 0x9F {
|
||||
let address = (((self.dma.base as usize) << 8) | offset as usize) - 0x8000;
|
||||
self.ppu.vram[address]
|
||||
} else if self.dma.base <= 0xDF {
|
||||
let address = ((self.dma.base as usize) << 8 | offset as usize) - 0xC000;
|
||||
self.memory.wram[address]
|
||||
} else if self.dma.base <= 0xFD {
|
||||
let address = ((self.dma.base as usize) << 8 | offset as usize) - 0xE000;
|
||||
self.memory.wram[address]
|
||||
} else {
|
||||
0xFF
|
||||
};
|
||||
|
||||
self.ppu.dma_write_oam(offset, value);
|
||||
self.dma.remaining_cycles -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn cpu_read_io(&self, address: u16) -> u8 {
|
||||
match address {
|
||||
0xFF00 => self.joypad.cpu_read(),
|
||||
0xFF01 => self.serial.sb,
|
||||
0xFF02 => self.serial.sc,
|
||||
0xFF02 => self.serial.get_sc(),
|
||||
0xFF03 => 0xFF, // Unused
|
||||
0xFF04 => self.timer.div,
|
||||
0xFF05 => self.timer.tima,
|
||||
|
@ -495,7 +452,7 @@ impl<S: SerialWriter> Gameboy<S> {
|
|||
0xFF4B => self.ppu.registers.wx,
|
||||
0xFF4C..=0xFF4E => 0xFF, // Unused
|
||||
0xFF4F => 0xFF, // CGB VRAM Bank Select
|
||||
0xFF50 => self.memory.bootrom_disabled as u8,
|
||||
0xFF50 => self.memory.get_bootrom_disabled(),
|
||||
0xFF51..=0xFF55 => 0xFF, // CGB VRAM DMA
|
||||
0xFF56..=0xFF67 => 0xFF, // Unused
|
||||
0xFF68..=0xFF69 => 0xFF, // BJ/OBJ Palettes
|
||||
|
@ -510,7 +467,7 @@ impl<S: SerialWriter> Gameboy<S> {
|
|||
match address {
|
||||
0xFF00 => self.joypad.cpu_write(value),
|
||||
0xFF01 => self.serial.sb = value,
|
||||
0xFF02 => self.serial.sc = value,
|
||||
0xFF02 => self.serial.set_sc(value),
|
||||
0xFF03 => {} // Unused
|
||||
0xFF04 => self.timer.div = 0,
|
||||
0xFF05 => self.timer.tima = value,
|
||||
|
@ -518,7 +475,7 @@ impl<S: SerialWriter> Gameboy<S> {
|
|||
0xFF07 => self.timer.write_tac(value),
|
||||
0xFF08..=0xFF0E => {} // Unused
|
||||
0xFF0F => self.interrupts.interrupt_flag = value | !0b1_1111,
|
||||
0xFF10 => self.sound.nr10 = value,
|
||||
0xFF10 => {} //self.sound.nr10 = value, - Unwritable on DMG
|
||||
0xFF11 => self.sound.nr11 = value,
|
||||
0xFF12 => self.sound.nr12 = value,
|
||||
0xFF13 => self.sound.nr13 = value,
|
||||
|
@ -528,19 +485,19 @@ impl<S: SerialWriter> Gameboy<S> {
|
|||
0xFF17 => self.sound.nr22 = value,
|
||||
0xFF18 => self.sound.nr23 = value,
|
||||
0xFF19 => self.sound.nr24 = value,
|
||||
0xFF1A => self.sound.nr30 = value,
|
||||
0xFF1A => {}, //self.sound.nr30 = value, - Unwritable on DMG
|
||||
0xFF1B => self.sound.nr31 = value,
|
||||
0xFF1C => self.sound.nr32 = value,
|
||||
0xFF1C => {}, //self.sound.nr32 = value, - Unwritable on DMG
|
||||
0xFF1D => self.sound.nr33 = value,
|
||||
0xFF1E => self.sound.nr34 = value,
|
||||
0xFF1F => {}
|
||||
0xFF20 => self.sound.nr41 = value,
|
||||
0xFF20 => {}, //self.sound.nr41 = value, - Unwritable on DMG
|
||||
0xFF21 => self.sound.nr42 = value,
|
||||
0xFF22 => self.sound.nr43 = value,
|
||||
0xFF23 => self.sound.nr44 = value,
|
||||
0xFF23 => {}, //self.sound.nr44 = value, - Unwritable on DMG
|
||||
0xFF24 => self.sound.nr50 = value,
|
||||
0xFF25 => self.sound.nr51 = value,
|
||||
0xFF26 => self.sound.nr52 = value,
|
||||
0xFF26 => {}, //self.sound.nr52 = value, - Unwritable on DMG
|
||||
0xFF27..=0xFF2F => {}
|
||||
0xFF30..=0xFF3F => self.sound.wave_pattern_ram[address as usize - 0xFF30] = value,
|
||||
0xFF40 => {
|
||||
|
@ -558,11 +515,7 @@ impl<S: SerialWriter> Gameboy<S> {
|
|||
0xFF43 => self.ppu.registers.scx = value,
|
||||
0xFF44 => {} // LY is read only
|
||||
0xFF45 => self.ppu.set_lyc(&mut self.interrupts, value),
|
||||
0xFF46 => {
|
||||
if self.dma.remaining_cycles == 0 {
|
||||
self.dma.init_request(value);
|
||||
}
|
||||
}
|
||||
0xFF46 => self.dma.init_request(value),
|
||||
0xFF47 => self.ppu.bgp.write_bgp(value),
|
||||
0xFF48 => self.ppu.obp[0].write_obp(value),
|
||||
0xFF49 => self.ppu.obp[1].write_obp(value),
|
||||
|
@ -642,12 +595,12 @@ impl<S: SerialWriter> Gameboy<S> {
|
|||
0xFEA0..=0xFEFF => {}
|
||||
0xFF00..=0xFF7F => self.cpu_write_io(address, value),
|
||||
0xFF80..=0xFFFE => self.memory.hram[address as usize - 0xFF80] = value,
|
||||
0xFFFF => self.interrupts.interrupt_enable = value & 0b1_1111,
|
||||
0xFFFF => self.interrupts.cpu_set_interrupt_enable(value),
|
||||
}
|
||||
}
|
||||
|
||||
fn internal_cpu_read_u8(&self, address: u16) -> u8 {
|
||||
if self.dma.remaining_cycles == 0 {
|
||||
if !self.ppu.dma_occuring {
|
||||
match address {
|
||||
0..=0xFF if !self.memory.bootrom_disabled => self.memory.bootrom[address as usize],
|
||||
0..=0x7FFF => match self.cartridge.as_ref() {
|
||||
|
@ -669,7 +622,7 @@ impl<S: SerialWriter> Gameboy<S> {
|
|||
}
|
||||
} else {
|
||||
match address {
|
||||
0..=0xFEFF => 0,
|
||||
0..=0xFEFF => 0xFF,
|
||||
0xFF00..=0xFF7F => self.cpu_read_io(address),
|
||||
0xFF80..=0xFFFE => self.memory.hram[address as usize - 0xFF80],
|
||||
0xFFFF => self.interrupts.interrupt_enable,
|
||||
|
@ -699,7 +652,7 @@ impl<S: SerialWriter> Gameboy<S> {
|
|||
log::info!("Triggered write bp @ {:#X} (value: {:#02X})", address, value);
|
||||
}
|
||||
|
||||
if self.dma.remaining_cycles == 0 {
|
||||
if !self.ppu.dma_occuring {
|
||||
match address {
|
||||
0..=0xFF if !self.memory.bootrom_disabled => {}
|
||||
0..=0x7FFF => {
|
||||
|
@ -719,14 +672,14 @@ impl<S: SerialWriter> Gameboy<S> {
|
|||
0xFEA0..=0xFEFF => {}
|
||||
0xFF00..=0xFF7F => self.cpu_write_io(address, value),
|
||||
0xFF80..=0xFFFE => self.memory.hram[address as usize - 0xFF80] = value,
|
||||
0xFFFF => self.interrupts.interrupt_enable = value & 0b1_1111,
|
||||
0xFFFF => self.interrupts.cpu_set_interrupt_enable(value),
|
||||
}
|
||||
} else {
|
||||
match address {
|
||||
0..=0xFEFF => {}
|
||||
0xFF00..=0xFF7F => self.cpu_write_io(address, value),
|
||||
0xFF80..=0xFFFE => self.memory.hram[address as usize - 0xFF80] = value,
|
||||
0xFFFF => self.interrupts.interrupt_enable = value & 0b1_1111,
|
||||
0xFFFF => self.interrupts.cpu_set_interrupt_enable(value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
61
meowgb-core/src/gameboy/dma.rs
Normal file
61
meowgb-core/src/gameboy/dma.rs
Normal file
|
@ -0,0 +1,61 @@
|
|||
use super::{ppu::Ppu, memory::Memory, mapper::Mapper};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DmaState {
|
||||
original_base: u8,
|
||||
pub base: u8,
|
||||
pub remaining_cycles: u8,
|
||||
restarting: Option<(u8, bool)>,
|
||||
}
|
||||
|
||||
impl DmaState {
|
||||
pub fn new() -> Self {
|
||||
Self { original_base: 0, base: 0, remaining_cycles: 0, restarting: None }
|
||||
}
|
||||
|
||||
pub fn init_request(&mut self, base: u8) {
|
||||
self.base = base;
|
||||
self.restarting = Some((base, false));
|
||||
}
|
||||
|
||||
pub fn tick_dma(&mut self, ppu: &mut Ppu, memory: &Memory, cartridge: Option<&(dyn Mapper + Send + Sync)>) {
|
||||
match self.restarting {
|
||||
Some((base, false)) => self.restarting = Some((base, true)),
|
||||
Some((base, true)) => {
|
||||
self.original_base = base;
|
||||
self.remaining_cycles = 0xA0;
|
||||
self.restarting = None;
|
||||
}
|
||||
None => {},
|
||||
}
|
||||
|
||||
ppu.dma_occuring = self.remaining_cycles > 0;
|
||||
|
||||
if self.remaining_cycles > 0 {
|
||||
let offset = 0xA0 - self.remaining_cycles;
|
||||
|
||||
let value = if self.original_base <= 0x7F {
|
||||
match cartridge {
|
||||
Some(cart) => cart.read_rom_u8((self.base as u16) << 8 | offset as u16),
|
||||
None => 0xFF,
|
||||
}
|
||||
} else if self.original_base <= 0x9F {
|
||||
let address = (((self.original_base as usize) << 8) | offset as usize) - 0x8000;
|
||||
ppu.vram[address]
|
||||
} else if self.original_base <= 0xDF {
|
||||
let address = ((self.original_base as usize) << 8 | offset as usize) - 0xC000;
|
||||
memory.wram[address]
|
||||
} else if self.original_base <= 0xFD {
|
||||
let address = ((self.original_base as usize) << 8 | offset as usize) - 0xE000;
|
||||
memory.wram[address]
|
||||
} else {
|
||||
0xFF
|
||||
};
|
||||
|
||||
ppu.dma_write_oam(offset, value);
|
||||
self.remaining_cycles -= 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -27,8 +27,8 @@ impl Interrupts {
|
|||
pub fn new() -> Self {
|
||||
Self {
|
||||
ime: false,
|
||||
interrupt_enable: 0,
|
||||
interrupt_flag: 0b11100000,
|
||||
interrupt_enable: 0b0000_0000,
|
||||
interrupt_flag: 0b1110_0001,
|
||||
ei_queued: false,
|
||||
cycle_passed: false,
|
||||
}
|
||||
|
@ -51,4 +51,8 @@ impl Interrupts {
|
|||
self.ime = false;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cpu_set_interrupt_enable(&mut self, value: u8) {
|
||||
self.interrupt_enable = value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ pub struct Joypad {
|
|||
impl Joypad {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
mode: JoypadMode::Direction,
|
||||
mode: JoypadMode::Both,
|
||||
down: false,
|
||||
up: false,
|
||||
left: false,
|
||||
|
@ -57,7 +57,7 @@ impl Joypad {
|
|||
}
|
||||
|
||||
pub fn cpu_read(&self) -> u8 {
|
||||
match self.mode {
|
||||
(0b11 << 6) | match self.mode {
|
||||
JoypadMode::Action => {
|
||||
(1 << 4)
|
||||
| ((!self.start as u8) << 3)
|
||||
|
@ -72,7 +72,7 @@ impl Joypad {
|
|||
| ((!self.left as u8) << 1)
|
||||
| (!self.right as u8)
|
||||
}
|
||||
JoypadMode::Both => 0x3F,
|
||||
JoypadMode::Both => 0b1111,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,4 +15,11 @@ impl Memory {
|
|||
bootrom_disabled: bootrom.is_none(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_bootrom_disabled(&self) -> u8 {
|
||||
match self.bootrom_disabled {
|
||||
true => 0xFF,
|
||||
false => 0x00,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,10 @@ use super::interrupts::Interrupts;
|
|||
pub const FB_HEIGHT: u32 = 144;
|
||||
pub const FB_WIDTH: u32 = 160;
|
||||
pub const PIXEL_SIZE: usize = 4; // RGBA
|
||||
/// Helper for debugging PPU timings that allows read/writes to PPU memory no
|
||||
/// matter what mode it is in. This also allows the PPU to bypass a DMA
|
||||
/// currently occuring which is blocking access to the memory bus.
|
||||
const OVERRIDE_PPU_MEMORY_ACCESS: bool = false;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Palette {
|
||||
|
@ -36,7 +40,7 @@ enum LineDrawingState {
|
|||
|
||||
impl Palette {
|
||||
pub fn new_bgp() -> Self {
|
||||
Self { id0: Color::White, id1: Color::LGray, id2: Color::DGray, id3: Color::Black }
|
||||
Self { id0: Color::White, id1: Color::Black, id2: Color::Black, id3: Color::Black }
|
||||
}
|
||||
|
||||
pub fn new_obp() -> Self {
|
||||
|
@ -325,7 +329,7 @@ impl Ppu {
|
|||
pub fn new(bootrom_ran: bool) -> Self {
|
||||
Self {
|
||||
registers: PpuRegisters {
|
||||
lcdc: (!bootrom_ran).then_some(0b1000_0000).unwrap_or_default(),
|
||||
lcdc: (!bootrom_ran).then_some(0b1001_0001).unwrap_or_default(),
|
||||
stat_flags: StatFlags::default(),
|
||||
mode: PPUMode::HBlank,
|
||||
scy: 0,
|
||||
|
@ -445,7 +449,7 @@ impl Ppu {
|
|||
}
|
||||
|
||||
fn internal_read_oam(&mut self, offset: usize) -> u8 {
|
||||
match self.dma_occuring {
|
||||
match self.dma_occuring && !OVERRIDE_PPU_MEMORY_ACCESS {
|
||||
true => 0xFF,
|
||||
false => self.oam[offset as usize],
|
||||
}
|
||||
|
@ -458,7 +462,7 @@ impl Ppu {
|
|||
|
||||
pub fn cpu_read_oam(&self, address: u16) -> u8 {
|
||||
let decoded_address = address - 0xFE00;
|
||||
if self.enabled() && !self.first_frame {
|
||||
if self.enabled() && !self.first_frame && !OVERRIDE_PPU_MEMORY_ACCESS {
|
||||
match self.mode() {
|
||||
PPUMode::HBlank | PPUMode::VBlank => self.oam[decoded_address as usize],
|
||||
PPUMode::SearchingOAM | PPUMode::TransferringData => 0xFF,
|
||||
|
@ -470,7 +474,7 @@ impl Ppu {
|
|||
|
||||
pub fn cpu_write_oam(&mut self, address: u16, value: u8) {
|
||||
let decoded_address = address - 0xFE00;
|
||||
if self.enabled() && !self.first_frame {
|
||||
if self.enabled() && !self.first_frame && !OVERRIDE_PPU_MEMORY_ACCESS {
|
||||
match self.mode() {
|
||||
PPUMode::HBlank | PPUMode::VBlank => self.oam[decoded_address as usize] = value,
|
||||
PPUMode::SearchingOAM | PPUMode::TransferringData => {}
|
||||
|
@ -482,7 +486,7 @@ impl Ppu {
|
|||
|
||||
pub fn cpu_read_vram(&self, address: u16) -> u8 {
|
||||
let decoded_address = address - 0x8000;
|
||||
if self.enabled() && !self.first_frame {
|
||||
if self.enabled() && !self.first_frame && !OVERRIDE_PPU_MEMORY_ACCESS {
|
||||
match self.mode() {
|
||||
PPUMode::HBlank | PPUMode::VBlank | PPUMode::SearchingOAM => {
|
||||
self.vram[decoded_address as usize]
|
||||
|
@ -496,7 +500,7 @@ impl Ppu {
|
|||
|
||||
pub fn cpu_write_vram(&mut self, address: u16, value: u8) {
|
||||
let decoded_address = address - 0x8000;
|
||||
if self.enabled() && !self.first_frame {
|
||||
if self.enabled() && !self.first_frame && !OVERRIDE_PPU_MEMORY_ACCESS {
|
||||
match self.mode() {
|
||||
PPUMode::HBlank | PPUMode::VBlank | PPUMode::SearchingOAM => {
|
||||
self.vram[decoded_address as usize] = value
|
||||
|
@ -629,9 +633,7 @@ impl Ppu {
|
|||
false
|
||||
}
|
||||
PPUMode::HBlank => {
|
||||
if self.first_line && self.current_dot == 16 && self.dot_target == 0 {
|
||||
// Special case for resets
|
||||
// self.handle_stat_irq(interrupts, false);
|
||||
if self.first_line && self.current_dot == 64 && self.dot_target == 0 {
|
||||
self.set_mode(interrupts, PPUMode::TransferringData);
|
||||
} else if self.dot_target != 0 && self.current_dot == self.dot_target {
|
||||
self.set_scanline(interrupts, self.registers.ly + 1);
|
||||
|
@ -639,7 +641,7 @@ impl Ppu {
|
|||
assert_eq!(
|
||||
self.total_dots,
|
||||
match self.first_frame && self.first_line {
|
||||
true => 456 - (80 - 16),
|
||||
true => 456 - (80 - 64),
|
||||
false => 456,
|
||||
}
|
||||
);
|
||||
|
|
|
@ -15,7 +15,7 @@ impl<T: Write> SerialWriter for T {
|
|||
|
||||
pub struct Serial<S: SerialWriter> {
|
||||
pub sb: u8,
|
||||
pub sc: u8,
|
||||
sc: u8,
|
||||
|
||||
internal_tick: u16,
|
||||
writer: S,
|
||||
|
@ -39,6 +39,14 @@ impl<S: SerialWriter> Serial<S> {
|
|||
self.sc & 0b1 == 1
|
||||
}
|
||||
|
||||
pub fn set_sc(&mut self, value: u8) {
|
||||
self.sc = value | (0b0111_1110);
|
||||
}
|
||||
|
||||
pub fn get_sc(&self) -> u8 {
|
||||
self.sc | (0b0111_1110)
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn set_side(&mut self, conductor: bool) {
|
||||
self.sc &= !0b1;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#[derive(Debug, Default)]
|
||||
#[derive(Debug)]
|
||||
pub struct Sound {
|
||||
pub nr10: u8,
|
||||
pub nr11: u8,
|
||||
|
@ -28,3 +28,32 @@ pub struct Sound {
|
|||
|
||||
pub wave_pattern_ram: [u8; 0x10],
|
||||
}
|
||||
|
||||
impl Sound {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
nr10: 0b1000_0000,
|
||||
nr11: 0b1011_1111,
|
||||
nr12: 0b1111_0011,
|
||||
nr13: 0b1111_1111,
|
||||
nr14: 0b1011_1111,
|
||||
nr21: 0b0011_1111,
|
||||
nr22: 0b0000_0000,
|
||||
nr23: 0b1111_1111,
|
||||
nr24: 0b1011_1111,
|
||||
nr30: 0b0111_1111,
|
||||
nr31: 0b1111_1111,
|
||||
nr32: 0b1001_1111,
|
||||
nr33: 0b1111_1111,
|
||||
nr34: 0b1011_1111,
|
||||
nr41: 0b1111_1111,
|
||||
nr42: 0b0000_0000,
|
||||
nr43: 0b0000_0000,
|
||||
nr44: 0b1011_1111,
|
||||
nr50: 0b0111_0111,
|
||||
nr51: 0b1111_0011,
|
||||
nr52: 0b1111_0001,
|
||||
wave_pattern_ram: [0u8;16],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ impl Timer {
|
|||
clock: TimerClock::C1024,
|
||||
tima: 0,
|
||||
tma: 0,
|
||||
div: 0,
|
||||
div: 0xAD,
|
||||
div_counter: 0,
|
||||
tima_counter: 0,
|
||||
overflow: false,
|
||||
|
@ -50,7 +50,7 @@ impl Timer {
|
|||
}
|
||||
|
||||
pub fn read_tac(&self) -> u8 {
|
||||
((self.enable as u8) << 2) | self.clock.tac_clock()
|
||||
((self.enable as u8) << 2) | self.clock.tac_clock() | 0b1111_1000
|
||||
}
|
||||
|
||||
pub fn write_tac(&mut self, value: u8) {
|
||||
|
|
1
meowgb-tests/expected_output/basic.bin
Normal file
1
meowgb-tests/expected_output/basic.bin
Normal file
|
@ -0,0 +1 @@
|
|||
"
|
1
meowgb-tests/expected_output/basic.gb
Normal file
1
meowgb-tests/expected_output/basic.gb
Normal file
|
@ -0,0 +1 @@
|
|||
"
|
1
meowgb-tests/expected_output/boot_hwio-dmgABCmgb.bin
Normal file
1
meowgb-tests/expected_output/boot_hwio-dmgABCmgb.bin
Normal file
|
@ -0,0 +1 @@
|
|||
"
|
1
meowgb-tests/expected_output/boot_regs-dmgABC.bin
Normal file
1
meowgb-tests/expected_output/boot_regs-dmgABC.bin
Normal file
|
@ -0,0 +1 @@
|
|||
"
|
1
meowgb-tests/expected_output/daa.bin
Normal file
1
meowgb-tests/expected_output/daa.bin
Normal file
|
@ -0,0 +1 @@
|
|||
"
|
1
meowgb-tests/expected_output/ei_sequence.bin
Normal file
1
meowgb-tests/expected_output/ei_sequence.bin
Normal file
|
@ -0,0 +1 @@
|
|||
"
|
1
meowgb-tests/expected_output/ei_timing.bin
Normal file
1
meowgb-tests/expected_output/ei_timing.bin
Normal file
|
@ -0,0 +1 @@
|
|||
"
|
1
meowgb-tests/expected_output/halt_ime0_ei.bin
Normal file
1
meowgb-tests/expected_output/halt_ime0_ei.bin
Normal file
|
@ -0,0 +1 @@
|
|||
"
|
1
meowgb-tests/expected_output/mem_oam.bin
Normal file
1
meowgb-tests/expected_output/mem_oam.bin
Normal file
|
@ -0,0 +1 @@
|
|||
"
|
1
meowgb-tests/expected_output/oam_dma_restart.bin
Normal file
1
meowgb-tests/expected_output/oam_dma_restart.bin
Normal file
|
@ -0,0 +1 @@
|
|||
"
|
1
meowgb-tests/expected_output/oam_dma_start.bin
Normal file
1
meowgb-tests/expected_output/oam_dma_start.bin
Normal file
|
@ -0,0 +1 @@
|
|||
"
|
1
meowgb-tests/expected_output/oam_dma_timing.bin
Normal file
1
meowgb-tests/expected_output/oam_dma_timing.bin
Normal file
|
@ -0,0 +1 @@
|
|||
"
|
1
meowgb-tests/expected_output/rapid_di_ei.bin
Normal file
1
meowgb-tests/expected_output/rapid_di_ei.bin
Normal file
|
@ -0,0 +1 @@
|
|||
"
|
1
meowgb-tests/expected_output/reg_f.bin
Normal file
1
meowgb-tests/expected_output/reg_f.bin
Normal file
|
@ -0,0 +1 @@
|
|||
"
|
1
meowgb-tests/expected_output/reg_read.bin
Normal file
1
meowgb-tests/expected_output/reg_read.bin
Normal file
|
@ -0,0 +1 @@
|
|||
"
|
1
meowgb-tests/expected_output/tim00_div_trigger.bin
Normal file
1
meowgb-tests/expected_output/tim00_div_trigger.bin
Normal file
|
@ -0,0 +1 @@
|
|||
"
|
1
meowgb-tests/expected_output/tim01.bin
Normal file
1
meowgb-tests/expected_output/tim01.bin
Normal file
|
@ -0,0 +1 @@
|
|||
"
|
1
meowgb-tests/expected_output/tim11_div_trigger.bin
Normal file
1
meowgb-tests/expected_output/tim11_div_trigger.bin
Normal file
|
@ -0,0 +1 @@
|
|||
"
|
1
meowgb-tests/expected_output/unused_hwio-GS.bin
Normal file
1
meowgb-tests/expected_output/unused_hwio-GS.bin
Normal file
|
@ -0,0 +1 @@
|
|||
"
|
19
test-roms/mooneye-test-suite/LICENSE
Normal file
19
test-roms/mooneye-test-suite/LICENSE
Normal file
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2014-2022 Joonas Javanainen <joonas.javanainen@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
5
test-roms/mooneye-test-suite/README.md
Normal file
5
test-roms/mooneye-test-suite/README.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
# Mooneye Test Suite
|
||||
|
||||
These test ROMs were written by "Gekkio", and are licensed by them under the MIT license, a copy of their license is in [LICENSE](./LICENSE).
|
||||
|
||||
The original source code can be found at [https://github.com/Gekkio/mooneye-test-suite](https://github.com/Gekkio/mooneye-test-suite).
|
BIN
test-roms/mooneye-test-suite/roms/basic.gb
Normal file
BIN
test-roms/mooneye-test-suite/roms/basic.gb
Normal file
Binary file not shown.
BIN
test-roms/mooneye-test-suite/roms/boot_hwio-dmgABCmgb.gb
Normal file
BIN
test-roms/mooneye-test-suite/roms/boot_hwio-dmgABCmgb.gb
Normal file
Binary file not shown.
BIN
test-roms/mooneye-test-suite/roms/boot_regs-dmgABC.gb
Normal file
BIN
test-roms/mooneye-test-suite/roms/boot_regs-dmgABC.gb
Normal file
Binary file not shown.
BIN
test-roms/mooneye-test-suite/roms/daa.gb
Normal file
BIN
test-roms/mooneye-test-suite/roms/daa.gb
Normal file
Binary file not shown.
BIN
test-roms/mooneye-test-suite/roms/ei_sequence.gb
Normal file
BIN
test-roms/mooneye-test-suite/roms/ei_sequence.gb
Normal file
Binary file not shown.
BIN
test-roms/mooneye-test-suite/roms/ei_timing.gb
Normal file
BIN
test-roms/mooneye-test-suite/roms/ei_timing.gb
Normal file
Binary file not shown.
BIN
test-roms/mooneye-test-suite/roms/halt_ime0_ei.gb
Normal file
BIN
test-roms/mooneye-test-suite/roms/halt_ime0_ei.gb
Normal file
Binary file not shown.
BIN
test-roms/mooneye-test-suite/roms/mem_oam.gb
Normal file
BIN
test-roms/mooneye-test-suite/roms/mem_oam.gb
Normal file
Binary file not shown.
BIN
test-roms/mooneye-test-suite/roms/oam_dma_restart.gb
Normal file
BIN
test-roms/mooneye-test-suite/roms/oam_dma_restart.gb
Normal file
Binary file not shown.
BIN
test-roms/mooneye-test-suite/roms/oam_dma_start.gb
Normal file
BIN
test-roms/mooneye-test-suite/roms/oam_dma_start.gb
Normal file
Binary file not shown.
BIN
test-roms/mooneye-test-suite/roms/oam_dma_timing.gb
Normal file
BIN
test-roms/mooneye-test-suite/roms/oam_dma_timing.gb
Normal file
Binary file not shown.
BIN
test-roms/mooneye-test-suite/roms/rapid_di_ei.gb
Normal file
BIN
test-roms/mooneye-test-suite/roms/rapid_di_ei.gb
Normal file
Binary file not shown.
BIN
test-roms/mooneye-test-suite/roms/reg_f.gb
Normal file
BIN
test-roms/mooneye-test-suite/roms/reg_f.gb
Normal file
Binary file not shown.
BIN
test-roms/mooneye-test-suite/roms/reg_read.gb
Normal file
BIN
test-roms/mooneye-test-suite/roms/reg_read.gb
Normal file
Binary file not shown.
BIN
test-roms/mooneye-test-suite/roms/tim00_div_trigger.gb
Normal file
BIN
test-roms/mooneye-test-suite/roms/tim00_div_trigger.gb
Normal file
Binary file not shown.
BIN
test-roms/mooneye-test-suite/roms/tim01.gb
Normal file
BIN
test-roms/mooneye-test-suite/roms/tim01.gb
Normal file
Binary file not shown.
BIN
test-roms/mooneye-test-suite/roms/tim11_div_trigger.gb
Normal file
BIN
test-roms/mooneye-test-suite/roms/tim11_div_trigger.gb
Normal file
Binary file not shown.
BIN
test-roms/mooneye-test-suite/roms/unused_hwio-GS.gb
Normal file
BIN
test-roms/mooneye-test-suite/roms/unused_hwio-GS.gb
Normal file
Binary file not shown.
Loading…
Reference in a new issue