Trunk r46303, src/core/ciacore.c.
Problem. ciacore_async_interrupt() moves the idle alarm to rclk + 1 only if (idleclk > rclk + 1). If the idle alarm is already due but has not run yet, it later runs with a clock older than ifr_clock, so ciacore_idle() skips cia_ifr_current() and the new flag raises no interrupt. It is only seen with the next event: two events, one interrupt.
When. Every asynchronous flag pulls the idle alarm close, so only the first flag after CIA_MAX_IDLE_CYCLES (5000) quiet cycles can hit an alarm that is due but has not run (its time fell inside the CPU's last instruction before the event).
Seen with a 1581 counting ATN edges by FLAG interrupt: now and then the first edge after a pause raised no interrupt. Only that case was tested; every ciacore_set_flag() and ciacore_set_sdr() caller shares the path. VIA signals are not affected.
Fix. Reschedule unless the alarm is already set for the next cycle. With it: 8 runs of 60 s clean, which without it failed within seconds.
That's an interesting patch, thanks!
I ran all tests from the CIA directory of the testbench and they all still pass. However, since the change affects what happens when a FLAG, CNT or SP input line is set from "the outside", those tests probably don't really test this change.
Would it be possible to make a small standalone test program, which fails without this patch but succeeds with it? That would be nice to add to the testbench. Although I can imagine that it is hard to make it small and simple...
Thanks for checking! Here's a small standalone test (ciaflag.prg, source for 64tass included). It needs a 1581 on device 8 in true drive emulation:
x64sc -debugcart -drive8type 1581 -drive8truedrive -autostartprgmode 1 -autostart ciaflag.prg
It uploads a little routine to the 1581 that counts FLAG interrupts (FLAG is ATN on the 1581) while the drive runs a busy loop with interrupts on. The C64 then sends bursts of 2 ATN pulses with a 5000-10000 cycle pause after each burst, so the first pulse of each burst comes after a long quiet stretch. Each round should count 2000 ($07D0). It runs 16 rounds and writes 0 or $ff to $d7ff, so with -debugcart it exits with 0 (pass) or 255 (fail).
With r46303 it fails every time I've run it (usually 5-9 interrupts lost). With the patch it passes.
You're right that it isn't really a CIA-only test, since it needs the drive. It's the simplest way I found to drive FLAG from outside at a random time relative to the drive CPU.
Thanks, I am convinced :) I will commit your patch in a moment and credit it to Mihai.
I will also add the test program to the test program collection. Since the testbench script currently has no way to specify that a 1581 is needed, it won't be run automatically. Yet, anyway.
Now it does :) cheers!
Is this related to the unstable parallel speeders perhaps? :)