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.
Some C64 emulators and programs support a 2 MHz CPU mode, which is activated by setting a specific bit in
$D030(thus mimicking the$D030port 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:
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.