timer: Reconfigure the timer in fast pwm mode
[simavr] / simavr / sim / avr_timer.c
index 22e9f45..7606c41 100644 (file)
@@ -6,7 +6,7 @@
        + CDC
        + Fast PWM
 
-       Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
+       Copyright 2008-2012 Michel Pollet <buserror@gmail.com>
 
        This file is part of simavr.
 
 
 #include <stdio.h>
 #include "avr_timer.h"
-
+#include "avr_ioport.h"
 
 /*
  * The timers are /always/ 16 bits here, if the higher byte register
  * is specified it's just added.
  */
-static uint16_t _timer_get_ocra(avr_timer_t * p)
-{
-       return p->io.avr->data[p->r_ocra] |
-                               (p->r_ocrah ? (p->io.avr->data[p->r_ocrah] << 8) : 0);
-}
-static uint16_t _timer_get_ocrb(avr_timer_t * p)
+static uint16_t _timer_get_ocr(avr_timer_t * p, int compi)
 {
-       return p->io.avr->data[p->r_ocrb] |
-                               (p->r_ocrbh ? (p->io.avr->data[p->r_ocrbh] << 8) : 0);
+       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_tcnt(avr_timer_t * p)
 {
@@ -52,67 +47,102 @@ static uint16_t _timer_get_icr(avr_timer_t * p)
        return p->io.avr->data[p->r_icr] |
                                (p->r_tcnth ? (p->io.avr->data[p->r_icrh] << 8) : 0);
 }
+static avr_cycle_count_t avr_timer_comp(avr_timer_t *p, avr_cycle_count_t when, uint8_t comp)
+{
+       avr_t * avr = p->io.avr;
+       avr_raise_interrupt(avr, &p->comp[comp].interrupt);
+
+       // check output compare mode and set/clear pins
+       uint8_t mode = avr_regbit_get(avr, p->comp[comp].com);
+       avr_irq_t * irq = &p->io.irq[TIMER_IRQ_OUT_COMP + comp];
+
+       switch (mode) {
+               case avr_timer_com_normal: // Normal mode OCnA disconnected
+                       break;
+               case avr_timer_com_toggle: // Toggle OCnA on compare match
+                       if (p->comp[comp].com_pin.reg)  // we got a physical pin
+                               avr_raise_irq(irq,
+                                               AVR_IOPORT_OUTPUT | (avr_regbit_get(avr, p->comp[comp].com_pin) ? 0 : 1));
+                       else // no pin, toggle the IRQ anyway
+                               avr_raise_irq(irq,
+                                               p->io.irq[TIMER_IRQ_OUT_COMP + comp].value ? 0 : 1);
+                       break;
+               case avr_timer_com_clear:
+                       avr_raise_irq(irq, 0);
+                       break;
+               case avr_timer_com_set:
+                       avr_raise_irq(irq, 1);
+                       break;
+       }
+
+       return p->tov_cycles ? 0 :
+                               p->comp[comp].comp_cycles ?
+                                               when + p->comp[comp].comp_cycles : 0;
+}
 
 static avr_cycle_count_t avr_timer_compa(struct avr_t * avr, avr_cycle_count_t when, void * param)
 {
-       avr_timer_t * p = (avr_timer_t *)param;
-       avr_raise_interrupt(avr, &p->compa);
-       return p->tov_cycles ? 0 : p->compa_cycles ? when + p->compa_cycles : 0;
+       return avr_timer_comp((avr_timer_t*)param, when, AVR_TIMER_COMPA);
 }
 
 static avr_cycle_count_t avr_timer_compb(struct avr_t * avr, avr_cycle_count_t when, void * param)
 {
-       avr_timer_t * p = (avr_timer_t *)param;
-       avr_raise_interrupt(avr, &p->compb);
-       return p->tov_cycles ? 0 : p->compb_cycles ? when + p->compb_cycles : 0;
+       return avr_timer_comp((avr_timer_t*)param, when, AVR_TIMER_COMPB);
+}
+
+static avr_cycle_count_t avr_timer_compc(struct avr_t * avr, avr_cycle_count_t when, void * param)
+{
+       return avr_timer_comp((avr_timer_t*)param, when, AVR_TIMER_COMPC);
 }
 
+// timer overflow
 static avr_cycle_count_t avr_timer_tov(struct avr_t * avr, avr_cycle_count_t when, void * param)
 {
        avr_timer_t * p = (avr_timer_t *)param;
        int start = p->tov_base == 0;
-       
+
        if (!start)
                avr_raise_interrupt(avr, &p->overflow);
        p->tov_base = when;
 
-       if (p->compa_cycles) {
-               if (p->compa_cycles < p->tov_cycles)
-                       avr_cycle_timer_register(avr, 
-                               p->compa_cycles - (avr->cycle - p->tov_base), 
-                               avr_timer_compa, p);
-               else if (p->tov_cycles == p->compa_cycles && !start)
-                       avr_timer_compa(avr, when, param);
-       }
-       
-       if (p->compb_cycles) {
-               if (p->compb_cycles < p->tov_cycles)
-                       avr_cycle_timer_register(avr, 
-                               p->compb_cycles - (avr->cycle - p->tov_base), 
-                               avr_timer_compb, p);
-               else if (p->tov_cycles == p->compb_cycles && !start)
-                       avr_timer_compb(avr, when, param);
+       static const avr_cycle_timer_t dispatch[AVR_TIMER_COMP_COUNT] =
+               { avr_timer_compa, avr_timer_compb, avr_timer_compc };
+
+       for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) {
+               if (p->comp[compi].comp_cycles) {
+                       if (p->comp[compi].comp_cycles < p->tov_cycles)
+                               avr_cycle_timer_register(avr,
+                                       p->comp[compi].comp_cycles,
+                                       dispatch[compi], p);
+                       else if (p->tov_cycles == p->comp[compi].comp_cycles && !start)
+                               dispatch[compi](avr, when, param);
+               }
        }
 
        return when + p->tov_cycles;
 }
 
+static uint16_t _avr_timer_get_current_tcnt(avr_timer_t * p)
+{
+       avr_t * avr = p->io.avr;
+       if (p->tov_cycles) {
+               uint64_t when = avr->cycle - p->tov_base;
+
+               return (when * (((uint32_t)p->tov_top)+1)) / p->tov_cycles;
+       }
+       return 0;
+}
 
 static uint8_t avr_timer_tcnt_read(struct avr_t * avr, avr_io_addr_t addr, void * param)
 {
        avr_timer_t * p = (avr_timer_t *)param;
        // made to trigger potential watchpoints
 
-       if (p->tov_cycles) {
-               uint64_t when = avr->cycle - p->tov_base;
-
-               uint16_t tcnt = (when * p->tov_top) / p->tov_cycles;
-       //      printf("%s-%c when = %d tcnt = %d/%d\n", __FUNCTION__, p->name, (uint32_t)when, tcnt, p->tov_top);
+       uint16_t tcnt = _avr_timer_get_current_tcnt(p);
 
-               avr->data[p->r_tcnt] = tcnt;
-               if (p->r_tcnth)
-                       avr->data[p->r_tcnth] = tcnt >> 8;
-       }
+       avr->data[p->r_tcnt] = tcnt;
+       if (p->r_tcnth)
+               avr->data[p->r_tcnth] = tcnt >> 8;
        
        return avr_core_watch_read(avr, addr);
 }
@@ -136,6 +166,7 @@ static void avr_timer_tcnt_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t
        avr_cycle_timer_cancel(avr, avr_timer_tov, p);
        avr_cycle_timer_cancel(avr, avr_timer_compa, p);
        avr_cycle_timer_cancel(avr, avr_timer_compb, p);
+       avr_cycle_timer_cancel(avr, avr_timer_compc, p);
 
        uint64_t cycles = (tcnt * p->tov_cycles) / p->tov_top;
 
@@ -152,31 +183,37 @@ static void avr_timer_tcnt_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t
 
 static void avr_timer_configure(avr_timer_t * p, uint32_t clock, uint32_t top)
 {
-       uint32_t ocra = _timer_get_ocra(p);
-       uint32_t ocrb = _timer_get_ocrb(p);
-       float fa = clock / (float)(ocra+1), fb = clock / (float)(ocrb+1);
        float t = clock / (float)(top+1);
        float frequency = p->io.avr->frequency;
 
-       p->compa_cycles = p->compb_cycles = p->tov_cycles = 0;
+       p->tov_cycles = 0;
        p->tov_top = top;
 
-       printf("%s-%c clock %d top %d a %d b %d\n", __FUNCTION__, p->name, clock, top, ocra, ocrb);
        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 (ocra && ocra <= top) {
-               p->compa_cycles = frequency / fa; // avr_hz_to_cycles(p->io.avr, fa);
-               printf("%s-%c A %.2fHz = %d cycles\n", __FUNCTION__, p->name, fa, (int)p->compa_cycles);
-       }
-       if (ocrb && ocrb <= top) {
-               p->compb_cycles = frequency / fb; // avr_hz_to_cycles(p->io.avr, fb);
-               printf("%s-%c B %.2fHz = %d cycles\n", __FUNCTION__, p->name, fb, (int)p->compb_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)
+                       continue;
+               uint32_t ocr = _timer_get_ocr(p, compi);
+               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);
+
+               if (ocr && ocr <= top) {
+                       p->comp[compi].comp_cycles = frequency / fc; // avr_hz_to_cycles(p->io.avr, fa);
+                       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);
+               }
        }
 
        if (p->tov_cycles > 1) {
                avr_cycle_timer_register(p->io.avr, p->tov_cycles, avr_timer_tov, p);
-               // calling it once, with when == 0 tells it to arm the A/B timers if needed
+               // calling it once, with when == 0 tells it to arm the A/B/C timers if needed
                p->tov_base = 0;
                avr_timer_tov(p->io.avr, p->io.avr->cycle, p);
        }
