RichardBrown384 / Eichhoernchen

Acorn Archimedes A3000 Emulator in C++23
https://github.com/RichardBrown384/archimedes
MIT License
14 stars 0 forks source link

[BUG] IOC Timers can infinite loop. #32

Open RichardBrown384 opened 2 months ago

RichardBrown384 commented 2 months ago

Checklist

Describe the bug The IOC timers can infinite loop.

Problem code

if (scaledTicks >= scaledValue) {
  const auto scaledInputLatch = Scale * inputLatch;
  while (scaledTicks >= scaledValue) {
    scaledValue += scaledInputLatch;
   }
   expiryCallback();
}
scaledValue -= scaledTicks;

The code infinite loops when the inputLatch has been programmed to zero.

To Reproduce Steps to reproduce the behaviour:

  1. Configure a timer
  2. While the timer is counting down program 0 to the input latch
  3. Expire the timer.

Expected behaviour While this is a programming error, there's an additional dimension that wasn't thought about durning development. Namely what's supposed to happen when the timer latch is programmed to zero? Does the IOC continuously set the timer bits in IRQ A or does it only do that the first time the timer expires?

The VTI manual says:

If a counter is loaded with zero it continuously reloads and does not count.

I'm not entirely sure how to interpret that statement.

Please complete the following information

Additional context The IOC timers (and timers in general) don't currently have any unit tests. Unit tests for the IOC should include this case.

See #5

RichardBrown384 commented 1 month ago

Possible fix

const auto scaledInputLatch = Scale * inputLatch;
if (scaledInputLatch) {
    if (scaledTicks >= scaledValue) {
        while (scaledTicks >= scaledValue) {
            scaledValue += scaledInputLatch;
        }
        expiryCallback();
    }
    scaledValue -= scaledTicks;
    return;
}
if (scaledTicks >= scaledValue) {
    if (scaledValue) {
        expiryCallback();
    }
    scaledValue = 0u;
    return;
}
scaledValue -= scaledTicks;