From 85915dfa16407eb4e32940c88dbc2798ffa362de Mon Sep 17 00:00:00 2001
From: bsekisser <squirmyworms@embarqmail.com>
Date: Mon, 3 Mar 2014 17:14:36 -0500
Subject: [PATCH] avr_timer: changed avr_timer_write_ocr as part of larger
 avr_timer refactor.

- changed avr_timer_write_ocr code to take pointer of relevant
  	comparator structure rather than its parent timer.

- added _timer_get_comp_ocr which the modified avr_timer_write_ocr
	function uses.

	modified:   simavr/sim/avr_timer.c
	modified:   simavr/sim/avr_timer.h
---
 simavr/sim/avr_timer.c | 50 ++++++++++++++++++++++--------------------
 simavr/sim/avr_timer.h | 18 ++++++++-------
 2 files changed, 36 insertions(+), 32 deletions(-)

diff --git a/simavr/sim/avr_timer.c b/simavr/sim/avr_timer.c
index 9518e2f..81fafd9 100644
--- a/simavr/sim/avr_timer.c
+++ b/simavr/sim/avr_timer.c
@@ -38,6 +38,12 @@ static uint16_t _timer_get_ocr(avr_timer_t * p, int compi)
 	return p->io.avr->data[p->comp[compi].r_ocr] |
 		      (p->comp[compi].r_ocrh ? (p->io.avr->data[p->comp[compi].r_ocrh] << 8) : 0);
 }