@@ -189,13 +226,15 @@ static void avr_timer_reconfigure(avr_timer_t * p)
        avr_timer_wgm_t zero={0};
        p->mode = zero;
        // cancel everything
-       p->compa_cycles = 0;
-       p->compb_cycles = 0;
+       p->comp[AVR_TIMER_COMPA].comp_cycles = 0;
+       p->comp[AVR_TIMER_COMPB].comp_cycles = 0;
+       p->comp[AVR_TIMER_COMPC].comp_cycles = 0;
        p->tov_cycles = 0;
        
        avr_cycle_timer_cancel(avr, avr_timer_tov, p);
        avr_cycle_timer_cancel(avr, avr_timer_compa, p);
        avr_cycle_timer_cancel(avr, avr_timer_compb, p);
+       avr_cycle_timer_cancel(avr, avr_timer_compc, p);
 
        long clock = avr->frequency;
 
@@ -219,48 +258,147 @@ 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_ocra(p));
+                       avr_timer_configure(p, f, _timer_get_ocr(p, AVR_TIMER_COMPA));
                }       break;
                case avr_timer_wgm_pwm: {
-                       uint16_t top = p->mode.top == avr_timer_wgm_reg_ocra ? _timer_get_ocra(p) : _timer_get_icr(p);
+                       uint16_t top = p->mode.top == avr_timer_wgm_reg_ocra ? _timer_get_ocr(p, AVR_TIMER_COMPA) : _timer_get_icr(p);
                        avr_timer_configure(p, f, top);
                }       break;
                case avr_timer_wgm_fast_pwm:
