]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - sim/m68hc11/interp.c
Switch the license of all files explicitly copyright the FSF
[thirdparty/binutils-gdb.git] / sim / m68hc11 / interp.c
index e04399236fab09e0c0c3de709fcddda1d4c3a7cd..9b1360819f123d0b21510db4c7f6ffef88a6cc53 100644 (file)
@@ -1,22 +1,22 @@
-/* interp.c -- Simulator for Motorola 68HC11
-   Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
-   Written by Stephane Carrez (stcarrez@worldnet.fr)
+/* interp.c -- Simulator for Motorola 68HC11/68HC12
+   Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2007
+   Free Software Foundation, Inc.
+   Written by Stephane Carrez (stcarrez@nerim.fr)
 
 This file is part of 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 version 2, or (at your option)
-any later version.
+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.  */
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "sim-main.h"
 #include "sim-assert.h"
@@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "hw-tree.h"
 #include "hw-device.h"
 #include "hw-ports.h"
+#include "elf32-m68hc1x.h"
 
 #ifndef MONITOR_BASE
 # define MONITOR_BASE (0x0C000)
@@ -166,12 +167,11 @@ sim_board_reset (SIM_DESC sd)
   cpu_restart (cpu);
 }
 
-int
+static int
 sim_hw_configure (SIM_DESC sd)
 {
   const struct bfd_arch_info *arch;
   struct hw *device_tree;
-  int m6811_mode;
   sim_cpu *cpu;
   
   arch = STATE_ARCHITECTURE (sd);
@@ -195,8 +195,17 @@ sim_hw_configure (SIM_DESC sd)
          sim_do_commandf (sd, "memory region 0x000@%d,0x8000",
                           M6811_RAM_LEVEL);
          sim_hw_parse (sd, "/m68hc11/reg 0x1000 0x03F");
+          if (cpu->bank_start < cpu->bank_end)
+            {
+              sim_do_commandf (sd, "memory region 0x%lx@%d,0x100000",
+                               cpu->bank_virtual, M6811_RAM_LEVEL);
+              sim_hw_parse (sd, "/m68hc11/use_bank 1");
+            }
        }
-
+      if (cpu->cpu_start_mode)
+        {
+          sim_hw_parse (sd, "/m68hc11/mode %s", cpu->cpu_start_mode);
+        }
       if (hw_tree_find_property (device_tree, "/m68hc11/m68hc11sio/reg") == 0)
        {
          sim_hw_parse (sd, "/m68hc11/m68hc11sio/reg 0x2b 0x5");
@@ -208,6 +217,7 @@ sim_hw_configure (SIM_DESC sd)
          /* M68hc11 Timer configuration. */
          sim_hw_parse (sd, "/m68hc11/m68hc11tim/reg 0x1b 0x5");
          sim_hw_parse (sd, "/m68hc11 > cpu-reset reset /m68hc11/m68hc11tim");
+          sim_hw_parse (sd, "/m68hc11 > capture capture /m68hc11/m68hc11tim");
        }
 
       /* Create the SPI device.  */
@@ -229,6 +239,11 @@ sim_hw_configure (SIM_DESC sd)
          sim_hw_parse (sd, "/m68hc11/m68hc11eepr/reg 0xb000 512");
          sim_hw_parse (sd, "/m68hc11 > cpu-reset reset /m68hc11/m68hc11eepr");
        }
+      sim_hw_parse (sd, "/m68hc11 > port-a cpu-write-port /m68hc11");
+      sim_hw_parse (sd, "/m68hc11 > port-b cpu-write-port /m68hc11");
+      sim_hw_parse (sd, "/m68hc11 > port-c cpu-write-port /m68hc11");
+      sim_hw_parse (sd, "/m68hc11 > port-d cpu-write-port /m68hc11");
+      cpu->hw_cpu = sim_hw_parse (sd, "/m68hc11");
     }
   else
     {
@@ -240,7 +255,12 @@ sim_hw_configure (SIM_DESC sd)
                           0x8000, M6811_RAM_LEVEL, 0x8000);
          sim_do_commandf (sd, "memory region 0x000@%d,0x8000",
                           M6811_RAM_LEVEL);
-
+          if (cpu->bank_start < cpu->bank_end)
+            {
+              sim_do_commandf (sd, "memory region 0x%lx@%d,0x100000",
+                               cpu->bank_virtual, M6811_RAM_LEVEL);
+              sim_hw_parse (sd, "/m68hc12/use_bank 1");
+            }
          sim_hw_parse (sd, "/m68hc12/reg 0x0 0x3FF");
        }
 
