From 401493c8d9033afab9e35ea98e8e714b071c1bd9 Mon Sep 17 00:00:00 2001 From: Stephane Carrez Date: Wed, 6 Sep 2000 19:33:12 +0000 Subject: Fix 68hc11 timer device (accuracy, io, timer overflow) --- sim/m68hc11/ChangeLog | 10 ++ sim/m68hc11/dv-m68hc11tim.c | 302 +++++++++++++++++++++++++++----------------- 2 files changed, 197 insertions(+), 115 deletions(-) (limited to 'sim/m68hc11') diff --git a/sim/m68hc11/ChangeLog b/sim/m68hc11/ChangeLog index 8b5a69c..be35547 100644 --- a/sim/m68hc11/ChangeLog +++ b/sim/m68hc11/ChangeLog @@ -1,5 +1,15 @@ 2000-09-06 Stephane Carrez + * dv-m68hc11tim.c (m68hc11tim_timer_event): Compute the overflow + interrupt and compare events accurately. Take into account the + pending ticks not processed by the simulator yet (introduced a shift). + (m68hc11_port_event): Reset the timer interrupt delays. + (m68hc11tim_io_read_buffer): Be able to read several bytes. + (m68hc11tim_io_write_buffer): Likewise for write. + (m68hc11tim_io_write_buffer): Recompute the timer overflow interrupt. + +2000-09-06 Stephane Carrez + * dv-m68hc11spi.c (m68hc11spi_io_read_buffer): Clear the interrupts. (m68hc11spi_io_write_buffer): Likewise and fix the spi frame. (m68hc11spi_info): Clarify the status report diff --git a/sim/m68hc11/dv-m68hc11tim.c b/sim/m68hc11/dv-m68hc11tim.c index 3a4b2cf..c830c05 100644 --- a/sim/m68hc11/dv-m68hc11tim.c +++ b/sim/m68hc11/dv-m68hc11tim.c @@ -77,6 +77,8 @@ struct m68hc11tim unsigned long ovf_delay; signed64 clock_prescaler; signed64 tcnt_adjust; + signed64 cop_prev_interrupt; + signed64 rti_prev_interrupt; /* Periodic timers. */ struct hw_event *rti_timer_event; @@ -165,11 +167,13 @@ m68hc11tim_port_event (struct hw *me, { hw_event_queue_deschedule (me, controller->rti_timer_event); controller->rti_timer_event = 0; + controller->rti_prev_interrupt = 0; } if (controller->cop_timer_event) { hw_event_queue_deschedule (me, controller->cop_timer_event); controller->cop_timer_event = 0; + controller->cop_prev_interrupt = 0; } if (controller->tof_timer_event) { @@ -220,13 +224,16 @@ m68hc11tim_timer_event (struct hw *me, void *data) int check_interrupt = 0; unsigned mask; unsigned flags; + unsigned long tcnt_internal; unsigned long tcnt; int i; + sim_events *events; controller = hw_data (me); sd = hw_system (me); cpu = STATE_CPU (sd, 0); type = (enum event_type) ((long) data) & 0x0FF; + events = STATE_EVENTS (sd); delay = 0; switch (type) @@ -234,43 +241,82 @@ m68hc11tim_timer_event (struct hw *me, void *data) case COP_EVENT: eventp = &controller->cop_timer_event; delay = controller->cop_delay; + delay = controller->cop_prev_interrupt + controller->cop_delay; + controller->cop_prev_interrupt = delay; + delay = delay - cpu->cpu_absolute_cycle; check_interrupt = 1; + delay += events->nr_ticks_to_process; break; case RTI_EVENT: eventp = &controller->rti_timer_event; - delay = controller->rti_delay; + delay = controller->rti_prev_interrupt + controller->rti_delay; + if (((long) (data) & 0x0100) == 0) { cpu->ios[M6811_TFLG2] |= M6811_RTIF; check_interrupt = 1; + controller->rti_prev_interrupt = delay; + delay += controller->rti_delay; } + delay = delay - cpu->cpu_absolute_cycle; + delay += events->nr_ticks_to_process; break; case OVERFLOW_EVENT: + /* Compute the 68HC11 internal free running counter. + There may be 'nr_ticks_to_process' pending cycles that are + not (yet) taken into account by 'sim_events_time'. */ + tcnt_internal = sim_events_time (sd) - controller->tcnt_adjust; + tcnt_internal += events->nr_ticks_to_process; + + /* We must take into account the prescaler that comes + before the counter (it's a power of 2). */ + tcnt_internal &= 0x0ffff * controller->clock_prescaler; + + /* Compute the time when the overflow will occur. It occurs when + the counter increments from 0x0ffff to 0x10000 (and thus resets). */ + delay = (0x10000 * controller->clock_prescaler) - tcnt_internal; + + /* The 'nr_ticks_to_process' will be subtracted when the event + is scheduled. */ + delay += events->nr_ticks_to_process; + eventp = &controller->tof_timer_event; - delay = controller->ovf_delay; - cpu->ios[M6811_TFLG2] |= M6811_TOF; + if (((long) (data) & 0x100) == 0) + { + cpu->ios[M6811_TFLG2] |= M6811_TOF; + check_interrupt = 1; + } break; case COMPARE_EVENT: eventp = &controller->cmp_timer_event; - /* Get current free running counter. */ - tcnt = ((cpu->cpu_absolute_cycle - controller->tcnt_adjust) - / controller->clock_prescaler); - tcnt &= 0x0ffffL; + /* Compute the 68HC11 internal free running counter. + There may be 'nr_ticks_to_process' pending cycles that are + not (yet) taken into account by 'sim_events_time'. */ + events = STATE_EVENTS (sd); + tcnt_internal = sim_events_time (sd) - controller->tcnt_adjust; + tcnt_internal += events->nr_ticks_to_process; + + /* We must take into account the prescaler that comes + before the counter (it's a power of 2). */ + tcnt_internal &= 0x0ffff * controller->clock_prescaler; + + /* Get current visible TCNT register value. */ + tcnt = tcnt_internal / controller->clock_prescaler; flags = cpu->ios[M6811_TMSK1]; mask = 0x80; - delay = 65536; + delay = 65536 * controller->clock_prescaler; /* Scan each output compare register to see if one matches the free running counter. Set the corresponding OCi flag if the output compare is enabled. */ for (i = M6811_TOC1; i <= M6811_TOC5; i += 2, mask >>= 1) { - unsigned short compare; + unsigned long compare; compare = (cpu->ios[i] << 8) + cpu->ios[i+1]; if (compare == tcnt && (flags & mask)) @@ -279,16 +325,19 @@ m68hc11tim_timer_event (struct hw *me, void *data) check_interrupt++; } - /* Compute how many times for the next match. */ - if (compare > tcnt) - compare = compare - tcnt; + /* Compute how many times for the next match. + Use the internal counter value to take into account the + prescaler accurately. */ + compare = compare * controller->clock_prescaler; + if (compare > tcnt_internal) + compare = compare - tcnt_internal; else - compare = compare - tcnt + 65536; + compare = compare - tcnt_internal + + 65536 * controller->clock_prescaler; if (compare < delay) delay = compare; } - delay = delay * controller->clock_prescaler; /* Deactivate the compare timer if no output compare is enabled. */ if ((flags & 0xF0) == 0) @@ -442,6 +491,7 @@ m68hc11tim_io_read_buffer (struct hw *me, struct m68hc11tim *controller; sim_cpu *cpu; unsigned8 val; + unsigned cnt = 0; HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes)); @@ -449,27 +499,34 @@ m68hc11tim_io_read_buffer (struct hw *me, cpu = STATE_CPU (sd, 0); controller = hw_data (me); - switch (base) + while (nr_bytes) { - /* The cpu_absolute_cycle is updated after each instruction. - Reading in a 16-bit register will be split in two accesses - but this will be atomic within the simulator. */ - case M6811_TCTN_H: - val = (uint8) ((cpu->cpu_absolute_cycle - controller->tcnt_adjust) - / (controller->clock_prescaler * 256)); - break; + switch (base) + { + /* The cpu_absolute_cycle is updated after each instruction. + Reading in a 16-bit register will be split in two accesses + but this will be atomic within the simulator. */ + case M6811_TCTN_H: + val = (uint8) ((cpu->cpu_absolute_cycle - controller->tcnt_adjust) + / (controller->clock_prescaler * 256)); + break; - case M6811_TCTN_L: - val = (uint8) ((cpu->cpu_absolute_cycle - controller->tcnt_adjust) - / controller->clock_prescaler); - break; + case M6811_TCTN_L: + val = (uint8) ((cpu->cpu_absolute_cycle - controller->tcnt_adjust) + / controller->clock_prescaler); + break; - default: - val = cpu->ios[base]; - break; + default: + val = cpu->ios[base]; + break; + } + *((unsigned8*) dest) = val; + dest++; + base++; + nr_bytes--; + cnt++; } - *((unsigned8*) dest) = val; - return 1; + return cnt; } static unsigned @@ -485,109 +542,120 @@ m68hc11tim_io_write_buffer (struct hw *me, unsigned8 val, n; signed64 adj; int reset_compare = 0; + int reset_overflow = 0; + int cnt = 0; HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes)); sd = hw_system (me); cpu = STATE_CPU (sd, 0); controller = hw_data (me); - - val = *((const unsigned8*) source); - switch (base) + + while (nr_bytes) { - /* Set the timer counter low part, trying to preserve the low part. - We compute the absolute cycle adjustment that we have to apply - to obtain the timer current value. Computation must be made - in 64-bit to avoid overflow problems. */ - case M6811_TCTN_L: - adj = ((cpu->cpu_absolute_cycle - controller->tcnt_adjust) - / (controller->clock_prescaler * (signed64) 256)) & 0x0FF; - adj = cpu->cpu_absolute_cycle - - (adj * controller->clock_prescaler * (signed64) 256) - - ((signed64) adj * controller->clock_prescaler); - controller->tcnt_adjust = adj; - reset_compare = 1; - break; + val = *((const unsigned8*) source); + switch (base) + { + /* Set the timer counter low part, trying to preserve the low part. + We compute the absolute cycle adjustment that we have to apply + to obtain the timer current value. Computation must be made + in 64-bit to avoid overflow problems. */ + case M6811_TCTN_L: + adj = ((cpu->cpu_absolute_cycle - controller->tcnt_adjust) + / (controller->clock_prescaler * (signed64) 256)) & 0x0FF; + adj = cpu->cpu_absolute_cycle + - (adj * controller->clock_prescaler * (signed64) 256) + - ((signed64) adj * controller->clock_prescaler); + controller->tcnt_adjust = adj; + reset_compare = 1; + reset_overflow = 1; + break; - case M6811_TCTN_H: - adj = ((cpu->cpu_absolute_cycle - controller->tcnt_adjust) - / controller->clock_prescaler) & 0x0ff; - adj = cpu->cpu_absolute_cycle - - ((signed64) val * controller->clock_prescaler * (signed64) 256) - - (adj * controller->clock_prescaler); - controller->tcnt_adjust = adj; - reset_compare = 1; - break; + case M6811_TCTN_H: + adj = ((cpu->cpu_absolute_cycle - controller->tcnt_adjust) + / controller->clock_prescaler) & 0x0ff; + adj = cpu->cpu_absolute_cycle + - ((signed64) val * controller->clock_prescaler * (signed64) 256) + - (adj * controller->clock_prescaler); + controller->tcnt_adjust = adj; + reset_compare = 1; + reset_overflow = 1; + break; - case M6811_TMSK2: + case M6811_TMSK2: /* Timer prescaler cannot be changed after 64 bus cycles. */ - if (cpu->cpu_absolute_cycle >= 64) - { - val &= ~(M6811_PR1 | M6811_PR0); - val |= cpu->ios[M6811_TMSK2] & (M6811_PR1 | M6811_PR0); - } - switch (val & (M6811_PR1 | M6811_PR0)) - { - case 0: - n = 1; - break; - case M6811_PR0: - n = 4; - break; - case M6811_PR1: - n = 8; - break; - default: - case M6811_PR1 | M6811_PR0: - n = 16; + if (cpu->cpu_absolute_cycle >= 64) + { + val &= ~(M6811_PR1 | M6811_PR0); + val |= cpu->ios[M6811_TMSK2] & (M6811_PR1 | M6811_PR0); + } + switch (val & (M6811_PR1 | M6811_PR0)) + { + case 0: + n = 1; + break; + case M6811_PR0: + n = 4; + break; + case M6811_PR1: + n = 8; + break; + default: + case M6811_PR1 | M6811_PR0: + n = 16; + break; + } + if (cpu->cpu_absolute_cycle < 64) + { + reset_overflow = 1; + controller->clock_prescaler = n; + } + cpu->ios[base] = val; + interrupts_update_pending (&cpu->cpu_interrupts); break; - } - if (controller->clock_prescaler != n) - { - controller->clock_prescaler = n; - controller->ovf_delay = n * 65536; - m68hc11tim_timer_event (me, (void*) (OVERFLOW_EVENT| 0x100)); - } - cpu->ios[base] = val; - interrupts_update_pending (&cpu->cpu_interrupts); - break; - case M6811_PACTL: - n = (1 << ((val & (M6811_RTR1 | M6811_RTR0)))); - cpu->ios[base] = val; + case M6811_PACTL: + n = (1 << ((val & (M6811_RTR1 | M6811_RTR0)))); + cpu->ios[base] = val; - controller->rti_delay = (long) (n) * 8192; - m68hc11tim_timer_event (me, (void*) (RTI_EVENT| 0x100)); - break; + controller->rti_delay = (long) (n) * 8192; + m68hc11tim_timer_event (me, (void*) (RTI_EVENT| 0x100)); + break; - case M6811_TFLG2: - if (val & M6811_TOF) - val &= ~M6811_TOF; - else - val |= cpu->ios[M6811_TFLG2] & M6811_TOF; + case M6811_TFLG2: + if (val & M6811_TOF) + val &= ~M6811_TOF; + else + val |= cpu->ios[M6811_TFLG2] & M6811_TOF; /* Clear the Real Time interrupt flag. */ - if (val & M6811_RTIF) - val &= ~M6811_RTIF; - else - val |= cpu->ios[M6811_TFLG2] & M6811_RTIF; + if (val & M6811_RTIF) + val &= ~M6811_RTIF; + else + val |= cpu->ios[M6811_TFLG2] & M6811_RTIF; - cpu->ios[base] = val; - interrupts_update_pending (&cpu->cpu_interrupts); - break; + cpu->ios[base] = val; + interrupts_update_pending (&cpu->cpu_interrupts); + break; - case M6811_TOC1: - case M6811_TOC2: - case M6811_TOC3: - case M6811_TOC4: - case M6811_TOC5: - cpu->ios[base] = val; - reset_compare = 1; - break; + case M6811_TOC1: + case M6811_TOC2: + case M6811_TOC3: + case M6811_TOC4: + case M6811_TOC5: + cpu->ios[base] = val; + reset_compare = 1; + break; - default: - return 0; + default: + break; + } + + base++; + nr_bytes--; + cnt++; + source++; } /* Re-compute the next timer compare event. */ @@ -595,7 +663,11 @@ m68hc11tim_io_write_buffer (struct hw *me, { m68hc11tim_timer_event (me, (void*) (COMPARE_EVENT)); } - return nr_bytes; + if (reset_overflow) + { + m68hc11tim_timer_event (me, (void*) (OVERFLOW_EVENT| 0x100)); + } + return cnt; } -- cgit v1.1