-               //      avr_timer_configure(p, f, (1 << p->mode.size) - 1);
+                       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;
+       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
+                       avr_timer_reconfigure(p);
+                       break;
+               case avr_timer_wgm_ctc:
+                       avr_timer_reconfigure(p);
+                       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_ocra(p));
-                               avr_raise_irq(p->io.irq + TIMER_IRQ_OUT_PWM1, _timer_get_ocrb(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));
                        }
                        break;
                case avr_timer_wgm_fast_pwm:
-                       avr_raise_irq(p->io.irq + TIMER_IRQ_OUT_PWM0, _timer_get_ocra(p));
-                       avr_raise_irq(p->io.irq + TIMER_IRQ_OUT_PWM1, _timer_get_ocrb(p));
+                       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));
                        break;
                default:
-                       printf("%s-%c mode %d\n", __FUNCTION__, p->name, p->mode.kind);
+                       printf("%s-%c mode %d UNSUPPORTED\n", __FUNCTION__, p->name, p->mode.kind);
                        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)
 {
        avr_timer_t * p = (avr_timer_t *)param;
+
+       uint8_t as2 = avr_regbit_get(avr, p->as2);
+       uint8_t cs = avr_regbit_get_array(avr, p->cs, ARRAY_SIZE(p->cs));
+       uint8_t mode = avr_regbit_get_array(avr, p->wgm, ARRAY_SIZE(p->wgm));
+
+       avr_core_watch_write(avr, addr, v);
+
+       // only reconfigure the timer if "relevant" bits have changed
+       // this prevent the timer reset when changing the edge detector
+       // or other minor bits
+       if (avr_regbit_get_array(avr, p->cs, ARRAY_SIZE(p->cs)) != cs ||
+                       avr_regbit_get_array(avr, p->wgm, ARRAY_SIZE(p->wgm)) != mode ||
+                                       avr_regbit_get(avr, p->as2) != as2) {
+               avr_timer_reconfigure(p);
+       }
+}
+
+/*
+ * write to the TIFR register. Watch for code that writes "1" to clear
+ * pending interrupts.
+ */
+static void avr_timer_write_pending(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param)
+{
+       avr_timer_t * p = (avr_timer_t *)param;
+       // save old bits values
+       uint8_t ov = avr_regbit_get(avr, p->overflow.raised);
+       uint8_t ic = avr_regbit_get(avr, p->icr.raised);
+       uint8_t cp[AVR_TIMER_COMP_COUNT];
+
+       for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++)
+               cp[compi] = avr_regbit_get(avr, p->comp[compi].interrupt.raised);
+
+       // write the value
        avr_core_watch_write(avr, addr, v);
