dirkwhoffmann / virtualc64

VirtualC64 is a cycle-accurate C64 emulator for macOS
https://dirkwhoffmann.github.io/virtualc64
Other
351 stars 33 forks source link

Treu Love [2015] does not work #803

Open dirkwhoffmann opened 1 month ago

dirkwhoffmann commented 1 month ago

To reproduce:

The CPU will jam eventually.

mithrendal commented 1 month ago

a few seconds after run

real c64

image

virtualC64 5.0b7

image

looks like its somehow not using the correct width when the REU is blitting that bob "Blitter object" into video buffer

dirkwhoffmann commented 1 week ago

v5.1 will feature improved REU timing:

Bildschirmfoto 2024-08-29 um 11 21 48
dirkwhoffmann commented 1 week ago

Findings: To make the demo scene work, REU timing is critical. First, it is important to transfer one byte at a time. In v5.1, there will be an option OPT_EXP_REU_SPEED. It must be set to 1 (native speed):

Bildschirmfoto 2024-08-29 um 09 56 44

Second, timing inside the emulator is essential. When a DMA transfer is requested, the following code is executed (new 5.1 code):

void 
Reu::prepareDma()
{
    if (REU_DEBUG) { dump(Category::Dma, std::cout); }

    c64Addr = c64Base;
    reuAddr = reuBase;
    isize len = tlen ? tlen : 0x10000;

    // Freeze the CPU
    cpu.pullDownRdyLine(INTSRC_EXP);

    // Schedule the first event
    c64.scheduleRel<SLOT_EXP>(2, EXP_REU_PREPARE, len);
}

To get the demo work, there must be a 2 cycle delay before the first DMA access happens. This is emulated in the last line by scheduling an EXP_REU_PREPARE event in 2 cycles. A value of 0 or 1 causes the screen to remain blank. A value of 3 causes distortion.

Bildschirmfoto 2024-08-29 um 11 32 54

Hence, 2 seems to be the correct value (assuming the demo runs fine on real hardware).

dirkwhoffmann commented 4 days ago

Update: To get the second scene working, timing on VICII's BA line is crucial.

On csdb, there is a lot of talk about REU hardware bugs, stealing cycles from VICII etc. I doubt this is true. When reading the BA line with the proper delay (3 cycles), the demo scene looks in VirtualC64 like it does on the original C64 (at least to my aging eyes).

This is how I changed REU::processEvent to make the scene work:

   // Perform DMA if VICII does not block the bus
    if (!vic.baLine.delayed()) for (; todo; todo--, remaining--) doDma(id);

    if (remaining) {

        // Prepare the next event
        c64.scheduleInc<SLOT_EXP>(1, id, remaining);

    } else {

        // Finalize DMA if this was the last cycle
        finalizeDma(id);
        c64.cancel<SLOT_EXP>();
    }

Note: Using baLine.delayed() instead of baLine.current() is essential here.