]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - sim/m68hc11/dv-m68hc11tim.c
sim: m68hc11: fix up cycle buffer printing
[thirdparty/binutils-gdb.git] / sim / m68hc11 / dv-m68hc11tim.c
index 9b0f3385f8c9af0f903e376d0fff0f13586f7a68..d7bcac3fecadeaabdf2804ae1b0e617bb3af42f2 100644 (file)
@@ -1,23 +1,22 @@
 /*  dv-m68hc11tim.c -- Simulation of the 68HC11 timer devices.
-    Copyright (C) 1999, 2000, 2002 Free Software Foundation, Inc.
-    Written by Stephane Carrez (stcarrez@worldnet.fr)
+    Copyright (C) 1999-2021 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.
     
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either vertimn 2 of the License, or
-    (at your option) any later vertimn.
-    
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
     This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.
-    
+
     You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
     
     */
 
@@ -25,7 +24,7 @@
 #include "sim-main.h"
 #include "hw-main.h"
 #include "sim-assert.h"
-
+#include <limits.h>
 
 /* DEVICE
 
@@ -194,12 +193,12 @@ 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;
@@ -237,7 +236,7 @@ enum event_type
   COMPARE_EVENT
 };
 
-void
+static void
 m68hc11tim_timer_event (struct hw *me, void *data)
 {
   SIM_DESC sd;
@@ -250,7 +249,9 @@ m68hc11tim_timer_event (struct hw *me, void *data)
   unsigned mask;
   unsigned flags;
   unsigned long tcnt_internal;
-  unsigned long tcnt;
+  unsigned long tcnt, tcnt_prev;
+  signed64 tcnt_insn_end;
+  signed64 tcnt_insn_start;
   int i;
   sim_events *events;
   
@@ -289,11 +290,8 @@ m68hc11tim_timer_event (struct hw *me, void *data)
       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;
+      /* 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).  */
@@ -316,22 +314,22 @@ m68hc11tim_timer_event (struct hw *me, void *data)
       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);
 
-      /* 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;
+      /* 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 visible TCNT register value.  */
-      tcnt = tcnt_internal / controller->clock_prescaler;
-      
       flags = cpu->ios[M6811_TMSK1];
       mask  = 0x80;
       delay = 65536 * controller->clock_prescaler;
@@ -342,12 +340,28 @@ m68hc11tim_timer_event (struct hw *me, void *data)
       for (i = M6811_TOC1; i <= M6811_TOC5; i += 2, mask >>= 1)
         {
           unsigned long compare;
-          
-          compare = (cpu->ios[i] << 8) + cpu->ios[i+1];
-          if (compare == tcnt && (flags & mask))
+
+          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.
@@ -359,14 +373,18 @@ m68hc11tim_timer_event (struct hw *me, void *data)
           else
             compare = compare - tcnt_internal
               + 65536 * controller->clock_prescaler;
-          
+
           if (compare < delay)
             delay = compare;
         }
 
       /* 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:
@@ -394,6 +412,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" },
@@ -433,20 +475,33 @@ to_realtime (sim_cpu *cpu, signed64 t)
 }
 
 const char*
-cycle_to_string (sim_cpu *cpu, signed64 t)
+cycle_to_string (sim_cpu *cpu, signed64 t, int flags)
 {
-  double dt;
-  static char buf[64];
-  
-  dt = to_realtime (cpu, t);
-  if (dt < 0.001)
-    sprintf (buf, "%llu cycle%s (%3.1f us)", t,
-             (t > 1 ? "s" : ""), dt * 1000000.0);
-  else if (dt < 1.0)
-    sprintf (buf, "%llu cycles (%3.1f ms)", t, dt * 1000.0);
-  else
-    sprintf (buf, "%llu cycles (%3.1f s)", t, dt);
+  char time_buf[32];
+  char cycle_buf[32];
+  /* Big enough to handle 64-bit t, time_buf, and cycle_buf.  */
+  static char buf[128];
+
+  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" : ""));
+
+  sprintf (buf, "%9" PRIi64 "%s%s", t, cycle_buf, time_buf);
   return buf;
 }
 
@@ -464,13 +519,13 @@ m68hc11tim_print_timer (struct hw *me, const char *name,
   else
     {
       signed64 t;
-      sim_cpucpu;
+      sim_cpu *cpu;
 
       cpu = STATE_CPU (sd, 0);
 
       t  = hw_event_remain_time (me, event);
       sim_io_printf (sd, "  Next %s interrupt in %s\n",
-                     name, cycle_to_string (cpu, t));
+                     name, cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE));
     }
 }
 
@@ -482,6 +537,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);
@@ -491,6 +547,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");
@@ -503,6 +609,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);
@@ -562,7 +672,7 @@ m68hc11tim_io_read_buffer (struct hw *me,
           break;
         }
       *((unsigned8*) dest) = val;
-      dest++;
+      dest = (char*) dest + 1;
       base++;
       nr_bytes--;
       cnt++;
@@ -625,7 +735,7 @@ m68hc11tim_io_write_buffer (struct hw *me,
 
         case M6811_TMSK2:
 
-      /* Timer prescaler cannot be changed after 64 bus cycles.  */
+          /* Timer prescaler cannot be changed after 64 bus cycles.  */
           if (cpu->cpu_absolute_cycle >= 64)
             {
               val &= ~(M6811_PR1 | M6811_PR0);
@@ -665,19 +775,21 @@ m68hc11tim_io_write_buffer (struct hw *me,
           break;
       
         case M6811_TFLG2:
-          if (val & M6811_TOF)
-            val &= ~M6811_TOF;
-          else
-            val |= cpu->ios[M6811_TFLG2] & M6811_TOF;
+          val &= cpu->ios[M6811_TFLG2];
+          cpu->ios[M6811_TFLG2] &= ~val;
+          interrupts_update_pending (&cpu->cpu_interrupts);
+          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;
+        case M6811_TMSK1:
+          cpu->ios[M6811_TMSK1] = val;
           interrupts_update_pending (&cpu->cpu_interrupts);
+          reset_compare = 1;
+          break;
+
+        case M6811_TFLG1:
+          val &= cpu->ios[M6811_TFLG1];
+          cpu->ios[M6811_TFLG1] &= ~val;
+          interrupts_update_pending (&cpu->cpu_interrupts);          
           break;
 
         case M6811_TOC1:
@@ -688,15 +800,21 @@ m68hc11tim_io_write_buffer (struct hw *me,
           cpu->ios[base] = val;
           reset_compare = 1;
           break;
-      
+
+        case M6811_TCTL1:
+        case M6811_TCTL2:
+          cpu->ios[base] = val;
+          break;
+
         default:
+          cpu->ios[base] = val;
           break;
         }
 
       base++;
       nr_bytes--;
       cnt++;
-      source++;
+      source = (char*) source + 1;
     }
 
   /* Re-compute the next timer compare event.  */