* configure.in: Remove target-libstdc++-v3 from noconfigdirs for
[deliverable/binutils-gdb.git] / sim / m68hc11 / dv-m68hc11tim.c
index 3a4b2cf3dde681d7c07436186ba0dcb65371e65f..0456f67891271e0b342f21ec8c4bc57e96efb97e 100644 (file)
@@ -1,6 +1,6 @@
 /*  dv-m68hc11tim.c -- Simulation of the 68HC11 timer devices.
-    Copyright (C) 1999, 2000 Free Software Foundation, Inc.
-    Written by Stephane Carrez (stcarrez@worldnet.fr)
+    Copyright (C) 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
+    Written by Stephane Carrez (stcarrez@nerim.fr)
     (From a driver model Contributed by Cygnus Solutions.)
 
     This file is part of the program GDB, the GNU debugger.
@@ -25,7 +25,7 @@
 #include "sim-main.h"
 #include "hw-main.h"
 #include "sim-assert.h"
-
+#include <limits.h>
 
 /* DEVICE
 
         Reset the timer device.  This port must be connected to
         the cpu-reset output port.
 
+   capture (input)
+
+        Input capture.  This port must be connected to the input
+        captures.  It latches the current TCNT free running counter
+        into one of the three input capture registers.
+
    */
 
 
 
 enum
 {
-  RESET_PORT
+  RESET_PORT,
+  CAPTURE
 };
 
 
 static const struct hw_port_descriptor m68hc11tim_ports[] = 
 {
-  { "reset", RESET_PORT, 0, input_port, },
+  { "reset",   RESET_PORT, 0, input_port, },
+  { "capture", CAPTURE,    0, input_port, },
   { NULL, },
 };
 
@@ -77,6 +85,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;
@@ -109,7 +119,6 @@ attach_m68hc11tim_regs (struct hw *me,
                     me);
 }
 
-
 static void
 m68hc11tim_finish (struct hw *me)
 {
@@ -126,7 +135,7 @@ m68hc11tim_finish (struct hw *me)
 #else
   me->to_ioctl = m68hc11tim_ioctl;
 #endif
-
+  
   /* Preset defaults.  */
   controller->clock_prescaler = 1;
   controller->tcnt_adjust = 0;
@@ -136,7 +145,6 @@ m68hc11tim_finish (struct hw *me)
 }
 
 
-
 /* An event arrives on an interrupt port.  */
 
 static void
@@ -150,7 +158,8 @@ m68hc11tim_port_event (struct hw *me,
   struct m68hc11tim *controller;
   sim_cpu *cpu;
   unsigned8 val;
-  
+  unsigned16 tcnt;
+
   controller = hw_data (me);
   sd         = hw_system (me);
   cpu        = STATE_CPU (sd, 0);
@@ -165,11 +174,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)
           {
@@ -183,17 +194,35 @@ m68hc11tim_port_event (struct hw *me,
           }
 
         /* Reset the state of Timer registers.  This also restarts
-           the timer events (overflow and RTI clock).  */
+           the timer events (overflow and RTI clock).  The pending
+           flags (TFLG2) must be cleared explicitly here.  */
         val = 0;
+        cpu->ios[M6811_TFLG2] = 0;
         m68hc11tim_io_write_buffer (me, &val, io_map,
                                     (unsigned_word) M6811_TMSK2, 1);
-        m68hc11tim_io_write_buffer (me, &val, io_map,
-                                    (unsigned_word) M6811_TFLG2, 1);
         m68hc11tim_io_write_buffer (me, &val, io_map,
                                     (unsigned_word) M6811_PACTL, 1);
         break;
       }
 
+    case CAPTURE:
+      tcnt = (uint16) ((cpu->cpu_absolute_cycle - controller->tcnt_adjust)
+                       / controller->clock_prescaler);
+      switch (level)
+        {
+        case M6811_TIC1:
+        case M6811_TIC2:
+        case M6811_TIC3:
+          cpu->ios[level] = tcnt >> 8;
+          cpu->ios[level + 1] = tcnt;
+          break;
+
+        default:
+          hw_abort (me, "Invalid event parameter %d", level);
+          break;
+        }
+      break;
+
     default:
       hw_abort (me, "Event on unknown port %d", my_port);
       break;
@@ -220,13 +249,18 @@ m68hc11tim_timer_event (struct hw *me, void *data)
   int check_interrupt = 0;
   unsigned mask;
   unsigned flags;
