Problems with test ROMs

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

Post Reply
Donqustix
Posts: 9
Joined: Fri Jul 21, 2017 2:29 am

Problems with test ROMs

Post by Donqustix »

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.
Last edited by Donqustix on Thu Nov 16, 2017 1:09 pm, edited 2 times in total.
User avatar
Zepper
Formerly Fx3
Posts: 3262
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Re: Problems with test ROMs

Post by Zepper »

Yes. In fact, they expect register $4017 to be functional.
Donqustix
Posts: 9
Joined: Fri Jul 21, 2017 2:29 am

Re: Problems with test ROMs

Post by Donqustix »

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?

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();}
Or I should implement all APU registers and channels in order to run the tests?
Donqustix
Posts: 9
Joined: Fri Jul 21, 2017 2:29 am

Re: Problems with test ROMs

Post by Donqustix »

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?
Donqustix
Posts: 9
Joined: Fri Jul 21, 2017 2:29 am

Re: Problems with test ROMs

Post by Donqustix »

My emulator has passed all tests :o (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:

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;
            }
Donqustix
Posts: 9
Joined: Fri Jul 21, 2017 2:29 am

Re: Problems with test ROMs

Post by Donqustix »

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.

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;
        }
    }
Post Reply