Quote:
Why do you set counter to 0?
Because my dispatch code checks for 0 as a sentinel.
Quote:
VICE uses absolute clock numbers, so it does not need to adjust counter values when manipulating the queue.
(Using 16-bit integers here for brevity; the general principle applies to any sized integer.) Problems occur when using absolute values; because they're modulo, you end up wrap-around errors. For example, if a timed event is slated for clock cycle $FFFE, and the CPU is currently on cycle $FFFD, by the time the CPU is done with its current instruction, it could find itself at $0002. Now, $0002 is less than $FFFE, and therefore the scheduled event never triggers.
With relative count-downs, this problem never occurs.
Quote:
Don't you have to adjust the following counter values according to how many cycles were left from the previous counter?
WHOOPS -- you're right! Although it hasn't had any impact on the emulator yet, it IS a bug. I'll try fixing that later this evening.
Quote:
(I am not entirely clear on the meaning of the counter variable, I assume it holds the clock cycle difference to the previous event).
Yes. If you have three events, one scheduled for 1PM, 2PM, and 4PM, then the first event will have a counter of 1 hour. The next one will have a counter of 1 hour because it occurs "1 hour after the previous." Likewise, the next one would have a counter of 2, since it occurs "two hours after its previous."
Quote:
In VICE we had quite some problems when the emulator was running long enough to overflow the 32bit cycle counter. You may want to handle that as well.
This is precisely why I use relative counts in the timer queue. If a device needs absolute cycle numbers, it'll tend to use modulo subtraction to find a difference in cycles.
Quote:
Not sure I understand what you mean here. You can see the VICE code for VIA and CIA emulation, which is cycle exact, using the VICE alarm code that works similarly as your code. If you like I can give a short overview on the different methods in the CIA or VIA core code if you want to reuse it (but remember, it's GPLd)
I should be able to look at the code and rewrite parts myself. Simply looking at GPL code does not automatically mean my code is "infected" with the GPL "virus".
(That being said, K2 is going to be GPLed too, but still...)
My timed event code also allows for cycle exact callbacks.
However, I don't think there is any need. You've identified a few issues already, which I think, upon correction, will make the code closer to ideal.
What I meant by what I wrote is that if you were to look at the timer services in most operating systems, you'll find they work by counting down a number of counters, and those that decrement to zero are "triggered." However, this is expensive and imprecise. Expensive, because you need to iterate over a whole list of structures unnecessarily. Imprecise because you rely on the precision of the timer interrupt's frequency. Too high, and you steal performance from the rest of the system, effectively defeating the purpose of setting it that high in frequency in the first place.
The approach I took was used in the Commodore-Amiga's operating system, where they said, "Hey, look, the CIA chip
already has a count-down timer in it. Let's just re-use
that instead." So they adopted a system by which relative counts were used, stored in the list via an insertion sort, so that
only the head of the list needs to be touched regularly.
The result was a timer service accurate to within microseconds on AmigaOS, using a CIA clocked at 1MHz (or so), with a microprocessor clocked at 7.15909MHz.
The code that I posted is a reproduction of those characteristics taken from Dolphin 0.3, my last attempt at trying to replicate the timer.device implementation (clean-room) on the PC. I simply adopted and adapted it to suit my needs in K2.
Quote:
* VICE uses an absolute CPU clock and uses this value in the alarm handling. Not sure how this compares to your code. Using an absolute value results in less arithmetic operations (adds and subs)
As already surmised, and as I confirmed, it uses relative clocks, not absolute.
Quote:
* The alarm list itself is unordered. New alarms are added at the end of the list. A new pending alarm is only searched by scanning the list when an old alarm has been handled. I think this reduces the overhead when alarms are modified frequently.
This prevents multiple events from occuring simultaneously, as far as I can tell?
Also, the overwhelming majority of timer events will be recurring in some capacity. Because of this, the time spent performing the insertion sort is about the same time spent scanning the list for the "next pending event." You still have to visit
every node in your list, and still need to run subtractions, to find the minimum difference node (which, by definition, is the next node to process).
I would even argue that my system is actually faster, since events that occur sooner don't need to touch every node. On average, only half the nodes in the list need to be touched.
Quote:
* VICE uses "static inline" functions on data given as "context" pointers, that are local to the calling functions, so the compiler can optimize the dereferral operations away.
You lost me on this; deferral operations?