gianlucag / mos6502

A fast & simple MOS 6502 CPU emulator written in C++
MIT License
286 stars 56 forks source link

Clock Cycle Callback #23

Closed elmfrain closed 5 months ago

elmfrain commented 5 months ago

This adds a ClockCycle callback function so you can trigger code every time the processor experiences a clock pulse.

mos6502 cpu(BusRead, BusWrite, ClockCycle); // You can add it in the 3rd parameter of the constructor.

mos6502 cpu2(BusRead, BusWrite); // You do not have to include it if you don't need it.

A ClockCycle callback looks like this:

void clockCycle(mos6502* cpu)
{
   // 'cpu' is the instance of the 6502 that is being ran.
   // Code goes here.
   gpio.cycle();
   if (gpio.shouldInterrupt())
     cpu->IRQ();
}

What can it be used for?

I am developing a virtual microcontroller that uses the mos6502 as a core. This system has modules such a GPIO, Timers, and Serial Interfaces that the processor can interact with. Everything in the MCU is running on the same clock as the CPU.

Each module needs to be updated on each clock cycle so that it can trigger interrupts at the correct time. This callback allows that by being invoked however many cycles that 6502 runs at.

cpu.Run(100, cyclesCounter); // Invokes 'ClockCycle' callback ~100 times

Note: The method of counting cycles for this callback is always CYCLE_COUNT. The idea is that modules are relying on a system clock, and INST_COUNT wouldn't make sense because the modules in the real world won't necessarily know how many instructions the 6502 has executed.

Inner Main Loop Changes

while(start + n > cycles && !illegalOpcode)
{
    // fetch
    opcode = Read(pc++);

    // decode
    instr = InstrTable[opcode];

    // execute
    Exec(instr);

        // ---- new code added here ---- //
        // run clock cycle callback
        if (Cycle)
                for(int i = 0; i < instr.cycles; i++)
                        Cycle(this);
}