-       avr_timer_reconfigure(p);
+
+       // clear any interrupts & flags
+       avr_clear_interrupt_if(avr, &p->overflow, ov);
+       avr_clear_interrupt_if(avr, &p->icr, ic);
+
+       for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++)
+               avr_clear_interrupt_if(avr, &p->comp[compi].interrupt, cp[compi]);
+}
+
+static void avr_timer_irq_icp(struct avr_irq_t * irq, uint32_t value, void * param)
+{
+       avr_timer_t * p = (avr_timer_t *)param;
+       avr_t * avr = p->io.avr;
+
+       // input capture disabled when ICR is used as top
+       if (p->mode.top == avr_timer_wgm_reg_icr)
+               return;
+       int bing = 0;
+       if (avr_regbit_get(avr, p->ices)) { // rising edge
+               if (!irq->value && value)
+                       bing++;
+       } else {        // default, falling edge
+               if (irq->value && !value)
+                       bing++;
+       }
+       if (!bing)
+               return;
+       // get current TCNT, copy it to ICR, and raise interrupt
+       uint16_t tcnt = _avr_timer_get_current_tcnt(p);
+       avr->data[p->r_icr] = tcnt;
+       if (p->r_icrh)
+               avr->data[p->r_icrh] = tcnt >> 8;
+       avr_raise_interrupt(avr, &p->icr);
 }
 
 static void avr_timer_reset(avr_io_t * port)
@@ -269,43 +407,86 @@ static void avr_timer_reset(avr_io_t * port)
        avr_cycle_timer_cancel(p->io.avr, avr_timer_tov, p);
        avr_cycle_timer_cancel(p->io.avr, avr_timer_compa, p);
        avr_cycle_timer_cancel(p->io.avr, avr_timer_compb, p);