@@ -250,17 +270,12 @@ sim_hw_configure (SIM_DESC sd)
          sim_hw_parse (sd, "/m68hc12/m68hc12sio@1/backend stdio");
          sim_hw_parse (sd, "/m68hc12 > cpu-reset reset /m68hc12/m68hc12sio@1");
        }
-      if (!hw_tree_find_property (device_tree, "/m68hc12/m68hc12sio@2/reg"))
-       {
-         sim_hw_parse (sd, "/m68hc12/m68hc12sio@2/reg 0xC8 0x8");
-         sim_hw_parse (sd, "/m68hc12/m68hc12sio@2/backend tcp");
-         sim_hw_parse (sd, "/m68hc12 > cpu-reset reset /m68hc12/m68hc12sio@2");
-       }
       if (hw_tree_find_property (device_tree, "/m68hc12/m68hc12tim/reg") == 0)
        {
          /* M68hc11 Timer configuration. */
          sim_hw_parse (sd, "/m68hc12/m68hc12tim/reg 0x1b 0x5");
          sim_hw_parse (sd, "/m68hc12 > cpu-reset reset /m68hc12/m68hc12tim");
+          sim_hw_parse (sd, "/m68hc12 > capture capture /m68hc12/m68hc12tim");
        }
 
       /* Create the SPI device.  */
@@ -281,23 +296,122 @@ sim_hw_configure (SIM_DESC sd)
          sim_hw_parse (sd, "/m68hc12/m68hc12eepr/reg 0x0800 2048");
          sim_hw_parse (sd, "/m68hc12 > cpu-reset reset /m68hc12/m68hc12eepr");
        }
+
+      sim_hw_parse (sd, "/m68hc12 > port-a cpu-write-port /m68hc12");
+      sim_hw_parse (sd, "/m68hc12 > port-b cpu-write-port /m68hc12");
+      sim_hw_parse (sd, "/m68hc12 > port-c cpu-write-port /m68hc12");
+      sim_hw_parse (sd, "/m68hc12 > port-d cpu-write-port /m68hc12");
+      cpu->hw_cpu = sim_hw_parse (sd, "/m68hc12");
     }
+  return 1;
+}
+
+/* Get the memory bank parameters by looking at the global symbols
+   defined by the linker.  */
+static int
+sim_get_bank_parameters (SIM_DESC sd, bfd* abfd)
+{
+  sim_cpu *cpu;
+  long symsize;
+  long symbol_count, i;
+  unsigned size;
+  asymbol** asymbols;
+  asymbol** current;
+
+  cpu = STATE_CPU (sd, 0);
+
+  symsize = bfd_get_symtab_upper_bound (abfd);
+  if (symsize < 0)
+    {
+      sim_io_eprintf (sd, "Cannot read symbols of program");
+      return 0;
+    }
+  asymbols = (asymbol **) xmalloc (symsize);
+  symbol_count = bfd_canonicalize_symtab (abfd, asymbols);
+  if (symbol_count < 0)
+    {
+      sim_io_eprintf (sd, "Cannot read symbols of program");
+      return 0;
+    }
+
+  size = 0;
+  for (i = 0, current = asymbols; i < symbol_count; i++, current++)
+    {
+      const char* name = bfd_asymbol_name (*current);
+
+      if (strcmp (name, BFD_M68HC11_BANK_START_NAME) == 0)
+        {
+          cpu->bank_start = bfd_asymbol_value (*current);
+        }
+      else if (strcmp (name, BFD_M68HC11_BANK_SIZE_NAME) == 0)
+        {
+          size = bfd_asymbol_value (*current);
+        }
+      else if (strcmp (name, BFD_M68HC11_BANK_VIRTUAL_NAME) == 0)
+        {
+          cpu->bank_virtual = bfd_asymbol_value (*current);
+        }
+    }
+  free (asymbols);
+
+  cpu->bank_end = cpu->bank_start + size;
+  cpu->bank_shift = 0;
+  for (; size > 1; size >>= 1)
+    cpu->bank_shift++;
+
   return 0;
 }
 
 static int
