When the program below starts, it sets up a few things (it's well commented), and when it reaches "idle_loop:", it waits for INT0 to be triggered by a mains zero-crossing.
I simulate the INT0 by clicking PIN[2]. It goes white (and stays white till I click it again). Even if I press shift-F5 to reset the simulator to the first instruction line, it does not change the colour of PIN[2].
It single-steps onto "brne idle_loop", then on the next single-step, it goes to the INT0 vector, then into the INT0 routine, then on reti, it returns to "cp R8,R9". The cp is true, and it falls through the branch. It runs down to "rcall average_time"
The "average_time:" routine starts with an identical wait loop - also waiting for R9=1, which is set by the INT0 interrupt.
cp R8,R9 ; R8 = 1
brne average_time
If the program counter (PC) is pointing to the brne when I trigger INT0, the next single-step takes it to the INT0 vector, and on return from the interrupt, it returns to the "cp R8,R9" instruction, which does the test, and falls through the "brne", and everything works every time, but if PC is pointing to the "cp R8,R9" when I click PIN[2], the next single-step takes it to the "brne" (always), and the next one takes it to the INT0 vector (always).
Now - each time I click the PIN[2] to invoke the interrupt, the PIN[2] square changes from white to grey, or from grey to white. If I click it and it goes white, the interrupt works as it should, and returns after the reti to "cp R8,R9". which gets tested for R9 being 1, then it falls through the branch and executes the instructions below it.
However, if I click PIN[2] and it turns grey (PC pointing to the "cp R8,R9", remember), it single-steps to the "brne" as before, and invokes the interrupt as before, but on reti, instead of returning to the "cp R8,R9", it returns to the "brne", and the compare does not get done. The next single-step takes it back to the interrupt, R9 gets incremented again (to 2, because it wasn't cleared), and my simulation falls apart.
Has this been noted before? Is it a bugette in AS-7, or is it some misunderstanding or bad coding on my part?
Here's enough of my code to simulate the question.
.org 0x0 rjmp main ; Reset - Address 0 .org 0x1 rjmp INT0_handler ; vector for INT0 (address 01) .org 0x05 rjmp TCNT0_overflow ; Vector for Timer/Counter0 Overflow INT0_handler: ; INT0 vector points here ; interrupts are stopped because we're in one. in R12,TCNT0 ; save LSB mov R11,R14 ; save MSB out TCNT0,R9 ; clear the timer clr R14 ; MSB (overflow counter) inc R9 ; indicates to main that INT0 has completed. reti TCNT0_overflow: ; increment overflow counter inc R14 ; number of overflows. Typically 0x3C-40 reti main: ; Load stack register LDI R16, HIGH(RAMEND) ; Upper byte OUT SPH,R16 ; to stack pointer LDI R16, LOW(RAMEND) ; Lower byte OUT SPL,R16 ; to stack pointer ldi R16,0x18 out DDRB,R16 ; Set PB3/PB4 OUT. All other port pins IN in R16, MCUCR andi R16,0xbc ; PUD set to 0 (active- disable pull-ups) and ISC[0:1] set to 0b00 ori R16,0x03 ; MCUCR[0:1] set - rising edge of int0 generates interrupt request out MCUCR,R16 in R16,TCCR0B andi R16,0xf8 ; CSO[0:2] set to 0. Other bits of TCCR0B preserved ori R16,0x4 ; CSO[0:2] set to 0b001 (clock/256) out TCCR0B,R16 ; start timer with prescaling of 1/256. Timer count will be cleared by each INT0 interrupt ldi R16,0x40 out GIMSK,R16 ; enable external INT0 in R16,TIMSK ; interrupt mask reg ori R16,0x02 ; TOIE0 - enable overflow interrupt out TIMSK,R16 setup_10mS_measurement: ; for first measurement, which may be invalid clr R9 ; INT0 indicator clr R14 ; overflow counter clr R8 inc R8 ; set R8 = 1 as a comparator for R9 sei ; enable interrupts idle_loop: cp R8,R9 brne idle_loop ; loop waiting for R9=1 - INT0 has triggered for the first time (which may give a partial count. ; We have seen the first count - waste it in case it was short. ;======================================== ; Start timing in earnest clr R9 ; re-arm interrupt clr R2 ; MSB in averaging accumulator clr R3 ; LSB in averaging accumulator ldi R16,8 mov R4,R16 ; Count of averaging samples = 8 rcall average_time rjmp reg_scope ; eternal routine. Displays indefinitely average_time: ; averages the timer counts over 8 counts ; R4 is the sample number. We will average 8 of them cp R8,R9 ; R8 = 1 brne average_time ; INT0 has been triggered clr R9 ; get ready for the next interrupt add R3,R12 ; LSB adc R2,R11 ; R2:R3 accumulate the total dec R4 brne average_time ; At this point, R4=0, and R2:R3 have accumulated the total of 8 timer counts. cli ; disable interrupts rcall stop_timer ; We don't need the timer any more. Let's stop it. ;========================================================= ; You don't need to go this far to simulate my question ;========================================================= ; Divide R2:R3 by 8 (shift them right 3 times) lsr R2 ; LSb -> [C] 1st time ror R3 ; [C] -> MSb lsr R2 ; LSb -> [C] 2nd time ror R3 ; [C] -> MSb lsr R2 ; LSb -> [C] 3rd time ror R3 ; [C] -> MSb if[C], the division yielded a fraction of more than half. Increment R3 (eg 3.51 ~= 3.6) adc R3,R4 ; R4=0, so this simply adds [C] to R3 ret ; average time is in R2:R3 stop_timer: in R16,TCCR0B ; timer control reg andi R16,0xf8 ; TCCR0B[xxxx x000] out TCCR0B, R16 ; Stop the clock reti reg_scope: ; displays 4 regs on scope, RS232-style. This routine works fine. ; not part of this question ; does not return