-  unsigned long tcnt;
+  unsigned long tcnt_internal;
+  unsigned long tcnt, tcnt_prev;
+  signed64 tcnt_insn_end;
+  signed64 tcnt_insn_start;
   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,65 +268,124 @@ 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.  */
+      tcnt_internal = (cpu->cpu_absolute_cycle - controller->tcnt_adjust);
+
+      /* 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;
+      /* Compute value of TCNT register (64-bit precision) at beginning
+         and end of instruction.  */
+      tcnt_insn_end = (cpu->cpu_absolute_cycle - controller->tcnt_adjust);
+      tcnt_insn_start = (tcnt_insn_end - cpu->cpu_current_cycle);
+
+      /* TCNT value at beginning of current instruction.  */
+      tcnt_prev = (tcnt_insn_start / controller->clock_prescaler) & 0x0ffff;
+
+      /* TCNT value at end of current instruction.  */
+      tcnt = (tcnt_insn_end / controller->clock_prescaler) & 0x0ffff;
+
+      /* We must take into account the prescaler that comes
+         before the counter (it's a power of 2).  */
+      tcnt_internal = tcnt_insn_end;
+      tcnt_internal &= 0x0ffff * controller->clock_prescaler;
 
-      /* Get current free running counter.  */
-      tcnt = ((cpu->cpu_absolute_cycle - controller->tcnt_adjust)
-              / controller->clock_prescaler);
-      tcnt &= 0x0ffffL;
-      
       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;
-          
-          compare = (cpu->ios[i] << 8) + cpu->ios[i+1];
-          if (compare == tcnt && (flags & mask))
+          unsigned long compare;
+
+          compare = (cpu->ios[i] << 8) + cpu->ios[i + 1];
+
+          /* See if compare is reached; handle wrap arround.  */
+          if ((compare >= tcnt_prev && compare <= tcnt && tcnt_prev < tcnt)
+              || (compare >= tcnt_prev && tcnt_prev > tcnt)
+              || (compare < tcnt && tcnt_prev > tcnt))
             {
+              unsigned dt;
+
+              if (compare > tcnt)
+                dt = 0x10000 - compare - tcnt;
+              else
+                dt = tcnt - compare;
+
               cpu->ios[M6811_TFLG1] |= mask;
-              check_interrupt++;
+
+              /* Raise interrupt now at the correct CPU cycle so that
+                 we can find the interrupt latency.  */
+              cpu->cpu_absolute_cycle -= dt;
+              interrupts_update_pending (&cpu->cpu_interrupts);
+              cpu->cpu_absolute_cycle += dt;
             }
 
-          /* 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)
+      if ((flags & 0xF8) == 0)
         delay = 0;
+      else
+        delay += events->nr_ticks_to_process;
+
+      eventp = &controller->cmp_timer_event;
       break;
 
     default:
@@ -320,6 +413,30 @@ m68hc11tim_timer_event (struct hw *me, void *data)
 
 /* Descriptions of the Timer I/O ports.  These descriptions are only used to
    give information of the Timer device under GDB.  */
+io_reg_desc tmsk1_desc[] = {
+  { M6811_OC1I,  "OC1I ", "Timer Output Compare 1 Interrupt Enable" },
+  { M6811_OC2I,  "OC2I ", "Timer Output Compare 2 Interrupt Enable" },
+  { M6811_OC3I,  "OC3I ", "Timer Output Compare 3 Interrupt Enable" },
+  { M6811_OC4I,  "OC4I ", "Timer Output Compare 4 Interrupt Enable" },
+  { M6811_OC5I,  "OC5I ", "Timer Input Capture 4 / Output Compare 5 Enable" },
+  { M6811_IC1I,  "IC1I ", "Timer Input Capture 1 Interrupt Enable" },
+  { M6811_IC2I,  "IC2I ", "Timer Input Capture 2 Interrupt Enable" },
+  { M6811_IC3I,  "IC3I ", "Timer Input Capture 3 Interrupt Enable" },
+  { 0, 0, 0 }
+};
+
+io_reg_desc tflg1_desc[] = {
+  { M6811_OC1F,  "OC1F ", "Timer Output Compare 1 Interrupt Flag" },
+  { M6811_OC2F,  "OC2F ", "Timer Output Compare 2 Interrupt Flag" },
+  { M6811_OC3F,  "OC3F ", "Timer Output Compare 3 Interrupt Flag" },
+  { M6811_OC4F,  "OC4F ", "Timer Output Compare 4 Interrupt Flag" },
+  { M6811_OC5F,  "OC5F ", "Timer Input Capture 4 / Output Compare 5 Flag" },
+  { M6811_IC1F,  "IC1F ", "Timer Input Capture 1 Interrupt Flag" },
+  { M6811_IC2F,  "IC2F ", "Timer Input Capture 2 Interrupt Flag" },
+  { M6811_IC3F,  "IC3F ", "Timer Input Capture 3 Interrupt Flag" },
+  { 0, 0, 0 }
+};
+
 io_reg_desc tmsk2_desc[] = {
   { M6811_TOI,    "TOI   ", "Timer Overflow Interrupt Enable" },
   { M6811_RTII,   "RTII  ", "RTI Interrupt Enable" },
@@ -358,6 +475,39 @@ to_realtime (sim_cpu *cpu, signed64 t)
   return (double) (t) / (double) (cpu->cpu_frequency / 4);
 }
 
