My emulator supports all official instructions (instr_test-v5) and basics of VBL handling (ppu_vbl_nmi - single rom #1), but I have a problem with cpu_timing_test6 and branch_timing_tests test ROMs.
Do they use any APU length counter? Because when my emulator executes these ROMs, they are stuck in an infinite loop.
Problems with test ROMs
Moderator: Moderators
Problems with test ROMs
Last edited by Donqustix on Thu Nov 16, 2017 1:09 pm, edited 2 times in total.
Re: Problems with test ROMs
Yes. In fact, they expect register $4017 to be functional.
Re: Problems with test ROMs
So, I've implemented some basics of the APU frame counter but it still doesn't work. Is it not enough for just running the tests?
Or I should implement all APU registers and channels in order to run the tests?
Code: Select all
void write_frame_counter(unsigned v) noexcept
{
frame_counter_mode = FrameCounterMode(v >> 7);
if ((inhibit_frame_irq = v & 0x40))
mem_pointers.cpu->set_irq(false);
delayed_frame_timer_reset = apu_clk1_is_high ? 4 : 3;
}
void clock_frame_counter_clock() noexcept
{
switch (frame_counter_mode)
{
case M4:
if (delayed_frame_timer_reset > 0 && --delayed_frame_timer_reset == 0)
frame_counter_clock = 0;
else
if (++frame_counter_clock == 2*14914 + 2) {
frame_counter_clock = 0;
if (!inhibit_frame_irq) {mem_pointers.cpu->set_irq(true);}
}
switch (frame_counter_clock)
{
case 2*14914:
case 2*14914 + 1:
if (!inhibit_frame_irq) mem_pointers.cpu->set_irq(true);
break;
}
break;
case M5:
if (delayed_frame_timer_reset > 0 && --delayed_frame_timer_reset == 0)
frame_counter_clock = 0;
else
if (++frame_counter_clock == 2*18640 + 2)
frame_counter_clock = 0;
break;
}
}
void tick() noexcept {apu_clk1_is_high = !apu_clk1_is_high; clock_frame_counter_clock();}
Re: Problems with test ROMs
Hm. Now, I can't pass 3-nmi_and_irq.nes from cpu_interrupts_v2 and the last one from ppu_vbl_nmi (even_odd_timing). Does someone know, if APU works properly but not very accurate, can it cause my emulator to fail the nmi_and_irq test?
Re: Problems with test ROMs
My emulator has passed all tests (not including nmi_and_irq and ppu_sprite_hit).
I added the following lines into the write_mask function to pass 10-even_odd_timing:
I added the following lines into the write_mask function to pass 10-even_odd_timing:
Code: Select all
if ((mask ^ open_bus_data) & MASK_MASK_RENDERING_ENABLED)
{
if (scanline == 261 && clks == 339 && odd_frame)
clks = open_bus_data & MASK_MASK_RENDERING_ENABLED ? 338 : 340;
}
Re: Problems with test ROMs
I don't understand something. In the second level of Battletoads, when I move the main character to the bottom of the screen, it becomes "immortal" because enemies always attack below the main character, despite his location.
I've found, the problem is the time of rising the sprite overflow flag. When the flag is set true immediately, it fixes Battletoads and breaks the third test of ppu_sprite_overflow (timing). When the setting of the flag is delayed by 1 PPU cycle, it breaks Battletoads and fixes ppu_sprite_overflow.
I've found, the problem is the time of rising the sprite overflow flag. When the flag is set true immediately, it fixes Battletoads and breaks the third test of ppu_sprite_overflow (timing). When the setting of the flag is delayed by 1 PPU cycle, it breaks Battletoads and fixes ppu_sprite_overflow.
Code: Select all
switch (clks & 1)
{
case 1: oam_tmp = oam[oam_addr]; break;
case 0:
{
const bool in_range = (scanline - oam_tmp < (ctrl & CTRL_MASK_SPRITE_SIZE ? 16 : 8));
if (clks == 66) s0_next_scanline = in_range;
if (!scan_oam_addr_overflow && !oam_addr_overflow)
scan_oam[scan_oam_addr] = oam_tmp;
else
oam_tmp = scan_oam[scan_oam_addr];
if (oam_copy > 0)
{
--oam_copy;
if (!(++ oam_addr &= 0xFF)) oam_addr_overflow = true;
if (!(++scan_oam_addr &= 0x1F)) scan_oam_addr_overflow = sprite_overflow_detection = true;
}
else if (in_range && !scan_oam_addr_overflow && !oam_addr_overflow)
{
oam_copy = 3;
if (!(++ oam_addr &= 0xFF)) oam_addr_overflow = true;
if (!(++scan_oam_addr &= 0x1F)) scan_oam_addr_overflow = sprite_overflow_detection = true;
}
else if (sprite_overflow_detection)
{
if (in_range && !oam_addr_overflow) {sprite_overflow = true; sprite_overflow_detection = false;}
else
{
const u16 temp = ((oam_addr + 4) & ~3) | ((oam_addr + 1) & 3); oam_addr = temp & 255;
if (temp & 256) oam_addr_overflow = true;
}
}
else
{
const u16 temp = oam_addr + 4; oam_addr = temp & 0xFC;
if (temp & 256) oam_addr_overflow = true;
}
break;
}
}