From 59c1754a7505a44571a496c39ee2ed8afb40620b Mon Sep 17 00:00:00 2001
From: Michel Pollet <buserror@gmail.com>
Date: Thu, 5 Apr 2012 15:26:05 +0100
Subject: [PATCH] timer: Added phase correct mode, possibly works

Not tested..

Signed-off-by: Michel Pollet <buserror@gmail.com>
---
 simavr/cores/sim_megax4.h |  3 +++
 simavr/sim/avr_timer.c    | 37 ++++++++++++++++++++++++++++++++-----
 simavr/sim/avr_timer.h    |  6 ++++++
 3 files changed, 41 insertions(+), 5 deletions(-)

diff --git a/simavr/cores/sim_megax4.h b/simavr/cores/sim_megax4.h
index ecfd491..21f3130 100644
--- a/simavr/cores/sim_megax4.h
+++ b/simavr/cores/sim_megax4.h
@@ -276,6 +276,9 @@ struct mcu_t SIM_CORENAME = {
 					AVR_IO_REGBIT(TCCR1B, WGM12), AVR_IO_REGBIT(TCCR1B, WGM13) },
 		.wgm_op = {
 			[0] = AVR_TIMER_WGM_NORMAL16(),
+			[1] = AVR_TIMER_WGM_FCPWM8(),
+			[2] = AVR_TIMER_WGM_FCPWM9(),
+			[3] = AVR_TIMER_WGM_FCPWM10(),
 			[4] = AVR_TIMER_WGM_CTC(),
 			[5] = AVR_TIMER_WGM_FASTPWM8(),
 			[6] = AVR_TIMER_WGM_FASTPWM9(),
diff --git a/simavr/sim/avr_timer.c b/simavr/sim/avr_timer.c
index bca6d9d..9c8a3f9 100644
--- a/simavr/sim/avr_timer.c
+++ b/simavr/sim/avr_timer.c
@@ -190,7 +190,9 @@ static void avr_timer_configure(avr_timer_t * p, uint32_t clock, uint32_t top)
 	p->tov_top = top;
 
 	p->tov_cycles = frequency / t; // avr_hz_to_cycles(frequency, t);
-	printf("%s-%c TOP %.2fHz = %d cycles\n", __FUNCTION__, p->name, t, (int)p->tov_cycles);
+
+	if (p->trace_flags)
+		printf("%s-%c TOP %.2fHz = %d cycles\n", __FUNCTION__, p->name, t, (int)p->tov_cycles);
 
 	for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) {
 		if (!p->comp[compi].r_ocr)
@@ -199,11 +201,12 @@ static void avr_timer_configure(avr_timer_t * p, uint32_t clock, uint32_t top)
 		float fc = clock / (float)(ocr+1);
 
 		p->comp[compi].comp_cycles = 0;
-//		printf("%s-%c clock %d top %d OCR%c %d\n", __FUNCTION__, p->name, clock, top, 'A'+compi, ocr);
+	//	printf("%s-%c clock %d top %d OCR%c %d\n", __FUNCTION__, p->name, clock, top, 'A'+compi, ocr);
 
 		if (ocr && ocr <= top) {
 			p->comp[compi].comp_cycles = frequency / fc; // avr_hz_to_cycles(p->io.avr, fa);
-			printf("%s-%c %c %.2fHz = %d cycles\n", __FUNCTION__, p->name,
+			if (p->trace_flags & (1 << compi))
+				printf("%s-%c %c %.2fHz = %d cycles\n", __FUNCTION__, p->name,
 					'A'+compi, fc, (int)p->comp[compi].comp_cycles);
 		}
 	}
@@ -255,6 +258,9 @@ static void avr_timer_reconfigure(avr_timer_t * p)
 		case avr_timer_wgm_normal:
 			avr_timer_configure(p, f, (1 << p->mode.size) - 1);
 			break;
+		case avr_timer_wgm_fc_pwm:
+			avr_timer_configure(p, f, (1 << p->mode.size) - 1);
+			break;
 		case avr_timer_wgm_ctc: {
 			avr_timer_configure(p, f, _timer_get_ocr(p, AVR_TIMER_COMPA));
 		}	break;
@@ -266,19 +272,38 @@ static void avr_timer_reconfigure(avr_timer_t * p)
 			avr_timer_configure(p, f, (1 << p->mode.size) - 1);
 			break;
 		default:
-			printf("%s-%c unsupported timer mode wgm=%d (%d)\n", __FUNCTION__, p->name, mode, p->mode.kind);
+			printf("%s-%c unsupported timer mode wgm=%d (%d)\n", __FUNCTION__, p->name,
+					mode, p->mode.kind);
 	}	
 }
 
 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;
