Hi,
Mikor wrote:I am currently increasing the system clock by 1 second every 18 ticks. HOWEVER, there are about 18.2 ticks per second, so the clock gains time. Is there a way for me to read the time from the CMOS, and use that, or do I have to find a way to make my current function more accurate?
My favourite method is to use overflow:
Code: Select all
add dword [factions_of_a_second], 0xE10E10E
adc dword [seconds], 0
In this case, the value 0xE10E10E makes the 32-bit "fractions_of_a_second" overflow once per second, which sets the carry flag and causes "seconds" to be incremented once per second.
This isn't quite right though...
The PIT runs with a base frequency of 1.19318166666 MHz, or more accurately "(3579544 / 3) MHz". The BIOS uses a divisor of 65536, which means IRQ 0 fires at 18.20650227864583333 Hz. To work out the value above you do "2^32 / frequency", which gives the value 0xE0F97D5.
Of course you don't have to use the PIT timer count that the BIOS used, and it's probably a good idea not to - using a smaller PIT count means you get a faster IRQ 0 frequency, and can measure the time more precisely. It also increases overhead a little, but that shouldn't matter much unless you set the PIT count too low . The maths above is the same though:
amount_to_add = (2^32 * 3 * PIT_count) / 3579544
I've done this at run-time before - the OS worked out how fast the CPU is, then decided what PIT count to use, then calculated the amount to add to the "factions_of_a_second" counter and setup the PIT. This means reduced overhead on slow CPUs and more precise timing on faster CPUs.
Note: for "precision" imagine what happens if software reads your time counter just before the IRQ fires and the counter is updated. If the counter is being increased once per second, then it can be wrong by almost a full a second.
The CMOS/RTC could be used too. It has a periodic interrupt which generates IRQ 8 that can be setup for any "power of 2" frequency from 2 Hz to 8192 Hz ("2, 4, 8, 16, 32, ..., 4096, 8192"). There's also an update interrupt which triggers IRQ 8 once per second.
You could also read the time directly from the CMOS/RTC "time of day" registers. This is slow (there's a lot of overhead involved) and it also lacks precision.
Cheers,
Brendan