Skip to content

2 MHz support #842

@dirkwhoffmann

Description

@dirkwhoffmann

Some C64 emulators and programs support a 2 MHz CPU mode, which is activated by setting a specific bit in $D030 (thus mimicking the $D030 port of the C128).

In 2 MHz mode, the VIC-II is blocked, allowing the CPU to use the VIC-II cycle for its own tasks. Supporting this mode is not difficult, but doing so without sacrificing emulation speed is the real task.

Let's peek into the main emulator loop:

template <bool enable8, bool enable9, bool execExp>
alwaysinline void C64::executeCycle()
{
    //
    // Run the emulator for one cycle
    //

    //  <---------- o2 low phase ----------->|<- o2 high phase ->|
    //                                       |                   |
    // ,-- C64 ------------------------------|-------------------|--,
    // |   ,-----,     ,-----,     ,-----,   |    ,-----,        |  |
    // |   |     |     |     |     |     |   |    |     |        |  |
    // '-->| CIA | --> | CIA | --> | VIC | --|--> | CPU | -------|--'
    //     |  1  |     |  2  |     |     |   |    |     |        |
    //     '-----'     '-----'     '-----'   |    '-----'        |
    //                                       |                   |
    //                                       |    ,--------,     |
    //                                       |    |        |     |
    // ,-- Drive ----------------------------|--> | VC1541 | ----|--,
    // |                                     |    |        |     |  |
    // |                                     |    '--------'     |  |
    // '-------------------------------------|-------------------|--'

    Cycle cycle = ++cpu.clock;

    //
    // First clock phase (o2 low)
    //

    if (nextTrigger <= cycle) processEvents(cycle);
    (vic.*vic.vicfunc[rasterCycle])();


    //
    // Second clock phase (o2 high)
    //

    cpu.execute<CPURevision::MOS_6510>();
    if constexpr (enable8) { if (drive8.needsEmulation) drive8.execute(durationOfOneCycle); }
    if constexpr (enable9) { if (drive9.needsEmulation) drive9.execute(durationOfOneCycle); }
    if constexpr (execExp) { expansionport.execute(); }
}

Adding a if (turbo) {} branch is the straightforward solution. However, it would hurt the performance of this function and degrade code quality. The cleanest solution is to modify the VIC-II function table once 2 MHz mode becomes active. The new handler functions can then execute the CPU instead of the VIC-II. This approach has zero impact on emulation speed and keeps the main loop clean.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions