From: Jakob Gruber <jakob.gruber@gmail.com>
Date: Thu, 23 Aug 2012 08:57:21 +0000 (+0200)
Subject: timer: Avoid infinite cycle timer on TCNT write
X-Git-Tag: v1.0~14
X-Git-Url: https://git.htl-mechatronik.at/public/?a=commitdiff_plain;h=27bab459856ad7e06c5c9801722628e77a03e33c;p=sx%2Fsimavr.git

timer: Avoid infinite cycle timer on TCNT write

In some situations, it was possible to enter an infinite cycle timer
loop. In avr_timer_tcnt_write, the tov cycle timer registration is not
protected and can register a timer with p->tov_cycles == 0.

The following atmega1280 program demonstrates this issue:

int main() {

	TCCR1A = 0;
	TCCR1B = (1<<WGM12) | (1<<ICES1);
	OCR1B = OCR1A = 960;

	/* Start */
	TCNT1 = 0;
	TCCR1B |= (1<<CS11);

	/* Stop */
	TCCR1B &= ~(1<<CS11);
	TIFR1 |= (1<<OCF1A) | (1<<OCF1B);

	/* Start */
	TCNT1 = 0; /**< Registers timer with tov_cycles == 0. */
	TCCR1B |= (1<<CS11);

	while (1) ;
	return 0;
}
---

diff --git a/simavr/sim/avr_timer.c b/simavr/sim/avr_timer.c
index aeda219..6e1d8cc 100644
--- a/simavr/sim/avr_timer.c
+++ b/simavr/sim/avr_timer.c
@@ -173,9 +173,11 @@ static void avr_timer_tcnt_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t
 //	printf("%s-%c %d/%d -- cycles %d/%d\n", __FUNCTION__, p->name, tcnt, p->tov_top, (uint32_t)cycles, (uint32_t)p->tov_cycles);
 
 	// this reset the timers bases to the new base
-	p->tov_base = 0;
-	avr_cycle_timer_register(avr, p->tov_cycles - cycles, avr_timer_tov, p);
-	avr_timer_tov(avr, avr->cycle - cycles, p);
+	if (p->tov_cycles > 1) {
+		avr_cycle_timer_register(avr, p->tov_cycles - cycles, avr_timer_tov, p);
+		p->tov_base = 0;
+		avr_timer_tov(avr, avr->cycle - cycles, p);
+	}
 
 //	tcnt = ((avr->cycle - p->tov_base) * p->tov_top) / p->tov_cycles;
 //	printf("%s-%c new tnt derive to %d\n", __FUNCTION__, p->name, tcnt);