-	avr_core_watch_write(avr, addr, v);
+	uint16_t oldv[AVR_TIMER_COMP_COUNT];
+	int target = -1;
 
+	/* vheck to see if the OCR values actualy changed */
+	for (int oi = 0; oi < AVR_TIMER_COMP_COUNT; oi++)
+		oldv[oi] = _timer_get_ocr(p, oi);
+	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;
+		}
+	uint16_t otrace = p->trace_flags;
+	if (target != -1) {
+		p->trace_flags = 1 << target;
+	} else {
+		p->trace_flags = 0;
+	}
 	switch (p->mode.kind) {
 		case avr_timer_wgm_normal:
 			avr_timer_reconfigure(p);
 			break;
+		case avr_timer_wgm_fc_pwm:	// OCR is not used here
+			break;
 		case avr_timer_wgm_ctc:
 			avr_timer_reconfigure(p);
 			break;
@@ -297,6 +322,7 @@ static void avr_timer_write_ocr(struct avr_t * avr, avr_io_addr_t addr, uint8_t
 			avr_timer_reconfigure(p);
 			break;
 	}
+	p->trace_flags = otrace;
 }
 
 static void avr_timer_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param)
@@ -458,4 +484,5 @@ void avr_timer_init(avr_t * avr, avr_timer_t * p)
 	}
 	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);
+	p->trace_flags = 0xf;
 }
diff --git a/simavr/sim/avr_timer.h b/simavr/sim/avr_timer.h
index a159138..04b25e8 100644
--- a/simavr/sim/avr_timer.h
+++ b/simavr/sim/avr_timer.h
@@ -50,6 +50,7 @@ enum {
 	avr_timer_wgm_ctc,
 	avr_timer_wgm_pwm,
 	avr_timer_wgm_fast_pwm,
+	avr_timer_wgm_fc_pwm,
 };
 
 // Compare output modes
@@ -77,6 +78,9 @@ typedef struct avr_timer_wgm_t {
 #define AVR_TIMER_WGM_FASTPWM8() { .kind = avr_timer_wgm_fast_pwm, .size=8 }
 #define AVR_TIMER_WGM_FASTPWM9() { .kind = avr_timer_wgm_fast_pwm, .size=9 }
 #define AVR_TIMER_WGM_FASTPWM10() { .kind = avr_timer_wgm_fast_pwm, .size=10 }
+#define AVR_TIMER_WGM_FCPWM8() { .kind = avr_timer_wgm_fc_pwm, .size=8 }
+#define AVR_TIMER_WGM_FCPWM9() { .kind = avr_timer_wgm_fc_pwm, .size=9 }
+#define AVR_TIMER_WGM_FCPWM10() { .kind = avr_timer_wgm_fc_pwm, .size=10 }
 #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 }
 
@@ -84,6 +88,8 @@ typedef struct avr_timer_wgm_t {
 typedef struct avr_timer_t {
 	avr_io_t	io;
 	char name;
+	uint16_t		trace_flags;
+
 	avr_regbit_t	disabled;	// bit in the PRR
 
 	avr_io_addr_t	r_tcnt, r_icr;
-- 
2.39.5