+const char*
+cycle_to_string (sim_cpu *cpu, signed64 t, int flags)
+{
+  char time_buf[32];
+  char cycle_buf[32];
+  static char buf[64];
+
+  time_buf[0] = 0;
+  cycle_buf[0] = 0;
+  if (flags & PRINT_TIME)
+    {
+      double dt;
+
+      dt = to_realtime (cpu, t);
+      if (dt < 0.001)
+        sprintf (time_buf, " (%3.1f us)", dt * 1000000.0);
+      else if (dt < 1.0)
+        sprintf (time_buf, " (%3.1f ms)", dt * 1000.0);
+      else
+        sprintf (time_buf, " (%3.1f s)", dt);
+    }
+
+  if (flags & PRINT_CYCLE)
+    sprintf (cycle_buf, " cycle%s",
+             (t > 1 ? "s" : ""));
+
+  if (t < LONG_MAX)
+    sprintf (buf, "%9lu%s%s", (unsigned long) t, cycle_buf, time_buf);
+  else
+    sprintf (buf, "%llu%s%s", t, cycle_buf, time_buf);
+  return buf;
+}
+
 static void
 m68hc11tim_print_timer (struct hw *me, const char *name,
                         struct hw_event *event)
@@ -372,15 +522,13 @@ m68hc11tim_print_timer (struct hw *me, const char *name,
   else
     {
       signed64 t;
-      double dt;
       sim_cpu* cpu;
 
       cpu = STATE_CPU (sd, 0);
 
       t  = hw_event_remain_time (me, event);
-      dt = to_realtime (cpu, t) * 1000.0;
-      sim_io_printf (sd, "  Next %s interrupt in %ld cycles (%3.3f ms)\n",
-                     name, (long) t, dt);
+      sim_io_printf (sd, "  Next %s interrupt in %s\n",
+                     name, cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE));
     }
 }
 
@@ -392,6 +540,7 @@ m68hc11tim_info (struct hw *me)
   sim_cpu *cpu;
   struct m68hc11tim *controller;
   uint8 val;
+  uint16 val16;
   
   sd = hw_system (me);
   cpu = STATE_CPU (sd, 0);
@@ -401,6 +550,56 @@ m68hc11tim_info (struct hw *me)
 
   base = cpu_get_io_base (cpu);
 
