wokwi / avr8js

Arduino (8-bit AVR) simulator, written in JavaScript and runs in the browser / Node.js
https://blog.wokwi.com/avr8js-simulate-arduino-in-javascript/
MIT License
462 stars 73 forks source link

Timer Output Compare sometimes misses Compare Match #79

Closed urish closed 3 years ago

urish commented 3 years ago

It happens when the timers goes past OCRA/OCRB due to a multi-cycle instruction.

Reproducing test case:

it('should not miss Compare Match when executing multi-cycle instruction', () => {
  const { program, instructionCount } = asmProgram(`
    LDI r16, 0x10   ; OCR0A = 0x10;   // <- TOP value
    OUT 0x27, r16  
    ; Set waveform generation mode (WGM) to normal, enable OC0A (Set on match)
    LDI r16, 0xc0   ; TCCR0A = (1 << COM0A1) | (1 << COM0A0);
    OUT 0x24, r16  
    LDI r16, 0x1    ; TCCR0B = (1 << CS00);
    OUT 0x25, r16  
    LDI r16, 0xf    ; TCNT0 = 0xf;
    OUT 0x26, r16  

    RJMP 1          ; TCNT0 will be 0x11 (this is a 2-cycle NOP)
  `);

  const cpu = new CPU(program);
  new AVRTimer(cpu, timer0Config);

  // Listen to Port D's internal callback
  const gpioCallback = jest.fn();
  cpu.gpioTimerHooks[PORTD] = gpioCallback;

  const runner = new TestProgramRunner(cpu);
  runner.runInstructions(instructionCount);
  expect(cpu.readData(TCNT0)).toEqual(0x11);
  expect(gpioCallback).toHaveBeenCalledWith(6, PinOverrideMode.Enable, 0x2b);
  expect(gpioCallback).toHaveBeenCalledWith(6, PinOverrideMode.Set, 0x2b);
});