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
463 stars 73 forks source link

Reading TCNT in 2-cycle instructions #40

Closed urish closed 4 years ago

urish commented 4 years ago

When reading TCNT using a 2-cycle instruction (such as LDS), the simulation behaves differently than the silicone. The following code demonstrates the issue:

void setup() {
  unsigned int value = 0;
  cli();
  TCCR2A = 0; 
  TCCR2B = 1 << CS10; 

  /* See the generated assembly code below */
  TCNT2 = 0;
  asm("nop");
  value = TCNT2;

  sei();
  Serial.begin(115200);
  Serial.print("Clock cycles: ");
  Serial.println(value - 1);
}

// the loop function runs over and over again forever
void loop() {
}

Running this code in the simulation prints 1, while running it on a physical ATmega328p prints 2.

If you inspect the generated assembly code, you will see that it uses STS to set the value of TCNT2, then executes the NOP instruction, followed by an LDS to read the value of TCNT2:

STS 0x00B2, r1
NOP
LDS r12, 0x00B2

The LDS instruction takes 2 cycles to execute, and it seems like the counter is still incremented on the first cycle, before being copied into the register during the second cycle.