+static uint16_t _timer_get_comp_ocr(struct avr_t * avr, avr_timer_comp_p comp)
+{
+	int ocrh = comp->r_ocrh;
+	return avr->data[comp->r_ocr] |
+		(ocrh ? (avr->data[ocrh] << 8) : 0);
+}
 static uint16_t _timer_get_tcnt(avr_timer_t * p)
 {
 	return p->io.avr->data[p->r_tcnt] |
@@ -283,45 +289,39 @@ static void avr_timer_reconfigure(avr_timer_t * p)
 
 static void avr_timer_write_ocr(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param)
 {
-	avr_timer_t * p = (avr_timer_t *)param;
-	uint16_t oldv[AVR_TIMER_COMP_COUNT];
-	int target = -1;
+	avr_timer_comp_p comp = (avr_timer_comp_p)param;
+	avr_timer_t *timer = comp->timer;
+	uint16_t oldv;
 
 	/* check to see if the OCR values actually changed */
-	for (int oi = 0; oi < AVR_TIMER_COMP_COUNT; oi++)
-		oldv[oi] = _timer_get_ocr(p, oi);
+	oldv = _timer_get_comp_ocr(avr, comp);
 	avr_core_watch_write(avr, addr, v);
-	for (int oi = 0; oi < AVR_TIMER_COMP_COUNT; oi++)
-		if (oldv[oi] != _timer_get_ocr(p, oi)) {
-			target = oi;
-			break;
-		}
 
-	switch (p->mode.kind) {
+	switch (timer->mode.kind) {
 		case avr_timer_wgm_normal:
-			avr_timer_reconfigure(p);
+			avr_timer_reconfigure(timer);
 			break;
 		case avr_timer_wgm_fc_pwm:	// OCR is not used here
-			avr_timer_reconfigure(p);
+			avr_timer_reconfigure(timer);
 			break;
 		case avr_timer_wgm_ctc:
-			avr_timer_reconfigure(p);
+			avr_timer_reconfigure(timer);
 			break;
 		case avr_timer_wgm_pwm:
-			if (p->mode.top != avr_timer_wgm_reg_ocra) {
-				avr_raise_irq(p->io.irq + TIMER_IRQ_OUT_PWM0, _timer_get_ocr(p, AVR_TIMER_COMPA));
-				avr_raise_irq(p->io.irq + TIMER_IRQ_OUT_PWM1, _timer_get_ocr(p, AVR_TIMER_COMPB));
+			if (timer->mode.top != avr_timer_wgm_reg_ocra) {
+				avr_raise_irq(timer->io.irq + TIMER_IRQ_OUT_PWM0, _timer_get_ocr(timer, AVR_TIMER_COMPA));
+				avr_raise_irq(timer->io.irq + TIMER_IRQ_OUT_PWM1, _timer_get_ocr(timer, AVR_TIMER_COMPB));
 			}
 			break;
 		case avr_timer_wgm_fast_pwm:
-			if (target != -1)
-				avr_timer_reconfigure(p);
-			avr_raise_irq(p->io.irq + TIMER_IRQ_OUT_PWM0, _timer_get_ocr(p, AVR_TIMER_COMPA));
-			avr_raise_irq(p->io.irq + TIMER_IRQ_OUT_PWM1, _timer_get_ocr(p, AVR_TIMER_COMPB));
+			if (oldv != _timer_get_comp_ocr(avr, comp))
+				avr_timer_reconfigure(timer);
+			avr_raise_irq(timer->io.irq + TIMER_IRQ_OUT_PWM0, _timer_get_ocr(timer, AVR_TIMER_COMPA));
+			avr_raise_irq(timer->io.irq + TIMER_IRQ_OUT_PWM1, _timer_get_ocr(timer, AVR_TIMER_COMPB));
 			break;
 		default:
-			AVR_LOG(avr, LOG_WARNING, "TIMER: %s-%c mode %d UNSUPPORTED\n", __FUNCTION__, p->name, p->mode.kind);
-			avr_timer_reconfigure(p);
+			AVR_LOG(avr, LOG_WARNING, "TIMER: %s-%c mode %d UNSUPPORTED\n", __FUNCTION__, timer->name, timer->mode.kind);
+			avr_timer_reconfigure(timer);
 			break;
 	}
 }
@@ -478,10 +478,12 @@ void avr_timer_init(avr_t * avr, avr_timer_t * p)
 	 * the trigger.
 	 */
 	for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) {
+		p->comp[compi].timer = p;
+		
 		avr_register_vector(avr, &p->comp[compi].interrupt);
 
 		if (p->comp[compi].r_ocr) // not all timers have all comparators
-			avr_register_io_write(avr, p->comp[compi].r_ocr, avr_timer_write_ocr, p);
+			avr_register_io_write(avr, p->comp[compi].r_ocr, avr_timer_write_ocr, &p->comp[compi]);
 	}
 	avr_register_io_write(avr, p->r_tcnt, avr_timer_tcnt_write, p);
 	avr_register_io_read(avr, p->r_tcnt, avr_timer_tcnt_read, p);
diff --git a/simavr/sim/avr_timer.h b/simavr/sim/avr_timer.h
index 7cb236f..87ec0b4 100644
--- a/simavr/sim/avr_timer.h
+++ b/simavr/sim/avr_timer.h
@@ -88,6 +88,15 @@ typedef struct avr_timer_wgm_t {
 #define AVR_TIMER_WGM_OCPWM() { .kind = avr_timer_wgm_pwm, .top = avr_timer_wgm_reg_ocra }
 #define AVR_TIMER_WGM_ICPWM() { .kind = avr_timer_wgm_pwm, .top = avr_timer_wgm_reg_icr }
 
+typedef struct avr_timer_comp_t {
+		avr_int_vector_t	interrupt;		// interrupt vector
+		struct avr_timer_t	*timer;			// parent timer
+		avr_io_addr_t		r_ocr;			// comparator register low byte
+		avr_io_addr_t		r_ocrh;			// comparator register hi byte
+		avr_regbit_t		com;			// comparator output mode registers
+		avr_regbit_t		com_pin;		// where comparator output is connected
+		uint64_t		comp_cycles;
+} avr_timer_comp_t, *avr_timer_comp_p;
 
 typedef struct avr_timer_t {
 	avr_io_t	io;
@@ -107,14 +116,7 @@ typedef struct avr_timer_t {
 	avr_regbit_t	icp;		// input capture pin, to link IRQs
 	avr_regbit_t	ices;		// input capture edge select
 
-	struct {
-		avr_int_vector_t	interrupt;		// interrupt vector
-		avr_io_addr_t		r_ocr;			// comparator register low byte
-		avr_io_addr_t		r_ocrh;			// comparator register hi byte
-		avr_regbit_t		com;			// comparator output mode registers
-		avr_regbit_t		com_pin;		// where comparator output is connected
-		uint64_t			comp_cycles;
-	} comp[AVR_TIMER_COMP_COUNT];
+	avr_timer_comp_t comp[AVR_TIMER_COMP_COUNT];
 
 	avr_int_vector_t overflow;	// overflow
 	avr_int_vector_t icr;	// input capture
-- 
2.39.5