+  /* Info for TIC1 */
+  val16  = (cpu->ios[M6811_TIC1_H] << 8) + cpu->ios[M6811_TIC1_L];
+  print_io_word (sd, "TIC1 ", 0, val16, base + M6811_TIC1);
+  sim_io_printf (sd, "\n");
+
+  /* Info for TIC2 */
+  val16  = (cpu->ios[M6811_TIC2_H] << 8) + cpu->ios[M6811_TIC2_L];
+  print_io_word (sd, "TIC2 ", 0, val16, base + M6811_TIC2);
+  sim_io_printf (sd, "\n");
+
+  /* Info for TIC3 */
+  val16  = (cpu->ios[M6811_TIC3_H] << 8) + cpu->ios[M6811_TIC3_L];
+  print_io_word (sd, "TIC3 ", 0, val16, base + M6811_TIC3);
+  sim_io_printf (sd, "\n");
+
+  /* Info for TOC1 */
+  val16  = (cpu->ios[M6811_TOC1_H] << 8) + cpu->ios[M6811_TOC1_L];
+  print_io_word (sd, "TOC1 ", 0, val16, base + M6811_TOC1);
+  sim_io_printf (sd, "\n");
+
+  /* Info for TOC2 */
+  val16  = (cpu->ios[M6811_TOC2_H] << 8) + cpu->ios[M6811_TOC2_L];
+  print_io_word (sd, "TOC2 ", 0, val16, base + M6811_TOC2);
+  sim_io_printf (sd, "\n");
+
+  /* Info for TOC3 */
+  val16  = (cpu->ios[M6811_TOC3_H] << 8) + cpu->ios[M6811_TOC3_L];
+  print_io_word (sd, "TOC3 ", 0, val16, base + M6811_TOC3);
+  sim_io_printf (sd, "\n");
+
+  /* Info for TOC4 */
+  val16  = (cpu->ios[M6811_TOC4_H] << 8) + cpu->ios[M6811_TOC4_L];
+  print_io_word (sd, "TOC4 ", 0, val16, base + M6811_TOC4);
+  sim_io_printf (sd, "\n");
+
+  /* Info for TOC5 */
+  val16  = (cpu->ios[M6811_TOC5_H] << 8) + cpu->ios[M6811_TOC5_L];
+  print_io_word (sd, "TOC5 ", 0, val16, base + M6811_TOC5);
+  sim_io_printf (sd, "\n");
+
+  /* Info for TMSK1 */
+  val  = cpu->ios[M6811_TMSK1];
+  print_io_byte (sd, "TMSK1 ", tmsk1_desc, val, base + M6811_TMSK1);
+  sim_io_printf (sd, "\n");
+
+  /* Info for TFLG1 */
+  val = cpu->ios[M6811_TFLG1];
+  print_io_byte (sd, "TFLG1", tflg1_desc, val, base + M6811_TFLG1);
+  sim_io_printf (sd, "\n");
+
   val  = cpu->ios[M6811_TMSK2];
   print_io_byte (sd, "TMSK2 ", tmsk2_desc, val, base + M6811_TMSK2);
   sim_io_printf (sd, "\n");
@@ -413,6 +612,10 @@ m68hc11tim_info (struct hw *me)
   print_io_byte (sd, "PACTL", pactl_desc, val, base + M6811_PACTL);
   sim_io_printf (sd, "\n");
 
+  val = cpu->ios[M6811_PACNT];
+  print_io_byte (sd, "PACNT", 0, val, base + M6811_PACNT);
+  sim_io_printf (sd, "\n");
+
   /* Give info about the next timer interrupts.  */
   m68hc11tim_print_timer (me, "RTI", controller->rti_timer_event);
   m68hc11tim_print_timer (me, "COP", controller->cop_timer_event);
@@ -442,6 +645,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 +653,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 = (char*) dest + 1;
+      base++;
+      nr_bytes--;
+      cnt++;
     }
-  *((unsigned8*) dest) = val;
-  return 1;
+  return cnt;
 }
 
 static unsigned
@@ -485,109 +696,128 @@ 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;
+          /* 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;
+              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;
-        case M6811_PR0:
-          n = 4;
+
+        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;
-        case M6811_PR1:
-          n = 8;
+      
+        case M6811_TFLG2:
+          val &= cpu->ios[M6811_TFLG2];
+          cpu->ios[M6811_TFLG2] &= ~val;
+          interrupts_update_pending (&cpu->cpu_interrupts);
           break;
-        default:
-        case M6811_PR1 | M6811_PR0:
-          n = 16;
+
+        case M6811_TMSK1:
+          cpu->ios[M6811_TMSK1] = val;
+          interrupts_update_pending (&cpu->cpu_interrupts);
+          reset_compare = 1;
           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_TFLG1:
+          val &= cpu->ios[M6811_TFLG1];
+          cpu->ios[M6811_TFLG1] &= ~val;
+          interrupts_update_pending (&cpu->cpu_interrupts);          
+          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_TOC1:
+        case M6811_TOC2:
+        case M6811_TOC3:
+        case M6811_TOC4:
+        case M6811_TOC5:
+          cpu->ios[base] = val;
+          reset_compare = 1;
+          break;
 
-      /* Clear the Real Time interrupt flag. */
-      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;
+        case M6811_TCTL1:
+        case M6811_TCTL2:
+          cpu->ios[base] = val;
+          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:
+          cpu->ios[base] = val;
+          break;
+        }
+
+      base++;
+      nr_bytes--;
+      cnt++;
+      source = (char*) source + 1;
     }
 
   /* Re-compute the next timer compare event.  */
@@ -595,12 +825,17 @@ 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;
 }     
 
 
 const struct hw_descriptor dv_m68hc11tim_descriptor[] = {
-  { "m68hc11tim", m68hc11tim_finish, },
+  { "m68hc11tim", m68hc11tim_finish },
+  { "m68hc12tim", m68hc11tim_finish },
   { NULL },
 };
 
This page took 0.039806 seconds and 4 git commands to generate.