-sim_prepare_for_program (SIM_DESC sd, struct _bfd* abfd)
+sim_prepare_for_program (SIM_DESC sd, bfd* abfd)
 {
   sim_cpu *cpu;
+  int elf_flags = 0;
 
   cpu = STATE_CPU (sd, 0);
 
-  sim_hw_configure (sd);
   if (abfd != NULL)
     {
+      asection *s;
+
+      if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
+        elf_flags = elf_elfheader (abfd)->e_flags;
+
       cpu->cpu_elf_start = bfd_get_start_address (abfd);
+      /* See if any section sets the reset address */
+      cpu->cpu_use_elf_start = 1;
+      for (s = abfd->sections; s && cpu->cpu_use_elf_start; s = s->next) 
+        {
+          if (s->flags & SEC_LOAD)
+            {
+              bfd_size_type size;
+
+              size = bfd_get_section_size (s);
+              if (size > 0)
+                {
+                  bfd_vma lma;
+
+                  if (STATE_LOAD_AT_LMA_P (sd))
+                    lma = bfd_section_lma (abfd, s);
+                  else
+                    lma = bfd_section_vma (abfd, s);
+
+                  if (lma <= 0xFFFE && lma+size >= 0x10000)
+                    cpu->cpu_use_elf_start = 0;
+                }
+            }
+        }
+
+      if (elf_flags & E_M68HC12_BANKS)
+        {
+          if (sim_get_bank_parameters (sd, abfd) != 0)
+            sim_io_eprintf (sd, "Memory bank parameters are not initialized\n");
+        }
     }
 
+  if (!sim_hw_configure (sd))
+    return SIM_RC_FAIL;
+
   /* reset all state information */
   sim_board_reset (sd);
 
@@ -306,12 +420,10 @@ sim_prepare_for_program (SIM_DESC sd, struct _bfd* abfd)
 
 SIM_DESC
 sim_open (SIM_OPEN_KIND kind, host_callback *callback,
-          struct _bfd *abfd, char **argv)
+          bfd *abfd, char **argv)
 {
-  char **p;
   SIM_DESC sd;
   sim_cpu *cpu;
-  struct hw *device_tree;
 
   sd = sim_state_alloc (kind, callback);
   cpu = STATE_CPU (sd, 0);
@@ -324,7 +436,6 @@ sim_open (SIM_OPEN_KIND kind, host_callback *callback,
 
   cpu_initialize (sd, cpu);
 
-  cpu->cpu_use_elf_start = 1;
   if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
     {
       free_state (sd);
@@ -366,8 +477,11 @@ sim_open (SIM_OPEN_KIND kind, host_callback *callback,
       free_state (sd);
       return 0;
     }
-
-  sim_hw_configure (sd);
+  if (sim_prepare_for_program (sd, abfd) != SIM_RC_OK)
+    {
+      free_state (sd);
+      return 0;
+    }      
 
   /* Fudge our descriptor.  */
   return sd;
@@ -437,6 +551,10 @@ sim_info (SIM_DESC sd, int verbose)
   const char *cpu_type;
   const struct bfd_arch_info *arch;
 
+  /* Nothing to do if there is no verbose flag set.  */
+  if (verbose == 0 && STATE_VERBOSE_P (sd) == 0)
+    return;
+
   arch = STATE_ARCHITECTURE (sd);
   if (arch->arch == bfd_arch_m68hc11)
     cpu_type = "68HC11";
@@ -450,7 +568,7 @@ sim_info (SIM_DESC sd, int verbose)
 }
 
 SIM_RC
-sim_create_inferior (SIM_DESC sd, struct _bfd *abfd,
+sim_create_inferior (SIM_DESC sd, struct bfd *abfd,
                      char **argv, char **env)
 {
   return sim_prepare_for_program (sd, abfd);
@@ -469,16 +587,19 @@ sim_fetch_register (SIM_DESC sd, int rn, unsigned char *memory, int length)
 {
   sim_cpu *cpu;
   uint16 val;
+  int size = 2;
 
   cpu = STATE_CPU (sd, 0);
   switch (rn)
     {
     case A_REGNUM:
       val = cpu_get_a (cpu);
+      size = 1;
       break;
 
     case B_REGNUM:
       val = cpu_get_b (cpu);
+      size = 1;
       break;
 
     case D_REGNUM:
@@ -503,15 +624,28 @@ sim_fetch_register (SIM_DESC sd, int rn, unsigned char *memory, int length)
 
     case PSW_REGNUM:
       val = cpu_get_ccr (cpu);
+      size = 1;
+      break;
+
+    case PAGE_REGNUM:
+      val = cpu_get_page (cpu);
+      size = 1;
       break;
 
     default:
       val = 0;
       break;
     }
-  memory[0] = val >> 8;
-  memory[1] = val & 0x0FF;
-  return 2;
+  if (size == 1)
+    {
+      memory[0] = val;
+    }
+  else
+    {
+      memory[0] = val >> 8;
+      memory[1] = val & 0x0FF;
+    }
+  return size;
 }
 
 int
@@ -534,11 +668,11 @@ sim_store_register (SIM_DESC sd, int rn, unsigned char *memory, int length)
 
     case A_REGNUM:
       cpu_set_a (cpu, val);
-      break;
+      return 1;
 
     case B_REGNUM:
       cpu_set_b (cpu, val);
-      break;
+      return 1;
 
     case X_REGNUM:
       cpu_set_x (cpu, val);
@@ -558,7 +692,11 @@ sim_store_register (SIM_DESC sd, int rn, unsigned char *memory, int length)
 
     case PSW_REGNUM:
       cpu_set_ccr (cpu, val);
-      break;
+      return 1;
+
+    case PAGE_REGNUM:
+      cpu_set_page (cpu, val);
+      return 1;
 
     default:
       break;
@@ -586,8 +724,6 @@ sim_do_command (SIM_DESC sd, char *cmd)
     {
       if (strncmp (cmd, "info", sizeof ("info") - 1) == 0)
        sim_get_info (sd, &cmd[4]);
-      else if (strncmp (cmd, "frame", sizeof ("frame") - 1) == 0)
-       cpu_print_frame (sd, STATE_CPU (sd, 0));
       else if (strncmp (cmd, mm_cmd, strlen (mm_cmd) == 0))
        sim_io_eprintf (sd,
                        "`memory-map' command replaced by `sim memory'\n");
@@ -601,3 +737,79 @@ sim_do_command (SIM_DESC sd, char *cmd)
   if (STATE_ARCHITECTURE (sd) != cpu->cpu_configured_arch)
     sim_hw_configure (sd);
 }
+
+/* Halt the simulator after just one instruction */
+
+static void
+has_stepped (SIM_DESC sd,
+            void *data)
+{
+  ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
+  sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_stopped, SIM_SIGTRAP);
+}
+
+
+/* Generic resume - assumes the existance of sim_engine_run */
+
+void
+sim_resume (SIM_DESC sd,
+           int step,
+           int siggnal)
+{
+  sim_engine *engine = STATE_ENGINE (sd);
+  jmp_buf buf;
+  int jmpval;
+
+  ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
+
+  /* we only want to be single stepping the simulator once */
+  if (engine->stepper != NULL)
+    {
+      sim_events_deschedule (sd, engine->stepper);
+      engine->stepper = NULL;
+    }
+  sim_module_resume (sd);
+
+  /* run/resume the simulator */
+  engine->jmpbuf = &buf;
+  jmpval = setjmp (buf);
+  if (jmpval == sim_engine_start_jmpval
+      || jmpval == sim_engine_restart_jmpval)
+    {
+      int last_cpu_nr = sim_engine_last_cpu_nr (sd);
+      int next_cpu_nr = sim_engine_next_cpu_nr (sd);
+      int nr_cpus = sim_engine_nr_cpus (sd);
+
+      sim_events_preprocess (sd, last_cpu_nr >= nr_cpus, next_cpu_nr >= nr_cpus);
+      if (next_cpu_nr >= nr_cpus)
+       next_cpu_nr = 0;
+
+      /* Only deliver the siggnal ]sic] the first time through - don't
+         re-deliver any siggnal during a restart. */
+      if (jmpval == sim_engine_restart_jmpval)
+       siggnal = 0;
+
+      /* Install the stepping event after having processed some
+         pending events.  This is necessary for HC11/HC12 simulator
+         because the tick counter is incremented by the number of cycles
+         the instruction took.  Some pending ticks to process can still
+         be recorded internally by the simulator and sim_events_preprocess
+         will handle them.  If the stepping event is inserted before,
+         these pending ticks will raise the event and the simulator will
+         stop without having executed any instruction.  */
+      if (step)
+        engine->stepper = sim_events_schedule (sd, 0, has_stepped, sd);
+
+#ifdef SIM_CPU_EXCEPTION_RESUME
+      {
+       sim_cpu* cpu = STATE_CPU (sd, next_cpu_nr);
+       SIM_CPU_EXCEPTION_RESUME(sd, cpu, siggnal);
+      }
+#endif
+
+      sim_engine_run (sd, next_cpu_nr, nr_cpus, siggnal);
+    }
+  engine->jmpbuf = NULL;
+
+  sim_module_suspend (sd);
+}