-       p->compa_cycles = 0;
-       p->compb_cycles = 0;
+       avr_cycle_timer_cancel(p->io.avr, avr_timer_compc, p);
+
+       // check to see if the comparators have a pin output. If they do,
+       // (try) to get the ioport corresponding IRQ and connect them
+       // they will automagically be triggered when the comparator raises
+       // it's own IRQ
+       for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) {
+               p->comp[compi].comp_cycles = 0;
+
+               avr_ioport_getirq_t req = {
+                       .bit = p->comp[compi].com_pin
+               };
+               if (avr_ioctl(port->avr, AVR_IOCTL_IOPORT_GETIRQ_REGBIT, &req) > 0) {
+                       // cool, got an IRQ
+//                     printf("%s-%c COMP%c Connecting PIN IRQ %d\n", __FUNCTION__, p->name, 'A'+compi, req.irq[0]->irq);
+                       avr_connect_irq(&port->irq[TIMER_IRQ_OUT_COMP + compi], req.irq[0]);
+               }
+       }
+       avr_ioport_getirq_t req = {
+               .bit = p->icp
+       };
+       if (avr_ioctl(port->avr, AVR_IOCTL_IOPORT_GETIRQ_REGBIT, &req) > 0) {
+               // cool, got an IRQ for the input capture pin
+//             printf("%s-%c ICP Connecting PIN IRQ %d\n", __FUNCTION__, p->name, req.irq[0]->irq);
+               avr_irq_register_notify(req.irq[0], avr_timer_irq_icp, p);
+       }
+
 }
 
+static const char * irq_names[TIMER_IRQ_COUNT] = {
+       [TIMER_IRQ_OUT_PWM0] = "8>pwm0",
+       [TIMER_IRQ_OUT_PWM1] = "8>pwm1",
+       [TIMER_IRQ_OUT_COMP + 0] = ">compa",
+       [TIMER_IRQ_OUT_COMP + 1] = ">compb",
+       [TIMER_IRQ_OUT_COMP + 2] = ">compc",
+};
+
 static avr_io_t        _io = {
        .kind = "timer",
        .reset = avr_timer_reset,
+       .irq_names = irq_names,
 };
 
 void avr_timer_init(avr_t * avr, avr_timer_t * p)
 {
        p->io = _io;
-       //printf("%s timer%c created\n", __FUNCTION__, p->name);
-
-       // allocate this module's IRQ
-       p->io.irq_count = TIMER_IRQ_COUNT;
-       p->io.irq = avr_alloc_irq(0, p->io.irq_count);
-       p->io.irq_ioctl_get = AVR_IOCTL_TIMER_GETIRQ(p->name);
-       p->io.irq[TIMER_IRQ_OUT_PWM0].flags |= IRQ_FLAG_FILTERED;
-       p->io.irq[TIMER_IRQ_OUT_PWM1].flags |= IRQ_FLAG_FILTERED;
 
        avr_register_io(avr, &p->io);
-       avr_register_vector(avr, &p->compa);
-       avr_register_vector(avr, &p->compb);
        avr_register_vector(avr, &p->overflow);
        avr_register_vector(avr, &p->icr);
 
+       // allocate this module's IRQ
+       avr_io_setirqs(&p->io, AVR_IOCTL_TIMER_GETIRQ(p->name), TIMER_IRQ_COUNT, NULL);
+
+       // marking IRQs as "filtered" means they don't propagate if the
+       // new value raised is the same as the last one.. in the case of the
+       // pwm value it makes sense not to bother.
+       p->io.irq[TIMER_IRQ_OUT_PWM0].flags |= IRQ_FLAG_FILTERED;
+       p->io.irq[TIMER_IRQ_OUT_PWM1].flags |= IRQ_FLAG_FILTERED;
+
+       if (p->wgm[0].reg) // these are not present on older AVRs
+               avr_register_io_write(avr, p->wgm[0].reg, avr_timer_write, p);
        avr_register_io_write(avr, p->cs[0].reg, avr_timer_write, p);
 
+       // this assumes all the "pending" interrupt bits are in the same
+       // register. Might not be true on all devices ?
+       avr_register_io_write(avr, p->overflow.raised.reg, avr_timer_write_pending, p);
+
        /*
         * Even if the timer is 16 bits, we don't care to have watches on the
         * high bytes because the datasheet says that the low address is always
         * the trigger.
         */
-       avr_register_io_write(avr, p->r_ocra, avr_timer_write_ocr, p);
-       avr_register_io_write(avr, p->r_ocrb, avr_timer_write, p);
-       avr_register_io_write(avr, p->r_tcnt, avr_timer_tcnt_write, p);
+       for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) {
+               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->r_tcnt, avr_timer_tcnt_write, p);
        avr_register_io_read(avr, p->r_tcnt, avr_timer_tcnt_read, p);
+       p->trace_flags = 0xf;
 }