OSDN Git Service

New simulator.
authorAndrew Cagney <cagney@redhat.com>
Thu, 27 Jul 2000 11:23:39 +0000 (11:23 +0000)
committerAndrew Cagney <cagney@redhat.com>
Thu, 27 Jul 2000 11:23:39 +0000 (11:23 +0000)
16 files changed:
sim/m68hc11/ChangeLog [new file with mode: 0644]
sim/m68hc11/config.in [new file with mode: 0644]
sim/m68hc11/configure.in [new file with mode: 0644]
sim/m68hc11/dv-m68hc11.c [new file with mode: 0644]
sim/m68hc11/dv-m68hc11eepr.c [new file with mode: 0644]
sim/m68hc11/dv-m68hc11sio.c [new file with mode: 0644]
sim/m68hc11/dv-m68hc11spi.c [new file with mode: 0644]
sim/m68hc11/dv-m68hc11tim.c [new file with mode: 0644]
sim/m68hc11/dv-nvram.c [new file with mode: 0644]
sim/m68hc11/emulos.c [new file with mode: 0644]
sim/m68hc11/gencode.c [new file with mode: 0644]
sim/m68hc11/interp.c [new file with mode: 0644]
sim/m68hc11/interrupts.c [new file with mode: 0644]
sim/m68hc11/interrupts.h [new file with mode: 0644]
sim/m68hc11/m68hc11_sim.c [new file with mode: 0644]
sim/m68hc11/sim-main.h [new file with mode: 0644]

diff --git a/sim/m68hc11/ChangeLog b/sim/m68hc11/ChangeLog
new file mode 100644 (file)
index 0000000..32698be
--- /dev/null
@@ -0,0 +1,178 @@
+2000-06-25  Stephane Carrez  <Stephane.Carrez@worldnet.fr>
+
+       * Makefile.in (SIM_RUN_OBJS): Define to use nrun.c
+       * dv-m68hc11.c (m68hc11cpu_finish): Register detach address callback.
+       (dv_m6811_detach_address_callback): New function to detach a
+       device from an address space.
+       * dv-m68hc11eepr.c (m68hc11eepr_port_event): Initialize
+       config register according to --cpu-config option.
+       * sim-main.h (_sim_cpu): Add cpu_config member.
+       * interp.c (sim_open): Delete specific simulator options.
+       * m68hc11_sim.c (cpu_option_handler): New options
+       --emulos and -cpu-config <val> to configure the simulator.
+       (cpu_initialize): Initialize cpu_config member.
+
+2000-06-24  Stephane Carrez  <Stephane.Carrez@worldnet.fr>
+
+       * emulos.c: Fix indentation and comments.
+       * gencode.c: Likewise.
+       * dv-m68hc11tim.c (m68hc11tim_timer_event): Handle COMPARE_EVENT.
+       (m68hc11tim_io_write_buffer): Write compare registers and
+       setup compare event.
+       * interp.c: Remove unused global variables.
+       * interrupts.c (idefs): New compare interrupts.
+       Fix indentation and comments.
+       * interrupts.h: Likewise.
+
+2000-06-18  Stephane Carrez  <Stephane.Carrez@worldnet.fr>
+
+       * dv-m68hc11sio.c: Fix indentation and comments.
+       Remove INT_PORT.
+       * dv-m68hc11.c: Fix indentation and comments.
+       (m68hc11cpu_port_event): Move initialization of M6811_HPRIO from here.
+       * m68hc11_sim.c (cpu_reset): To here.
+       * dv-m68hc11eepr.c: Fix indentation and comments.
+       
+2000-06-17  Stephane Carrez  <Stephane.Carrez@worldnet.fr>
+
+       * dv-nvram.c: New file, rename from dv-pram.c.
+       * dv-pram.c: Delete file.
+       * sim-main.h: Incorporate m68hc11_sim.h.
+       * m68hc11_sim.h: Delete file.
+       * configure.in: Rename pram into nvram.
+       * interp.c (sim_open): Likewise in creation of device tree.
+       
+2000-05-31  Stephane Carrez  <Stephane.Carrez@worldnet.fr>
+
+       * interp.c (sim_open): Create the SPI device.
+       * dv-m68hc11spi.c: New file for SPI device simulation.
+       * configure.in (hw_extra_devices): Add SPI device.
+
+2000-05-28  Stephane Carrez  <Stephane.Carrez@worldnet.fr>
+
+       * interrupts.c (interrupts_initialize): Clear XIRQ accounting.
+       (interrupts_process): Separate IRQ and XIRQ accounting.
+       (interrupts_info): Report XIRQ accounting.
+       * interrupts.h (struct interrupts): Added accounting for XIRQ.
+
+2000-04-16  Stephane Carrez  <stcarrez@worldnet.fr>
+
+       * dv-pram.c (attach_pram_regs): Fix the 'save-modified' mode.
+       * m68hc11_sim.h (_sim_cpu): Allow configuration of cpu mode.
+       * dv-m68hc11.c (attach_m68hc11_regs): Get the cpu MODA,MODB 
+       configuration from the 'mode' device tree property.
+       (m68hc11cpu_port_event): Reset M6811_HPRIO to the cpu MODA, MODB
+       configuration.
+
+2000-02-24  Stephane Carrez  <stcarrez@worldnet.fr>
+
+       * sim-main.h: Remove WITH_TARGET_* defines.
+       * Makefile.in (SIM_EXTRA_CFLAGS): Specify the WITH_TARGET_* flags.
+
+2000-02-08  Stephane Carrez  <stcarrez@worldnet.fr>
+
+       * dv-m68hc11sio.c (m68hc11sio_port_event): Setup the SCI to
+       1200 baud when cpu is in bootstrap mode.
+
+       * dv-m68hc11tim.c (m68hc11tim_io_write_buffer): Be able to
+       write in the TCTN timer register.
+
+       * dv-m68hc11sio.c (m68hc11sio_io_write_buffer): Divide cpu clock
+       by 4 to obtain the E clock frequency.
+       (sccr2_desc): Use M6811_TIE for TIE bit.
+       (m68hc11sio_info): Fix baud rate report.
+
+       * dv-m68hc11tim.c (to_realtime): Likewise.
+
+       * interp.c (sim_open): When building device tree, only provide
+       devices that do not exist yet.
+
+       * emulos.c: Fix compilation pb under Windows.
+
+       * dv-m68hc11.c (attach_m68hc11_regs): Get the clock frequency
+       from the 'clock' property.
+
+2000-01-02  Stephane Carrez  <stcarrez@worldnet.fr>
+
+       * m68hc11_sim.h (*_REGNUM): Define.
+       (_sim_cpu): New member cpu_page0_reg table.
+       * interp.c (sim_create_inferior): Fill the cpu_page0_reg table with
+       addresses of soft registers in .page0.
+       (sim_fetch_register, sim_store_register): Use cpu_page0_reg table 
+       to get/set soft registers.
+
+1999-12-31  Stephane Carrez  <stcarrez@worldnet.fr>
+
+       * dv-m68hc11.c (m68hc11cpu_io_write_buffer): Clear byte to avoid
+       returning random values.
+
+1999-12-17  Stephane Carrez  <stcarrez@worldnet.fr>
+
+       * gencode.c: Fix "subb N,x" that used a instead of b.
+
+1999-09-09  Stephane Carrez  <stcarrez@worldnet.fr>
+
+       * gencode.c: Fixed sbc8 and adc8 when there was a initial carry.
+
+1999-09-01  Stephane Carrez  <stcarrez@worldnet.fr>
+
+       * sim-main.h (SIM_HANDLES_LMA): Define to enable loading using lma.
+
+1999-08-14  Stephane Carrez  <stcarrez@worldnet.fr>
+
+       * dv-m68hc11.c (attach_m68hc11_regs): Save the size of the
+       register region in the m68hc11cpu struct.
+       (m68hc11cpu_io_write): When the IO mapping addres changes,
+       detach the register region and re-attach it at the new address.
+       (m68hc11cpu_io_read_buffer): Renamed base_address into
+       attach_address.
+       (m68hc11cpu_io_write_buffer): Likewise. Pass the hw pointer
+       to m68hc11cpu_io_write.
+
+1999-08-13  Stephane Carrez  <stcarrez@worldnet.fr>
+
+       * gencode.c: For sbc8, check the carry and increment the source
+       before trying to set the carry for the result.
+
+1999-05-24  John S. Kallal <kallal@voicenet.com>
+       
+       * interp.c (sim_get_info): Don't crash if the command line is 0.
+       Define prototype for sim_get_info() and init_system().
+       (sim_info): Correct call to sim_get_info().
+       
+1999-05-16  Stephane Carrez  <stcarrez@worldnet.fr>
+
+       * configure.in: Recognize m6811-*-*.
+       * configure: Regenerate.
+       * m68hc11_sim.h (cpu_ccr_update_add8, cpu_ccr_update_add16,
+       cpu_ccr_update_sub8, cpu_ccr_update_sub16):
+       Correct the computation of carry of 8 and 16-bits add and subtract.
+       * gencode.c: Use cpu_ccr_update_sub8 for subtraction (carry and
+       overflow set in a different manner than add).
+
+1999-05-14  Stephane Carrez  <stcarrez@worldnet.fr>
+
+       * dv-m68hc11.c (dv_m6811_attach_address_callback): Removed a
+       trace message.
+       * interp.c (sim_open, sim_create_inferior): Initialize the
+       cpu_elf_start from the ELF header.
+       * m68hc11_sim.c (cpu_initialize): Clear the new data members.
+       (cpu_restart): Use cpu_elf_start as the starting address when
+       the flag is set.
+       (cpu_special): When cpu_use_elf_start is set, the WAI instruction
+       exits the simulator (exit status is in D).
+       * m68hc11_sim.h (_sim_cpu): Added members cpu_use_elf_start and
+       cpu_elf_star to start execution at address specified in ELF file.
+
+1999-05-02  Stephane Carrez  <stcarrez@worldnet.fr>
+
+       * Makefile.in, config.in, configure, configure.in: New files.
+       * gencode.c: New file, generation of 68HC11 interpreter.
+       * m68hc11_sim.h, m68hc11_sim.c: New files, specific operations
+       for interpreter.
+       * interrupts.c, interrupts.h: New files, management of interrupts.
+       * interp.c, sim-main.h, 
+       * dv-m68hc11.c, dv-m68hc11eepr.c, dv-m68hc11sio.c,
+       dv-m68hc11tim.c, dv-pram.c: New files representing devices for
+       68HC11 (dv-pram.c is generic and could probably migrate to common).
+       * emulos.c: New file, basic emulation of some os.
diff --git a/sim/m68hc11/config.in b/sim/m68hc11/config.in
new file mode 100644 (file)
index 0000000..dbd6508
--- /dev/null
@@ -0,0 +1,174 @@
+/* config.in.  Generated automatically from configure.in by autoheader.  */
+
+/* Define if using alloca.c.  */
+#undef C_ALLOCA
+
+/* Define to empty if the keyword does not work.  */
+#undef const
+
+/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
+   This function is required for alloca.c support on those systems.  */
+#undef CRAY_STACKSEG_END
+
+/* Define if you have alloca, as a function or macro.  */
+#undef HAVE_ALLOCA
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix).  */
+#undef HAVE_ALLOCA_H
+
+/* Define if you have a working `mmap' system call.  */
+#undef HAVE_MMAP
+
+/* Define as __inline if that's what the C compiler calls it.  */
+#undef inline
+
+/* Define to `long' if <sys/types.h> doesn't define.  */
+#undef off_t
+
+/* Define if you need to in order for stat and other things to work.  */
+#undef _POSIX_SOURCE
+
+/* Define as the return type of signal handlers (int or void).  */
+#undef RETSIGTYPE
+
+/* Define to `unsigned' if <sys/types.h> doesn't define.  */
+#undef size_t
+
+/* If using the C implementation of alloca, define if you know the
+   direction of stack growth for your system; otherwise it will be
+   automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown
+ */
+#undef STACK_DIRECTION
+
+/* Define if you have the ANSI C header files.  */
+#undef STDC_HEADERS
+
+/* Define if your processor stores words with the most significant
+   byte first (like Motorola and SPARC, unlike Intel and VAX).  */
+#undef WORDS_BIGENDIAN
+
+/* Define to 1 if NLS is requested.  */
+#undef ENABLE_NLS
+
+/* Define as 1 if you have gettext and don't want to use GNU gettext.  */
+#undef HAVE_GETTEXT
+
+/* Define as 1 if you have the stpcpy function.  */
+#undef HAVE_STPCPY
+
+/* Define if your locale.h file contains LC_MESSAGES.  */
+#undef HAVE_LC_MESSAGES
+
+/* Define if you have the __argz_count function.  */
+#undef HAVE___ARGZ_COUNT
+
+/* Define if you have the __argz_next function.  */
+#undef HAVE___ARGZ_NEXT
+
+/* Define if you have the __argz_stringify function.  */
+#undef HAVE___ARGZ_STRINGIFY
+
+/* Define if you have the __setfpucw function.  */
+#undef HAVE___SETFPUCW
+
+/* Define if you have the aint function.  */
+#undef HAVE_AINT
+
+/* Define if you have the anint function.  */
+#undef HAVE_ANINT
+
+/* Define if you have the dcgettext function.  */
+#undef HAVE_DCGETTEXT
+
+/* Define if you have the getcwd function.  */
+#undef HAVE_GETCWD
+
+/* Define if you have the getpagesize function.  */
+#undef HAVE_GETPAGESIZE
+
+/* Define if you have the getrusage function.  */
+#undef HAVE_GETRUSAGE
+
+/* Define if you have the munmap function.  */
+#undef HAVE_MUNMAP
+
+/* Define if you have the putenv function.  */
+#undef HAVE_PUTENV
+
+/* Define if you have the setenv function.  */
+#undef HAVE_SETENV
+
+/* Define if you have the setlocale function.  */
+#undef HAVE_SETLOCALE
+
+/* Define if you have the sigaction function.  */
+#undef HAVE_SIGACTION
+
+/* Define if you have the sqrt function.  */
+#undef HAVE_SQRT
+
+/* Define if you have the stpcpy function.  */
+#undef HAVE_STPCPY
+
+/* Define if you have the strcasecmp function.  */
+#undef HAVE_STRCASECMP
+
+/* Define if you have the strchr function.  */
+#undef HAVE_STRCHR
+
+/* Define if you have the time function.  */
+#undef HAVE_TIME
+
+/* Define if you have the <argz.h> header file.  */
+#undef HAVE_ARGZ_H
+
+/* Define if you have the <fcntl.h> header file.  */
+#undef HAVE_FCNTL_H
+
+/* Define if you have the <fpu_control.h> header file.  */
+#undef HAVE_FPU_CONTROL_H
+
+/* Define if you have the <limits.h> header file.  */
+#undef HAVE_LIMITS_H
+
+/* Define if you have the <locale.h> header file.  */
+#undef HAVE_LOCALE_H
+
+/* Define if you have the <malloc.h> header file.  */
+#undef HAVE_MALLOC_H
+
+/* Define if you have the <nl_types.h> header file.  */
+#undef HAVE_NL_TYPES_H
+
+/* Define if you have the <stdlib.h> header file.  */
+#undef HAVE_STDLIB_H
+
+/* Define if you have the <string.h> header file.  */
+#undef HAVE_STRING_H
+
+/* Define if you have the <strings.h> header file.  */
+#undef HAVE_STRINGS_H
+
+/* Define if you have the <sys/param.h> header file.  */
+#undef HAVE_SYS_PARAM_H
+
+/* Define if you have the <sys/resource.h> header file.  */
+#undef HAVE_SYS_RESOURCE_H
+
+/* Define if you have the <sys/time.h> header file.  */
+#undef HAVE_SYS_TIME_H
+
+/* Define if you have the <time.h> header file.  */
+#undef HAVE_TIME_H
+
+/* Define if you have the <unistd.h> header file.  */
+#undef HAVE_UNISTD_H
+
+/* Define if you have the <values.h> header file.  */
+#undef HAVE_VALUES_H
+
+/* Define if you have the m library (-lm).  */
+#undef HAVE_LIBM
diff --git a/sim/m68hc11/configure.in b/sim/m68hc11/configure.in
new file mode 100644 (file)
index 0000000..78dee58
--- /dev/null
@@ -0,0 +1,35 @@
+dnl Process this file with autoconf to produce a configure script.
+sinclude(../common/aclocal.m4)
+AC_PREREQ(2.12.1)dnl
+AC_INIT(Makefile.in)
+
+SIM_AC_COMMON
+
+dnl Options available in this module
+SIM_AC_OPTION_INLINE()
+SIM_AC_OPTION_ALIGNMENT(NONSTRICT_ALIGNMENT)
+SIM_AC_OPTION_HOSTENDIAN
+SIM_AC_OPTION_WARNINGS
+
+#
+# Add simulated hardware devices
+#
+hw_enabled=no
+case "${target}" in
+  m68hc11-*-*|m6811-*-*)
+       hw_enabled=yes
+       hw_extra_devices="m68hc11 m68hc11sio m68hc11eepr m68hc11tim m68hc11spi nvram"
+       m68hc11_extra_objs="dv-sockser.o"
+       SIM_SUBTARGET="$SIM_SUBTARGET -DTARGET_M68HC11=1"
+       ;;
+  *)
+       m68hc11_extra_objs="" 
+       ;;
+esac
+SIM_AC_OPTION_HARDWARE($hw_enabled,$hw_devices,$hw_extra_devices)
+
+AC_CHECK_HEADERS(string.h strings.h stdlib.h stdlib.h fcntl.h)
+
+AC_SUBST(m68hc11_extra_objs)
+
+SIM_AC_OUTPUT
diff --git a/sim/m68hc11/dv-m68hc11.c b/sim/m68hc11/dv-m68hc11.c
new file mode 100644 (file)
index 0000000..0cca680
--- /dev/null
@@ -0,0 +1,582 @@
+/*  dv-m68hc11.c -- CPU 68HC11 as a device.
+    Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+    Written by Stephane Carrez (stcarrez@worldnet.fr)
+    (From a driver model Contributed by Cygnus Solutions.)
+    
+    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 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.
+    
+    */
+
+
+#include "sim-main.h"
+#include "hw-main.h"
+
+/* DEVICE
+
+        m68hc11cpu - m68hc11 cpu virtual device
+
+   
+   DESCRIPTION
+
+        Implements the external m68hc11 functionality.  This includes the
+        delivery of of interrupts generated from other devices and the
+        handling of device specific registers.
+
+
+   PROPERTIES
+
+   reg <base> <size>
+
+        Register base (should be 0x1000 0x03f).
+
+   clock <hz>
+
+        Frequency of the quartz used by the processor.
+
+   mode [single | expanded | bootstrap | test]
+
+        Cpu operating mode (the MODA and MODB external pins).
+
+
+   PORTS
+
+   reset (input)
+
+        Reset the cpu and generates a cpu-reset event (used to reset
+        other devices).
+
+   nmi (input)
+
+        Deliver a non-maskable interrupt to the processor.
+
+
+   cpu-reset (output)
+
+        Event generated after the CPU performs a reset.
+
+
+   BUGS
+
+        When delivering an interrupt, this code assumes that there is only
+        one processor (number 0).
+
+   */
+
+
+
+struct m68hc11cpu {
+  /* Pending interrupts for delivery by event handler.  */
+  int              pending_reset;
+  int              pending_nmi;
+  int              pending_level;
+  struct hw_event  *event;
+  unsigned_word    attach_address;
+  int              attach_size;
+  int              attach_space;
+};
+
+
+
+/* input port ID's */ 
+
+enum {
+  RESET_PORT,
+  NMI_PORT,
+  IRQ_PORT,
+  CPU_RESET_PORT
+};
+
+
+static const struct hw_port_descriptor m68hc11cpu_ports[] = {
+
+  /* Interrupt inputs.  */
+  { "reset",     RESET_PORT,     0, input_port, },
+  { "nmi",       NMI_PORT,       0, input_port, },
+  { "irq",       IRQ_PORT,       0, input_port, },
+
+  /* Events generated for connection to other devices.  */
+  { "cpu-reset", CPU_RESET_PORT, 0, output_port, },
+
+  { NULL, },
+};
+
+static hw_io_read_buffer_method m68hc11cpu_io_read_buffer;
+static hw_io_write_buffer_method m68hc11cpu_io_write_buffer;
+static hw_ioctl_method m68hc11_ioctl;
+
+/* Finish off the partially created hw device.  Attach our local
+   callbacks.  Wire up our port names etc.  */
+
+static hw_port_event_method m68hc11cpu_port_event;
+
+
+static void
+dv_m6811_attach_address_callback (struct hw *me,
+                                  int level,
+                                  int space,
+                                  address_word addr,
+                                  address_word nr_bytes,
+                                  struct hw *client)
+{
+  HW_TRACE ((me, "attach - level=%d, space=%d, addr=0x%lx, sz=%ld, client=%s",
+            level, space, (unsigned long) addr, (unsigned long) nr_bytes,
+             hw_path (client)));
+
+  if (space != io_map)
+    {
+      sim_core_attach (hw_system (me),
+                      NULL, /*cpu*/
+                      level,
+                      access_read_write_exec,
+                      space, addr,
+                      nr_bytes,
+                      0, /* modulo */
+                      client,
+                      NULL);
+    }
+  else
+    {
+      /*printf("Attach from sub device: %d\n", (long) addr);*/
+      sim_core_attach (hw_system (me),
+                      NULL, /*cpu*/
+                      level,
+                      access_io,
+                      space, addr,
+                      nr_bytes,
+                      0, /* modulo */
+                      client,
+                      NULL);
+    }
+}
+
+static void
+dv_m6811_detach_address_callback (struct hw *me,
+                                  int level,
+                                  int space,
+                                  address_word addr,
+                                  address_word nr_bytes,
+                                  struct hw *client)
+{
+  sim_core_detach (hw_system (me), NULL, /*cpu*/
+                   level, space, addr);
+}
+
+
+static void
+attach_m68hc11_regs (struct hw *me,
+                    struct m68hc11cpu *controller)
+{
+  SIM_DESC sd;
+  sim_cpu *cpu;
+  reg_property_spec reg;
+  const char *cpu_mode;
+  
+  if (hw_find_property (me, "reg") == NULL)
+    hw_abort (me, "Missing \"reg\" property");
+
+  if (!hw_find_reg_array_property (me, "reg", 0, &reg))
+    hw_abort (me, "\"reg\" property must contain one addr/size entry");
+
+  hw_unit_address_to_attach_address (hw_parent (me),
+                                    &reg.address,
+                                    &controller->attach_space,
+                                    &controller->attach_address,
+                                    me);
+  hw_unit_size_to_attach_size (hw_parent (me),
+                              &reg.size,
+                              &controller->attach_size, me);
+
+  hw_attach_address (hw_parent (me), 0,
+                    controller->attach_space,
+                     controller->attach_address,
+                     controller->attach_size,
+                    me);
+
+
+  /* Get cpu frequency.  */
+  sd = hw_system (me);
+  cpu = STATE_CPU (sd, 0);
+  if (hw_find_property (me, "clock") != NULL)
+    {
+      cpu->cpu_frequency = hw_find_integer_property (me, "clock");
+    }
+  else
+    {
+      cpu->cpu_frequency = 8*1000*1000;
+    }
+
+  cpu_mode = "expanded";
+  if (hw_find_property (me, "mode") != NULL)
+    cpu_mode = hw_find_string_property (me, "mode");
+
+  if (strcmp (cpu_mode, "test") == 0)
+    cpu->cpu_mode = M6811_MDA | M6811_SMOD;
+  else if (strcmp (cpu_mode, "bootstrap") == 0)
+    cpu->cpu_mode = M6811_SMOD;
+  else if (strcmp (cpu_mode, "single") == 0)
+    cpu->cpu_mode = 0;
+  else
+    cpu->cpu_mode = M6811_MDA;
+}
+
+static void
+m68hc11cpu_finish (struct hw *me)
+{
+  struct m68hc11cpu *controller;
+
+  controller = HW_ZALLOC (me, struct m68hc11cpu);
+  me->overlap_mode_hw = 1;
+  set_hw_data (me, controller);
+  set_hw_io_read_buffer (me, m68hc11cpu_io_read_buffer);
+  set_hw_io_write_buffer (me, m68hc11cpu_io_write_buffer);
+  set_hw_ports (me, m68hc11cpu_ports);
+  set_hw_port_event (me, m68hc11cpu_port_event);
+  set_hw_attach_address (me, dv_m6811_attach_address_callback);
+  set_hw_detach_address (me, dv_m6811_detach_address_callback);
+#ifdef set_hw_ioctl
+  set_hw_ioctl (me, m68hc11_ioctl);
+#else
+  me->to_ioctl = m68hc11_ioctl;
+#endif
+
+  /* Initialize the pending interrupt flags.  */
+  controller->pending_level = 0;
+  controller->pending_reset = 0;
+  controller->pending_nmi = 0;
+  controller->event = NULL;
+
+  attach_m68hc11_regs (me, controller);
+}
+
+
+
+/* An event arrives on an interrupt port.  */
+
+static void
+deliver_m68hc11cpu_interrupt (struct hw *me, void *data)
+{
+}
+
+
+static void
+m68hc11cpu_port_event (struct hw *me,
+                       int my_port,
+                       struct hw *source,
+                       int source_port,
+                       int level)
+{
+  struct m68hc11cpu *controller = hw_data (me);
+  SIM_DESC sd;
+  sim_cpu* cpu;
+  
+  sd  = hw_system (me);
+  cpu = STATE_CPU (sd, 0);
+  switch (my_port)
+    {
+    case RESET_PORT:
+      HW_TRACE ((me, "port-in reset"));
+
+      /* The reset is made in 3 steps:
+         - First, cleanup the current sim_cpu struct.
+         - Reset the devices.
+         - Restart the cpu for the reset (get the CPU mode from the
+           CONFIG register that gets initialized by EEPROM device).  */
+      cpu_reset (cpu);
+      hw_port_event (me, CPU_RESET_PORT, 1);
+      cpu_restart (cpu);
+      break;
+      
+    case NMI_PORT:
+      controller->pending_nmi = 1;
+      HW_TRACE ((me, "port-in nmi"));
+      break;
+      
+    case IRQ_PORT:
+      /* level == 0 means that the interrupt was cleared.  */
+      if(level == 0)
+       controller->pending_level = -1; /* signal end of interrupt */
+      else
+       controller->pending_level = level;
+      HW_TRACE ((me, "port-in level=%d", level));
+      break;
+      
+    default:
+      hw_abort (me, "bad switch");
+      break;
+    }
+
+  /* Schedule an event to be delivered immediately after current
+     instruction.  */
+  if(controller->event != NULL)
+    hw_event_queue_deschedule(me, controller->event);
+  controller->event =
+    hw_event_queue_schedule (me, 0, deliver_m68hc11cpu_interrupt, NULL);
+}
+
+
+io_reg_desc config_desc[] = {
+  { M6811_NOSEC, "NOSEC ", "Security Mode Disable" },
+  { M6811_NOCOP, "NOCOP ", "COP System Disable" },
+  { M6811_ROMON, "ROMON ", "Enable On-chip Rom" },
+  { M6811_EEON,  "EEON  ", "Enable On-chip EEprom" },
+  { 0,  0, 0 }
+};
+
+io_reg_desc hprio_desc[] = {
+  { M6811_RBOOT, "RBOOT ", "Read Bootstrap ROM" },
+  { M6811_SMOD,  "SMOD  ", "Special Mode" },
+  { M6811_MDA,   "MDA   ", "Mode Select A" },
+  { M6811_IRV,   "IRV   ", "Internal Read Visibility" },
+  { 0,  0, 0 }
+};
+
+io_reg_desc option_desc[] = {
+  { M6811_ADPU,  "ADPU  ", "A/D Powerup" },
+  { M6811_CSEL,  "CSEL  ", "A/D/EE Charge pump clock source select" },
+  { M6811_IRQE,  "IRQE  ", "IRQ Edge/Level sensitive" },
+  { M6811_DLY,   "DLY   ", "Stop exit turn on delay" },
+  { M6811_CME,   "CME   ", "Clock Monitor Enable" },
+  { M6811_CR1,   "CR1   ", "COP timer rate select (CR1)" },
+  { M6811_CR0,   "CR0   ", "COP timer rate select (CR0)" },
+  { 0,  0, 0 }
+};
+
+static void
+m68hc11_info (struct hw *me)
+{
+  SIM_DESC sd;
+  uint16 base = 0;
+  sim_cpu *cpu;
+  struct m68hc11sio *controller;
+  uint8 val;
+  
+  sd = hw_system (me);
+  cpu = STATE_CPU (sd, 0);
+  controller = hw_data (me);
+
+  base = cpu_get_io_base (cpu);
+  sim_io_printf (sd, "M68HC11:\n");
+
+  val = cpu->ios[M6811_HPRIO];
+  print_io_byte (sd, "HPRIO ", hprio_desc, val, base + M6811_HPRIO);
+  sim_io_printf (sd, "\n");
+
+  val = cpu->ios[M6811_CONFIG];
+  print_io_byte (sd, "CONFIG", config_desc, val, base + M6811_CONFIG);
+  sim_io_printf (sd, "\n");
+
+  val = cpu->ios[M6811_OPTION];
+  print_io_byte (sd, "OPTION", option_desc, val, base + M6811_OPTION);
+  sim_io_printf (sd, "\n");
+
+  val = cpu->ios[M6811_INIT];
+  print_io_byte (sd, "INIT  ", 0, val, base + M6811_INIT);
+  sim_io_printf (sd, "Ram = 0x%04x IO = 0x%04x\n",
+                (((uint16) (val & 0xF0)) << 8),
+                (((uint16) (val & 0x0F)) << 12));
+
+
+  cpu_info (sd, cpu);
+  interrupts_info (sd, &cpu->cpu_interrupts);
+}
+
+static int
+m68hc11_ioctl (struct hw *me,
+              hw_ioctl_request request,
+              va_list ap)
+{
+  m68hc11_info (me);
+  return 0;
+}
+
+/* generic read/write */
+
+static unsigned
+m68hc11cpu_io_read_buffer (struct hw *me,
+                          void *dest,
+                          int space,
+                          unsigned_word base,
+                          unsigned nr_bytes)
+{
+  SIM_DESC sd;
+  struct m68hc11cpu *controller = hw_data (me);
+  sim_cpu *cpu;
+  unsigned byte = 0;
+  int result;
+  
+  HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
+
+  sd  = hw_system (me); 
+  cpu = STATE_CPU (sd, 0);
+
+  /* Handle reads for the sub-devices.  */
+  base -= controller->attach_address;
+  result = sim_core_read_buffer (sd, cpu,
+                                io_map, dest, base, nr_bytes);
+  if (result > 0)
+    return result;
+  
+  while (nr_bytes)
+    {
+      if (base >= 0x3F)
+       break;
+
+      memcpy (dest, &cpu->ios[base], 1);
+      dest++;
+      base++;
+      byte++;
+      nr_bytes--;
+    }
+  return byte;
+}     
+
+
+static void
+m68hc11cpu_io_write (struct hw *me, sim_cpu *cpu,
+                     unsigned_word addr, uint8 val)
+{
+  switch (addr)
+    {
+    case M6811_PORTA:
+      break;
+
+    case M6811_PIOC:
+      break;
+
+    case M6811_PORTC:
+      break;
+
+    case M6811_PORTB:
+      break;
+
+    case M6811_PORTCL:
+      break;
+
+    case M6811_DDRC:
+      break;
+
+    case M6811_PORTD:
+      break;
+
+    case M6811_DDRD:
+      break;
+
+    case M6811_TMSK2:
+      
+      break;
+      
+      /* Change the RAM and I/O mapping.  */
+    case M6811_INIT:
+      {
+       uint8 old_bank = cpu->ios[M6811_INIT];
+       
+       cpu->ios[M6811_INIT] = val;
+
+       /* Update IO mapping.  Detach from the old address
+          and attach to the new one.  */
+       if ((old_bank & 0xF0) != (val & 0xF0))
+         {
+            struct m68hc11cpu *controller = hw_data (me);
+
+            hw_detach_address (hw_parent (me), 0,
+                               controller->attach_space,
+                               controller->attach_address,
+                               controller->attach_size,
+                               me);
+            controller->attach_address = (val & 0x0F0) << 12;
+            hw_attach_address (hw_parent (me), 0,
+                               controller->attach_space,
+                               controller->attach_address,
+                               controller->attach_size,
+                               me);
+         }
+       if ((old_bank & 0x0F) != (val & 0x0F))
+         {
+           ;
+         }
+       return;
+      }
+
+    /* Writing the config is similar to programing the eeprom.
+       The config register value is the last byte of the EEPROM.
+       This last byte is not mapped in memory (that's why we have
+       to add '1' to 'end_addr').  */
+    case M6811_CONFIG:
+      {
+        return;
+      }
+      
+
+      /* COP reset.  */
+    case M6811_COPRST:
+      if (val == 0xAA && cpu->ios[addr] == 0x55)
+       {
+          val = 0;
+          /* COP reset here.  */
+       }
+      break;
+      
+    default:
+      break;
+
+    }
+  cpu->ios[addr] = val;
+}
+
+static unsigned
+m68hc11cpu_io_write_buffer (struct hw *me,
+                           const void *source,
+                           int space,
+                           unsigned_word base,
+                           unsigned nr_bytes)
+{
+  SIM_DESC sd;
+  struct m68hc11cpu *controller = hw_data (me);
+  unsigned byte;
+  sim_cpu *cpu;
+  int result;
+
+  HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
+
+  sd = hw_system (me); 
+  cpu = STATE_CPU (sd, 0);  
+  base -= controller->attach_address;
+  result = sim_core_write_buffer (sd, cpu,
+                                 io_map, source, base, nr_bytes);
+  if (result > 0)
+    return result;
+
+  byte = 0;
+  while (nr_bytes)
+    {
+      uint8 val;
+      if (base >= 0x3F)
+       break;
+
+      val = *((uint8*) source);
+      m68hc11cpu_io_write (me, cpu, base, val);
+      source++;
+      base++;
+      byte++;
+      nr_bytes--;
+    }
+  return byte;
+}
+
+const struct hw_descriptor dv_m68hc11_descriptor[] = {
+  { "m68hc11", m68hc11cpu_finish, },
+  { NULL },
+};
+
diff --git a/sim/m68hc11/dv-m68hc11eepr.c b/sim/m68hc11/dv-m68hc11eepr.c
new file mode 100644 (file)
index 0000000..1e26d85
--- /dev/null
@@ -0,0 +1,620 @@
+/*  dv-m68hc11eepr.c -- Simulation of the 68HC11 Internal EEPROM.
+    Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+    Written by Stephane Carrez (stcarrez@worldnet.fr)
+    (From a driver model Contributed by Cygnus Solutions.)
+    
+    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 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.
+    
+    */
+
+
+#include "sim-main.h"
+#include "hw-main.h"
+#include "sim-assert.h"
+#include "sim-events.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+
+
+/* DEVICE
+
+        m68hc11eepr - m68hc11 EEPROM
+
+   
+   DESCRIPTION
+
+        Implements the 68HC11 eeprom device described in the m68hc11
+        user guide (Chapter 4 in the pink book).
+
+
+   PROPERTIES
+
+   reg <base> <length>
+
+        Base of eeprom and its length.
+
+   file <path>
+
+        Path of the EEPROM file.  The default is 'm6811.eeprom'.
+
+
+   PORTS
+
+        None
+
+   */
+
+
+
+/* static functions */
+
+
+/* port ID's */
+
+enum
+{
+  RESET_PORT
+};
+
+
+static const struct hw_port_descriptor m68hc11eepr_ports[] = 
+{
+  { "reset", RESET_PORT, 0, input_port, },
+  { NULL, },
+};
+
+
+
+/* The timer/counter register internal state.  Note that we store
+   state using the control register images, in host endian order.  */
+
+struct m68hc11eepr 
+{
+  address_word  base_address; /* control register base */
+  int           attach_space;
+  unsigned      size;
+
+  /* Current state of the eeprom programing:
+     - eeprom_wmode indicates whether the EEPROM address and byte have
+       been latched.
+     - eeprom_waddr indicates the EEPROM address that was latched
+       and eeprom_wbyte is the byte that was latched.
+     - eeprom_wcycle indicates the CPU absolute cycle type when
+       the high voltage was applied (successfully) on the EEPROM.
+   
+     These data members are setup only when we detect good EEPROM programing
+     conditions (see Motorola EEPROM Programming and PPROG register usage).
+     When the high voltage is switched off, we look at the CPU absolute
+     cycle time to see if the EEPROM command must succeeds or not.
+     The EEPROM content is updated and saved only at that time.
+     (EEPROM command is: byte zero bits program, byte erase, row erase
+     and bulk erase).
+    
+     The CONFIG register is programmed in the same way.  It is physically
+     located at the end of the EEPROM (eeprom size + 1).  It is not mapped
+     in memory but it's saved in the EEPROM file.  */
+  unsigned long                eeprom_wcycle;
+  uint16               eeprom_waddr;
+  uint8                        eeprom_wbyte;
+  uint8                        eeprom_wmode;
+
+  uint8*               eeprom;
+  
+  /* Minimum time in CPU cycles for programming the EEPROM.  */
+  unsigned long         eeprom_min_cycles;
+
+  char* file_name;
+};
+
+
+
+/* Finish off the partially created hw device.  Attach our local
+   callbacks.  Wire up our port names etc.  */
+
+static hw_io_read_buffer_method m68hc11eepr_io_read_buffer;
+static hw_io_write_buffer_method m68hc11eepr_io_write_buffer;
+static hw_ioctl_method m68hc11eepr_ioctl;
+
+/* Read or write the memory bank content from/to a file.
+   Returns 0 if the operation succeeded and -1 if it failed.  */
+static int
+m6811eepr_memory_rw (struct m68hc11eepr *controller, int mode)
+{
+  const char *name = controller->file_name;
+  int fd;
+  size_t size;
+  
+  size = controller->size;
+  fd = open (name, mode, 0644);
+  if (fd < 0)
+    {
+      if (mode == O_RDONLY)
+        {
+          memset (controller->eeprom, 0xFF, size);
+          /* Default value for CONFIG register (0xFF should be ok):
+             controller->eeprom[size - 1] = M6811_NOSEC | M6811_NOCOP
+                                            | M6811_ROMON | M6811_EEON;  */
+          return 0;
+        }
+      return -1;
+    }
+
+  if (mode == O_RDONLY)
+    {
+      if (read (fd, controller->eeprom, size) != size)
+       {
+         close (fd);
+         return -1;
+       }
+    }
+  else
+    {
+      if (write (fd, controller->eeprom, size) != size)
+       {
+         close (fd);
+         return -1;
+       }
+    }
+  close (fd);
+
+  return 0;
+}
+
+
+
+
+static void
+attach_m68hc11eepr_regs (struct hw *me,
+                         struct m68hc11eepr *controller)
+{
+  unsigned_word attach_address;
+  int attach_space;
+  unsigned attach_size;
+  reg_property_spec reg;
+
+  if (hw_find_property (me, "reg") == NULL)
+    hw_abort (me, "Missing \"reg\" property");
+
+  if (!hw_find_reg_array_property (me, "reg", 0, &reg))
+    hw_abort (me, "\"reg\" property must contain one addr/size entry");
+
+  hw_unit_address_to_attach_address (hw_parent (me),
+                                    &reg.address,
+                                    &attach_space,
+                                    &attach_address,
+                                    me);
+  hw_unit_size_to_attach_size (hw_parent (me),
+                              &reg.size,
+                              &attach_size, me);
+
+  /* Attach the two IO registers that control the EEPROM.
+     The EEPROM is only attached at reset time because it may
+     be enabled/disabled by the EEON bit in the CONFIG register.  */
+  hw_attach_address (hw_parent (me), 0, io_map, M6811_PPROG, 1, me);
+  hw_attach_address (hw_parent (me), 0, io_map, M6811_CONFIG, 1, me);
+
+  if (hw_find_property (me, "file") == NULL)
+    controller->file_name = "m6811.eeprom";
+  else
+    controller->file_name = hw_find_string_property (me, "file");
+  
+  controller->attach_space = attach_space;
+  controller->base_address = attach_address;
+  controller->eeprom = (char*) malloc (attach_size + 1);
+  controller->eeprom_min_cycles = 10000;
+  controller->size = attach_size + 1;
+
+  m6811eepr_memory_rw (controller, O_RDONLY);
+}
+
+
+/* An event arrives on an interrupt port.  */
+
+static void
+m68hc11eepr_port_event (struct hw *me,
+                        int my_port,
+                        struct hw *source,
+                        int source_port,
+                        int level)
+{
+  SIM_DESC sd;
+  struct m68hc11eepr *controller;
+  sim_cpu *cpu;
+  
+  controller = hw_data (me);
+  sd         = hw_system (me);
+  cpu        = STATE_CPU (sd, 0);
+  switch (my_port)
+    {
+    case RESET_PORT:
+      {
+       HW_TRACE ((me, "EEPROM reset"));
+
+        /* Re-read the EEPROM from the file.  This gives the chance
+           to users to erase this file before doing a reset and have
+           a fresh EEPROM taken into account.  */
+        m6811eepr_memory_rw (controller, O_RDONLY);
+
+        /* Reset the state of EEPROM programmer.  The CONFIG register
+           is also initialized from the EEPROM/file content.  */
+        cpu->ios[M6811_PPROG]    = 0;
+        if (cpu->cpu_use_local_config)
+          cpu->ios[M6811_CONFIG] = cpu->cpu_config;
+        else
+          cpu->ios[M6811_CONFIG]   = controller->eeprom[controller->size-1];
+        controller->eeprom_wmode = 0;
+        controller->eeprom_waddr = 0;
+        controller->eeprom_wbyte = 0;
+
+        /* Attach or detach to the bus depending on the EEPROM enable bit.
+           The EEPROM CONFIG register is still enabled and can be programmed
+           for a next configuration (taken into account only after a reset,
+           see Motorola spec).  */
+        if (cpu->ios[M6811_CONFIG] & M6811_EEON)
+          {
+            hw_attach_address (hw_parent (me), 0,
+                               controller->attach_space,
+                               controller->base_address,
+                               controller->size - 1,
+                               me);
+          }
+        else
+          {
+            hw_detach_address (hw_parent (me), 0,
+                               controller->attach_space,
+                               controller->base_address,
+                               controller->size - 1,
+                               me);
+          }
+        break;
+      }
+
+    default:
+      hw_abort (me, "Event on unknown port %d", my_port);
+      break;
+    }
+}
+
+
+static void
+m68hc11eepr_finish (struct hw *me)
+{
+  struct m68hc11eepr *controller;
+
+  controller = HW_ZALLOC (me, struct m68hc11eepr);
+  me->overlap_mode_hw = 1;
+  set_hw_data (me, controller);
+  set_hw_io_read_buffer (me, m68hc11eepr_io_read_buffer);
+  set_hw_io_write_buffer (me, m68hc11eepr_io_write_buffer);
+  set_hw_ports (me, m68hc11eepr_ports);
+  set_hw_port_event (me, m68hc11eepr_port_event);
+#ifdef set_hw_ioctl
+  set_hw_ioctl (me, m68hc11eepr_ioctl);
+#else
+  me->to_ioctl = m68hc11eepr_ioctl;
+#endif
+
+  attach_m68hc11eepr_regs (me, controller);
+}
+
+
+static io_reg_desc pprog_desc[] = {
+  { M6811_BYTE,  "BYTE  ", "Byte Program Mode" },
+  { M6811_ROW,   "ROW   ", "Row Program Mode" },
+  { M6811_ERASE, "ERASE ", "Erase Mode" },
+  { M6811_EELAT, "EELAT ", "EEProm Latch Control" },
+  { M6811_EEPGM, "EEPGM ", "EEProm Programming Voltable Enable" },
+  { 0,  0, 0 }
+};
+extern io_reg_desc config_desc[];
+
+
+/* Describe the state of the EEPROM device.  */
+static void
+m68hc11eepr_info (struct hw *me)
+{
+  SIM_DESC sd;
+  uint16 base = 0;
+  sim_cpu *cpu;
+  struct m68hc11eepr *controller;
+  uint8 val;
+  
+  sd         = hw_system (me);
+  cpu        = STATE_CPU (sd, 0);
+  controller = hw_data (me);
+  base       = cpu_get_io_base (cpu);
+  
+  sim_io_printf (sd, "M68HC11 EEprom:\n");
+
+  val = cpu->ios[M6811_PPROG];
+  print_io_byte (sd, "PPROG  ", pprog_desc, val, base + M6811_PPROG);
+  sim_io_printf (sd, "\n");
+
+  val = cpu->ios[M6811_CONFIG];
+  print_io_byte (sd, "CONFIG ", config_desc, val, base + M6811_CONFIG);
+  sim_io_printf (sd, "\n");
+
+  val = controller->eeprom[controller->size - 1];
+  print_io_byte (sd, "(*NEXT*) ", config_desc, val, base + M6811_CONFIG);
+  sim_io_printf (sd, "\n");
+  
+  /* Describe internal state of EEPROM.  */
+  if (controller->eeprom_wmode)
+    {
+      if (controller->eeprom_waddr == controller->size - 1)
+        sim_io_printf (sd, "  Programming CONFIG register ");
+      else
+        sim_io_printf (sd, "  Programming: 0x%04x ",
+                       controller->eeprom_waddr);
+
+      sim_io_printf (sd, "with 0x%02x\n",
+                    controller->eeprom_wbyte);
+    }
+
+  sim_io_printf (sd, "  EEProm file: %s\n",
+                 controller->file_name);
+}
+
+static int
+m68hc11eepr_ioctl (struct hw *me,
+                  hw_ioctl_request request,
+                  va_list ap)
+{
+  m68hc11eepr_info (me);
+  return 0;
+}
+
+/* generic read/write */
+
+static unsigned
+m68hc11eepr_io_read_buffer (struct hw *me,
+                           void *dest,
+                           int space,
+                           unsigned_word base,
+                           unsigned nr_bytes)
+{
+  SIM_DESC sd;
+  struct m68hc11eepr *controller;
+  sim_cpu *cpu;
+  
+  HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
+
+  sd         = hw_system (me);
+  controller = hw_data (me);
+  cpu        = STATE_CPU (sd, 0);
+
+  if (space == io_map)
+    {
+      unsigned cnt = 0;
+      
+      while (nr_bytes != 0)
+        {
+          switch (base)
+            {
+            case M6811_PPROG:
+            case M6811_CONFIG:
+              *((uint8*) dest) = cpu->ios[base];
+              break;
+
+            default:
+              hw_abort (me, "reading wrong register 0x%04x", base);
+            }
+          dest = (uint8*) (dest) + 1;
+          base++;
+          nr_bytes--;
+          cnt++;
+        }
+      return cnt;
+    }
+
+  /* In theory, we can't read the EEPROM when it's being programmed.  */
+  if ((cpu->ios[M6811_PPROG] & M6811_EELAT) != 0
+      && cpu_is_running (cpu))
+    {
+      sim_memory_error (cpu, SIM_SIGBUS, base,
+                       "EEprom not configured for reading");
+    }
+
+  base = base - controller->base_address;
+  memcpy (dest, &controller->eeprom[base], nr_bytes);
+  return nr_bytes;
+}
+
+
+static unsigned
+m68hc11eepr_io_write_buffer (struct hw *me,
+                            const void *source,
+                            int space,
+                            unsigned_word base,
+                            unsigned nr_bytes)
+{
+  SIM_DESC sd;
+  struct m68hc11eepr *controller;
+  sim_cpu *cpu;
+  uint8 val;
+
+  HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
+
+  sd         = hw_system (me);
+  controller = hw_data (me);
+  cpu        = STATE_CPU (sd, 0);
+
+  /* Programming several bytes at a time is not possible.  */
+  if (space != io_map && nr_bytes != 1)
+    {
+      sim_memory_error (cpu, SIM_SIGBUS, base,
+                       "EEprom write error (only 1 byte can be programmed)");
+      return 0;
+    }
+  
+  if (nr_bytes != 1)
+    hw_abort (me, "Cannot write more than 1 byte to EEPROM device at a time");
+
+  val = *((const uint8*) source);
+
+  /* Write to the EEPROM control register.  */
+  if (space == io_map && base == M6811_PPROG)
+    {
+      uint8 wrong_bits;
+      uint16 addr;
+      
+      addr = base + cpu_get_io_base (cpu);
+
+      /* Setting EELAT and EEPGM at the same time is an error.
+         Clearing them both is ok.  */
+      wrong_bits = (cpu->ios[M6811_PPROG] ^ val) & val;
+      wrong_bits &= (M6811_EELAT | M6811_EEPGM);
+
+      if (wrong_bits == (M6811_EEPGM|M6811_EELAT))
+       {
+         sim_memory_error (cpu, SIM_SIGBUS, addr,
+                           "Wrong eeprom programing value");
+         return 0;
+       }
+
+      if ((val & M6811_EELAT) == 0)
+       {
+         val = 0;
+       }
+      if ((val & M6811_EEPGM) && !(cpu->ios[M6811_PPROG] & M6811_EELAT))
+       {
+         sim_memory_error (cpu, SIM_SIGBUS, addr,
+                           "EEProm high voltage applied after EELAT");
+       }
+      if ((val & M6811_EEPGM) && controller->eeprom_wmode == 0)
+       {
+         sim_memory_error (cpu, SIM_SIGSEGV, addr,
+                           "EEProm high voltage applied without address");
+       }
+      if (val & M6811_EEPGM)
+       {
+         controller->eeprom_wcycle = cpu_current_cycle (cpu);
+       }
+      else if (cpu->ios[M6811_PPROG] & M6811_PPROG)
+       {
+         int i;
+         unsigned long t = cpu_current_cycle (cpu);
+
+         t -= controller->eeprom_wcycle;
+         if (t < controller->eeprom_min_cycles)
+           {
+             sim_memory_error (cpu, SIM_SIGILL, addr,
+                               "EEprom programmed only for %lu cycles",
+                               t);
+           }
+
+         /* Program the byte by clearing some bits.  */
+         if (!(cpu->ios[M6811_PPROG] & M6811_ERASE))
+           {
+             controller->eeprom[controller->eeprom_waddr]
+               &= controller->eeprom_wbyte;
+           }
+
+         /* Erase a byte, row or the complete eeprom.  Erased value is 0xFF.
+             Ignore row or complete eeprom erase when we are programming the
+             CONFIG register (last EEPROM byte).  */
+         else if ((cpu->ios[M6811_PPROG] & M6811_BYTE)
+                   || controller->eeprom_waddr == controller->size - 1)
+           {
+             controller->eeprom[controller->eeprom_waddr] = 0xff;
+           }
+         else if (cpu->ios[M6811_BYTE] & M6811_ROW)
+           {
+              size_t max_size;
+
+              /* Size of EEPROM (-1 because the last byte is the
+                 CONFIG register.  */
+              max_size = controller->size;
+             controller->eeprom_waddr &= 0xFFF0;
+             for (i = 0; i < 16
+                     && controller->eeprom_waddr < max_size; i++)
+               {
+                 controller->eeprom[controller->eeprom_waddr] = 0xff;
+                 controller->eeprom_waddr ++;
+               }
+           }
+         else
+           {
+              size_t max_size;
+
+              max_size = controller->size;
+             for (i = 0; i < max_size; i++)
+               {
+                 controller->eeprom[i] = 0xff;
+               }
+           }
+
+         /* Save the eeprom in a file.  We have to save after each
+            change because the simulator can be stopped or crash...  */
+         if (m6811eepr_memory_rw (controller, O_WRONLY | O_CREAT) != 0)
+           {
+             sim_memory_error (cpu, SIM_SIGABRT, addr,
+                               "EEPROM programing failed: errno=%d", errno);
+           }
+         controller->eeprom_wmode = 0;
+       }
+      cpu->ios[M6811_PPROG] = val;
+      return 1;
+    }
+
+  /* The CONFIG IO register is mapped at end of EEPROM.
+     It's not visible.  */
+  if (space == io_map && base == M6811_CONFIG)
+    {
+      base = controller->size - 1;
+    }
+  else
+    {
+      base = base - controller->base_address;
+    }
+
+  /* Writing the memory is allowed for the Debugger or simulator
+     (cpu not running).  */
+  if (cpu_is_running (cpu))
+    {
+      if ((cpu->ios[M6811_PPROG] & M6811_EELAT) == 0)
+       {
+         sim_memory_error (cpu, SIM_SIGSEGV, base,
+                           "EEprom not configured for writing");
+         return 0;
+       }
+      if (controller->eeprom_wmode != 0)
+       {
+         sim_memory_error (cpu, SIM_SIGSEGV, base,
+                           "EEprom write error");
+         return 0;
+       }
+      controller->eeprom_wmode = 1;
+      controller->eeprom_waddr = base;
+      controller->eeprom_wbyte = val;
+    }
+  else
+    {
+      controller->eeprom[base] = val;
+      m6811eepr_memory_rw (controller, O_WRONLY);
+    }
+  
+  return 1;
+}
+
+const struct hw_descriptor dv_m68hc11eepr_descriptor[] = {
+  { "m68hc11eepr", m68hc11eepr_finish, },
+  { NULL },
+};
+
diff --git a/sim/m68hc11/dv-m68hc11sio.c b/sim/m68hc11/dv-m68hc11sio.c
new file mode 100644 (file)
index 0000000..df493d6
--- /dev/null
@@ -0,0 +1,664 @@
+/*  dv-m68hc11sio.c -- Simulation of the 68HC11 serial device.
+    Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+    Written by Stephane Carrez (stcarrez@worldnet.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 version 2 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.
+    
+    */
+
+
+#include "sim-main.h"
+#include "hw-main.h"
+#include "dv-sockser.h"
+#include "sim-assert.h"
+
+
+/* DEVICE
+
+        m68hc11sio - m68hc11 serial I/O
+
+   
+   DESCRIPTION
+
+        Implements the m68hc11 serial I/O controller described in the m68hc11
+        user guide. The serial I/O controller is directly connected to the CPU
+        interrupt. The simulator implements:
+
+            - baud rate emulation
+            - 8-bits transfers
+    
+   PROPERTIES
+
+   backend {tcp | stdio}
+
+        Use dv-sockser TCP-port backend or stdio for backend.  Default: stdio.
+
+   
+   PORTS
+
+   reset (input)
+
+        Reset port. This port is only used to simulate a reset of the serial
+        I/O controller. It should be connected to the RESET output of the cpu.
+
+   */
+
+
+
+/* port ID's */
+
+enum
+{
+  RESET_PORT
+};
+
+
+static const struct hw_port_descriptor m68hc11sio_ports[] = 
+{
+  { "reset", RESET_PORT, 0, input_port, },
+  { NULL, },
+};
+
+
+/* Serial Controller information.  */
+struct m68hc11sio 
+{
+  enum {sio_tcp, sio_stdio} backend; /* backend */
+
+  /* Number of cpu cycles to send a bit on the wire.  */
+  unsigned long baud_cycle;
+
+  /* Length in bits of characters sent, this includes the
+     start/stop and parity bits.  Together with baud_cycle, this
+     is used to find the number of cpu cycles to send/receive a data.  */
+  unsigned int  data_length;
+
+  /* Information about next character to be transmited.  */
+  unsigned char tx_has_char;
+  unsigned char tx_char;
+
+  unsigned char rx_char;
+  unsigned char rx_clear_scsr;
+  
+  /* Periodic I/O polling.  */
+  struct hw_event* tx_poll_event;
+  struct hw_event* rx_poll_event;
+};
+
+
+
+/* Finish off the partially created hw device.  Attach our local
+   callbacks.  Wire up our port names etc.  */
+
+static hw_io_read_buffer_method m68hc11sio_io_read_buffer;
+static hw_io_write_buffer_method m68hc11sio_io_write_buffer;
+static hw_port_event_method m68hc11sio_port_event;
+static hw_ioctl_method m68hc11sio_ioctl;
+
+#define M6811_SCI_FIRST_REG (M6811_BAUD)
+#define M6811_SCI_LAST_REG  (M6811_SCDR)
+
+
+static void
+attach_m68hc11sio_regs (struct hw *me,
+                        struct m68hc11sio *controller)
+{
+  hw_attach_address (hw_parent (me), 0, io_map,
+                     M6811_SCI_FIRST_REG,
+                     M6811_SCI_LAST_REG - M6811_SCI_FIRST_REG + 1,
+                    me);
+
+  if (hw_find_property(me, "backend") != NULL)
+    {
+      const char *value = hw_find_string_property(me, "backend");
+      if(! strcmp(value, "tcp"))
+       controller->backend = sio_tcp;
+      else if(! strcmp(value, "stdio"))
+       controller->backend = sio_stdio;
+      else
+       hw_abort (me, "illegal value for backend parameter `%s':"
+                  "use tcp or stdio", value);
+    }
+}
+
+
+static void
+m68hc11sio_finish (struct hw *me)
+{
+  struct m68hc11sio *controller;
+
+  controller = HW_ZALLOC (me, struct m68hc11sio);
+  me->overlap_mode_hw = 1;
+  set_hw_data (me, controller);
+  set_hw_io_read_buffer (me, m68hc11sio_io_read_buffer);
+  set_hw_io_write_buffer (me, m68hc11sio_io_write_buffer);
+  set_hw_ports (me, m68hc11sio_ports);
+  set_hw_port_event (me, m68hc11sio_port_event);
+#ifdef set_hw_ioctl
+  set_hw_ioctl (me, m68hc11sio_ioctl);
+#else
+  me->to_ioctl = m68hc11sio_ioctl;
+#endif
+
+  /* Preset defaults.  */
+  controller->backend = sio_stdio;
+
+  /* Attach ourself to our parent bus.  */
+  attach_m68hc11sio_regs (me, controller);
+
+  /* Initialize to reset state.  */
+  controller->tx_poll_event = NULL;
+  controller->rx_poll_event = NULL;
+  controller->tx_char       = 0;
+  controller->tx_has_char   = 0;
+  controller->rx_clear_scsr = 0;
+  controller->rx_char       = 0;
+}
+
+
+
+/* An event arrives on an interrupt port.  */
+
+static void
+m68hc11sio_port_event (struct hw *me,
+                       int my_port,
+                       struct hw *source,
+                       int source_port,
+                       int level)
+{
+  SIM_DESC sd;
+  struct m68hc11sio *controller;
+  sim_cpu *cpu;
+  unsigned8 val;
+  
+  controller = hw_data (me);
+  sd         = hw_system (me);
+  cpu        = STATE_CPU (sd, 0);  
+  switch (my_port)
+    {
+    case RESET_PORT:
+      {
+       HW_TRACE ((me, "SCI reset"));
+
+        /* Reset the state of SCI registers.  */
+        val = 0;
+        m68hc11sio_io_write_buffer (me, &val, io_map,
+                                    (unsigned_word) M6811_BAUD, 1);
+        m68hc11sio_io_write_buffer (me, &val, io_map,
+                                    (unsigned_word) M6811_SCCR1, 1);
+        m68hc11sio_io_write_buffer (me, &val, io_map,
+                                    (unsigned_word) M6811_SCCR2, 1);
+        
+        cpu->ios[M6811_SCSR]    = M6811_TC | M6811_TDRE;
+        controller->rx_char     = 0;
+        controller->tx_char     = 0;
+        controller->tx_has_char = 0;
+        controller->rx_clear_scsr = 0;
+        if (controller->rx_poll_event)
+          {
+            hw_event_queue_deschedule (me, controller->rx_poll_event);
+            controller->rx_poll_event = 0;
+          }
+        if (controller->tx_poll_event)
+          {
+            hw_event_queue_deschedule (me, controller->tx_poll_event);
+            controller->tx_poll_event = 0;
+          }
+
+        /* In bootstrap mode, initialize the SCI to 1200 bauds to
+           simulate some initial setup by the internal rom.  */
+        if (((cpu->ios[M6811_HPRIO]) & (M6811_SMOD | M6811_MDA)) == M6811_SMOD)
+          {
+            unsigned char val = 0x33;
+            
+            m68hc11sio_io_write_buffer (me, &val, io_map,
+                                        (unsigned_word) M6811_BAUD, 1);
+            val = 0x12;
+            m68hc11sio_io_write_buffer (me, &val, io_map,
+                                        (unsigned_word) M6811_SCCR2, 1);
+          }
+        break;
+      }
+
+    default:
+      hw_abort (me, "Event on unknown port %d", my_port);
+      break;
+    }
+}
+
+
+void
+m68hc11sio_rx_poll (struct hw *me, void *data)
+{
+  SIM_DESC sd;
+  struct m68hc11sio *controller;
+  sim_cpu *cpu;
+  char cc;
+  int cnt;
+  int check_interrupt = 0;
+  
+  controller = hw_data (me);
+  sd         = hw_system (me);
+  cpu        = STATE_CPU (sd, 0);
+  switch (controller->backend)
+    {
+    case sio_tcp:
+      cnt = dv_sockser_read (sd);
+      if (cnt != -1)
+        {
+          cc = (char) cnt;
+          cnt = 1;
+        }
+      break;
+
+    case sio_stdio:
+      cnt = sim_io_poll_read (sd, 0 /* stdin */, &cc, 1);
+      break;
+
+    default:
+      cnt = 0;
+      break;
+    }
+
+  if (cnt == 1)
+    {
+      /* Raise the overrun flag if the previous character was not read.  */
+      if (cpu->ios[M6811_SCSR] & M6811_RDRF)
+        cpu->ios[M6811_SCSR] |= M6811_OR;
+
+      cpu->ios[M6811_SCSR]     |= M6811_RDRF;
+      controller->rx_char       = cc;
+      controller->rx_clear_scsr = 0;
+      check_interrupt = 1;
+    }
+  else
+    {
+      /* handle idle line detect here.  */
+      ;
+    }
+
+  if (controller->rx_poll_event)
+    {
+      hw_event_queue_deschedule (me, controller->rx_poll_event);
+      controller->rx_poll_event = 0;
+    }
+
+  if (cpu->ios[M6811_SCCR2] & M6811_RE)
+    {
+      unsigned long clock_cycle;
+
+      /* Compute CPU clock cycles to wait for the next character.  */
+      clock_cycle = controller->data_length * controller->baud_cycle;
+
+      controller->rx_poll_event = hw_event_queue_schedule (me, clock_cycle,
+                                                           m68hc11sio_rx_poll,
+                                                           NULL);
+    }
+
+  if (check_interrupt)
+      interrupts_update_pending (&cpu->cpu_interrupts);
+}
+
+
+void
+m68hc11sio_tx_poll (struct hw *me, void *data)
+{
+  SIM_DESC sd;
+  struct m68hc11sio *controller;
+  sim_cpu *cpu;
+  int check_interrupt = 0;
+  
+  controller = hw_data (me);
+  sd         = hw_system (me);
+  cpu        = STATE_CPU (sd, 0);
+
+  cpu->ios[M6811_SCSR] |= M6811_TDRE;
+  cpu->ios[M6811_SCSR] |= M6811_TC;
+  
+  /* Transmitter is enabled and we have something to sent.  */
+  if ((cpu->ios[M6811_SCCR2] & M6811_TE) && controller->tx_has_char)
+    {
+      cpu->ios[M6811_SCSR] &= ~M6811_TDRE;
+      cpu->ios[M6811_SCSR] &= ~M6811_TC;
+      controller->tx_has_char = 0;
+      check_interrupt = 1;
+      switch (controller->backend)
+        {
+        case sio_tcp:
+          dv_sockser_write (sd, controller->tx_char);
+          break;
+
+        case sio_stdio:
+          sim_io_write_stdout (sd, &controller->tx_char, 1);
+          sim_io_flush_stdout (sd);
+          break;
+
+        default:
+          break;
+        }
+    }
+
+  if (controller->tx_poll_event)
+    {
+      hw_event_queue_deschedule (me, controller->tx_poll_event);
+      controller->tx_poll_event = 0;
+    }
+  
+  if ((cpu->ios[M6811_SCCR2] & M6811_TE)
+      && ((cpu->ios[M6811_SCSR] & M6811_TC) == 0))
+    {
+      unsigned long clock_cycle;
+      
+      /* Compute CPU clock cycles to wait for the next character.  */
+      clock_cycle = controller->data_length * controller->baud_cycle;
+
+      controller->tx_poll_event = hw_event_queue_schedule (me, clock_cycle,
+                                                           m68hc11sio_tx_poll,
+                                                           NULL);
+    }
+
+  if (check_interrupt)
+      interrupts_update_pending (&cpu->cpu_interrupts);
+}
+
+/* Descriptions of the SIO I/O ports.  These descriptions are only used to
+   give information of the SIO device under GDB.  */
+io_reg_desc sccr2_desc[] = {
+  { M6811_TIE,   "TIE  ", "Transmit Interrupt Enable" },
+  { M6811_TCIE,  "TCIE ", "Transmit Complete Interrupt Enable" },
+  { M6811_RIE,   "RIE  ", "Receive Interrupt Enable" },
+  { M6811_ILIE,  "ILIE ", "Idle Line Interrupt Enable" },
+  { M6811_TE,    "TE   ", "Transmit Enable" },
+  { M6811_RE,    "RE   ", "Receive Enable" },
+  { M6811_RWU,   "RWU  ", "Receiver Wake Up" },
+  { M6811_SBK,   "SBRK ", "Send Break" },
+  { 0,  0, 0 }
+};
+
+io_reg_desc sccr1_desc[] = {
+  { M6811_R8,    "R8   ", "Receive Data bit 8" },
+  { M6811_T8,    "T8   ", "Transmit Data bit 8" },
+  { M6811_M,     "M    ", "SCI Character length (0=8-bits, 1=9-bits)" },
+  { M6811_WAKE,  "WAKE ", "Wake up method select (0=idle, 1=addr mark" },
+  { 0,  0, 0 }
+};
+
+io_reg_desc scsr_desc[] = {
+  { M6811_TDRE,  "TDRE ", "Transmit Data Register Empty" },
+  { M6811_TC,    "TC   ", "Transmit Complete" },
+  { M6811_RDRF,  "RDRF ", "Receive Data Register Full" },
+  { M6811_IDLE,  "IDLE ", "Idle Line Detect" },
+  { M6811_OR,    "OR   ", "Overrun Error" },
+  { M6811_NF,    "NF   ", "Noise Flag" },
+  { M6811_FE,    "FE   ", "Framing Error" },
+  { 0,  0, 0 }
+};
+
+io_reg_desc baud_desc[] = {
+  { M6811_TCLR,  "TCLR ", "Clear baud rate (test mode)" },
+  { M6811_SCP1,  "SCP1 ", "SCI baud rate prescaler select (SCP1)" },
+  { M6811_SCP0,  "SCP0 ", "SCI baud rate prescaler select (SCP0)" },
+  { M6811_RCKB,  "RCKB ", "Baur Rate Clock Check (test mode)" },
+  { M6811_SCR2,  "SCR2 ", "SCI Baud rate select (SCR2)" },
+  { M6811_SCR1,  "SCR1 ", "SCI Baud rate select (SCR1)" },
+  { M6811_SCR0,  "SCR0 ", "SCI Baud rate select (SCR0)" },
+  { 0,  0, 0 }
+};
+
+static void
+m68hc11sio_info (struct hw *me)
+{
+  SIM_DESC sd;
+  uint16 base = 0;
+  sim_cpu *cpu;
+  struct m68hc11sio *controller;
+  uint8 val;
+  long clock_cycle;
+  
+  sd = hw_system (me);
+  cpu = STATE_CPU (sd, 0);
+  controller = hw_data (me);
+  
+  sim_io_printf (sd, "M68HC11 SIO:\n");
+
+  base = cpu_get_io_base (cpu);
+
+  val  = cpu->ios[M6811_BAUD];
+  print_io_byte (sd, "BAUD ", baud_desc, val, base + M6811_BAUD);
+  sim_io_printf (sd, " (%ld baud)\n",
+                 (cpu->cpu_frequency / 4) / controller->baud_cycle);
+
+  val = cpu->ios[M6811_SCCR1];
+  print_io_byte (sd, "SCCR1", sccr1_desc, val, base + M6811_SCCR1);
+  sim_io_printf (sd, "  (%d bits) (%dN1)\n",
+                 controller->data_length, controller->data_length - 2);
+
+  val = cpu->ios[M6811_SCCR2];
+  print_io_byte (sd, "SCCR2", sccr2_desc, val, base + M6811_SCCR2);
+  sim_io_printf (sd, "\n");
+
+  val = cpu->ios[M6811_SCSR];
+  print_io_byte (sd, "SCSR ", scsr_desc, val, base + M6811_SCSR);
+  sim_io_printf (sd, "\n");
+
+  clock_cycle = controller->data_length * controller->baud_cycle;
+  
+  if (controller->tx_poll_event)
+    {
+      signed64 t;
+      int n;
+
+      t = hw_event_remain_time (me, controller->tx_poll_event);
+      n = (clock_cycle - t) / controller->baud_cycle;
+      n = controller->data_length - n;
+      sim_io_printf (sd, "  Transmit finished in %ld cycles (%d bit%s)\n",
+                    (long) t, n, (n > 1 ? "s" : ""));
+    }
+  if (controller->rx_poll_event)
+    {
+      signed64 t;
+
+      t = hw_event_remain_time (me, controller->rx_poll_event);
+      sim_io_printf (sd, "  Receive finished in %ld cycles\n",
+                    (long) t);
+    }
+  
+}
+
+static int
+m68hc11sio_ioctl (struct hw *me,
+                  hw_ioctl_request request,
+                  va_list ap)
+{
+  m68hc11sio_info (me);
+  return 0;
+}
+
+/* generic read/write */
+
+static unsigned
+m68hc11sio_io_read_buffer (struct hw *me,
+                           void *dest,
+                           int space,
+                           unsigned_word base,
+                           unsigned nr_bytes)
+{
+  SIM_DESC sd;
+  struct m68hc11sio *controller;
+  sim_cpu *cpu;
+  unsigned8 val;
+  
+  HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
+
+  sd  = hw_system (me);
+  cpu = STATE_CPU (sd, 0);
+  controller = hw_data (me);
+
+  switch (base)
+    {
+    case M6811_SCSR:
+      controller->rx_clear_scsr = cpu->ios[M6811_SCSR]
+        & (M6811_RDRF | M6811_IDLE | M6811_OR | M6811_NF | M6811_FE);
+      
+    case M6811_BAUD:
+    case M6811_SCCR1:
+    case M6811_SCCR2:
+      val = cpu->ios[base];
+      break;
+      
+    case M6811_SCDR:
+      if (controller->rx_clear_scsr)
+        {
+          cpu->ios[M6811_SCSR] &= ~controller->rx_clear_scsr;
+        }
+      val = controller->rx_char;
+      break;
+      
+    default:
+      return 0;
+    }
+  *((unsigned8*) dest) = val;
+  return 1;
+}
+
+static unsigned
+m68hc11sio_io_write_buffer (struct hw *me,
+                            const void *source,
+                            int space,
+                            unsigned_word base,
+                            unsigned nr_bytes)
+{
+  SIM_DESC sd;
+  struct m68hc11sio *controller;
+  sim_cpu *cpu;
+  unsigned8 val;
+
+  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)
+    {
+    case M6811_BAUD:
+      {
+        long divisor;
+        long baud;
+
+        cpu->ios[M6811_BAUD] = val;        
+        switch (val & (M6811_SCP1|M6811_SCP0))
+          {
+          case M6811_BAUD_DIV_1:
+            divisor = 1 * 16;
+            break;
+
+          case M6811_BAUD_DIV_3:
+            divisor = 3 * 16;
+            break;
+
+          case M6811_BAUD_DIV_4:
+            divisor = 4 * 16;
+            break;
+
+          default:
+          case M6811_BAUD_DIV_13:
+            divisor = 13 * 16;
+            break;
+          }
+        val &= (M6811_SCR2|M6811_SCR1|M6811_SCR0);
+        divisor *= (1 << val);
+
+        baud = (cpu->cpu_frequency / 4) / divisor;
+
+        HW_TRACE ((me, "divide rate %ld, baud rate %ld",
+                   divisor, baud));
+
+        controller->baud_cycle = divisor;
+      }
+      break;
+      
+    case M6811_SCCR1:
+      {
+        if (val & M6811_M)
+          controller->data_length = 11;
+        else
+          controller->data_length = 10;
+
+        cpu->ios[M6811_SCCR1] = val;
+      }
+      break;
+      
+    case M6811_SCCR2:
+      if ((val & M6811_RE) == 0)
+        {
+          val &= ~(M6811_RDRF|M6811_IDLE|M6811_OR|M6811_NF|M6811_NF);
+          val |= (cpu->ios[M6811_SCCR2]
+                  & (M6811_RDRF|M6811_IDLE|M6811_OR|M6811_NF|M6811_NF));
+          cpu->ios[M6811_SCCR2] = val;
+          break;
+        }
+
+      /* Activate reception.  */
+      if (controller->rx_poll_event == 0)
+        {
+          long clock_cycle;
+          
+          /* Compute CPU clock cycles to wait for the next character.  */
+          clock_cycle = controller->data_length * controller->baud_cycle;
+
+          controller->rx_poll_event = hw_event_queue_schedule (me, clock_cycle,
+                                                               m68hc11sio_rx_poll,
+                                                               NULL);
+        }      
+      cpu->ios[M6811_SCCR2] = val;
+      interrupts_update_pending (&cpu->cpu_interrupts);
+      break;
+
+      /* No effect.  */
+    case M6811_SCSR:
+      return 1;
+      
+    case M6811_SCDR:
+      if (!(cpu->ios[M6811_SCSR] & M6811_TDRE))
+        {
+          return 0;
+        }
+
+      controller->tx_char     = val;
+      controller->tx_has_char = 1;
+      if ((cpu->ios[M6811_SCCR2] & M6811_TE)
+          && controller->tx_poll_event == 0)
+        {
+          m68hc11sio_tx_poll (me, NULL);
+        }
+      return 1;
+      
+    default:
+      return 0;
+    }
+  return nr_bytes;
+}     
+
+
+const struct hw_descriptor dv_m68hc11sio_descriptor[] = {
+  { "m68hc11sio", m68hc11sio_finish, },
+  { NULL },
+};
+
diff --git a/sim/m68hc11/dv-m68hc11spi.c b/sim/m68hc11/dv-m68hc11spi.c
new file mode 100644 (file)
index 0000000..42aaa70
--- /dev/null
@@ -0,0 +1,508 @@
+/*  dv-m68hc11spi.c -- Simulation of the 68HC11 SPI
+    Copyright (C) 2000 Free Software Foundation, Inc.
+    Written by Stephane Carrez (stcarrez@worldnet.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 version 2 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.
+    
+    */
+
+
+#include "sim-main.h"
+#include "hw-main.h"
+#include "dv-sockser.h"
+#include "sim-assert.h"
+
+
+/* DEVICE
+
+        m68hc11spi - m68hc11 SPI interface
+
+   
+   DESCRIPTION
+
+        Implements the m68hc11 Synchronous Serial Peripheral Interface
+        described in the m68hc11 user guide (Chapter 8 in pink book).
+        The SPI I/O controller is directly connected to the CPU
+        interrupt.  The simulator implements:
+
+            - SPI clock emulation
+            - Data transfer
+            - Write collision detection
+    
+
+   PROPERTIES
+
+        None
+
+   
+   PORTS
+
+   reset (input)
+
+        Reset port. This port is only used to simulate a reset of the SPI
+        I/O controller. It should be connected to the RESET output of the cpu.
+
+   */
+
+
+
+/* port ID's */
+
+enum
+{
+  RESET_PORT
+};
+
+
+static const struct hw_port_descriptor m68hc11spi_ports[] = 
+{
+  { "reset", RESET_PORT, 0, input_port, },
+  { NULL, },
+};
+
+
+/* SPI */
+struct m68hc11spi 
+{
+  /* Information about next character to be transmited.  */
+  unsigned char tx_char;
+  int           tx_bit;
+  unsigned char mode;
+  
+  unsigned char rx_char;
+  unsigned char rx_clear_scsr;
+  unsigned char clk_pin;
+  
+  /* SPI clock rate (twice the real clock).  */
+  unsigned int clock;
+  
+  /* Periodic SPI event.  */
+  struct hw_event* spi_event;
+};
+
+
+
+/* Finish off the partially created hw device.  Attach our local
+   callbacks.  Wire up our port names etc */
+
+static hw_io_read_buffer_method m68hc11spi_io_read_buffer;
+static hw_io_write_buffer_method m68hc11spi_io_write_buffer;
+static hw_port_event_method m68hc11spi_port_event;
+static hw_ioctl_method m68hc11spi_ioctl;
+
+#define M6811_SPI_FIRST_REG (M6811_SPCR)
+#define M6811_SPI_LAST_REG  (M6811_SPDR)
+
+
+static void
+attach_m68hc11spi_regs (struct hw *me,
+                        struct m68hc11spi *controller)
+{
+  hw_attach_address (hw_parent (me), 0, io_map,
+                     M6811_SPI_FIRST_REG,
+                     M6811_SPI_LAST_REG - M6811_SPI_FIRST_REG + 1,
+                    me);
+}
+
+static void
+m68hc11spi_finish (struct hw *me)
+{
+  struct m68hc11spi *controller;
+
+  controller = HW_ZALLOC (me, struct m68hc11spi);
+  me->overlap_mode_hw = 1;
+  set_hw_data (me, controller);
+  set_hw_io_read_buffer (me, m68hc11spi_io_read_buffer);
+  set_hw_io_write_buffer (me, m68hc11spi_io_write_buffer);
+  set_hw_ports (me, m68hc11spi_ports);
+  set_hw_port_event (me, m68hc11spi_port_event);
+#ifdef set_hw_ioctl
+  set_hw_ioctl (me, m68hc11spi_ioctl);
+#else
+  me->to_ioctl = m68hc11spi_ioctl;
+#endif
+
+  /* Attach ourself to our parent bus.  */
+  attach_m68hc11spi_regs (me, controller);
+
+  /* Initialize to reset state.  */
+  controller->spi_event = NULL;
+  controller->rx_clear_scsr = 0;
+}
+
+
+
+/* An event arrives on an interrupt port */
+
+static void
+m68hc11spi_port_event (struct hw *me,
+                       int my_port,
+                       struct hw *source,
+                       int source_port,
+                       int level)
+{
+  SIM_DESC sd;
+  struct m68hc11spi *controller;
+  sim_cpu* cpu;
+  unsigned8 val;
+  
+  controller = hw_data (me);
+  sd         = hw_system (me);
+  cpu        = STATE_CPU (sd, 0);  
+  switch (my_port)
+    {
+    case RESET_PORT:
+      {
+       HW_TRACE ((me, "SPI reset"));
+
+        /* Reset the state of SPI registers.  */
+        controller->rx_clear_scsr = 0;
+        if (controller->spi_event)
+          {
+            hw_event_queue_deschedule (me, controller->spi_event);
+            controller->spi_event = 0;
+          }
+
+        val = 0;
+        m68hc11spi_io_write_buffer (me, &val, io_map,
+                                    (unsigned_word) M6811_SPCR, 1);
+        break;
+      }
+
+    default:
+      hw_abort (me, "Event on unknown port %d", my_port);
+      break;
+    }
+}
+
+static void
+set_bit_port (struct hw *me, sim_cpu *cpu, int port, int mask, int value)
+{
+  /* TODO: Post an event to inform other devices that pin 'port' changes.
+     This has only a sense if we provide some device that is logically
+     connected to these pin ports (SCLK and MOSI) and that handles
+     the SPI protocol.  */
+  if (value)
+    cpu->ios[port] |= mask;
+  else
+    cpu->ios[port] &= ~mask;
+}
+
+
+/* When a character is sent/received by the SPI, the PD2..PD5 line
+   are driven by the following signals:
+
+             B7        B6
+      -----+---------+--------+---/-+-------
+ MOSI      |    |    |   |    |     |
+ MISO     +---------+--------+---/-+
+               ____      ___
+ CLK   _______/    \____/   \__                CPOL=0, CPHA=0
+       _______      ____     __
+              \____/    \___/                  CPOL=1, CPHA=0
+          ____      ____     __
+       __/    \____/    \___/                  CPOL=0, CPHA=1
+       __      ____      ___
+         \____/    \____/   \__                CPOL=1, CPHA=1
+
+ SS ___                                 ____
+       \__________________________//___/
+
+ MISO = PD2
+ MOSI = PD3
+ SCK  = PD4
+ SS   = PD5
+
+*/
+
+#define SPI_START_BIT  0
+#define SPI_MIDDLE_BIT 1
+
+void
+m68hc11spi_clock (struct hw *me, void *data)
+{
+  SIM_DESC sd;
+  struct m68hc11spi* controller;
+  sim_cpu *cpu;
+  int check_interrupt = 0;
+  
+  controller = hw_data (me);
+  sd         = hw_system (me);
+  cpu        = STATE_CPU (sd, 0);
+
+  /* Cleanup current event.  */
+  if (controller->spi_event)
+    {
+      hw_event_queue_deschedule (me, controller->spi_event);
+      controller->spi_event = 0;
+    }
+
+  /* Change a bit of data at each two SPI event.  */
+  if (controller->mode == SPI_START_BIT)
+    {
+      /* Reflect the bit value on bit 2 of port D.  */
+      set_bit_port (me, cpu, M6811_PORTD, (1 << 2),
+                    (controller->tx_char & (1 << controller->tx_bit)));
+      controller->tx_bit--;
+      controller->mode = SPI_MIDDLE_BIT;
+    }
+  else
+    {
+      controller->mode = SPI_START_BIT;
+    }
+
+  /* Change the SPI clock at each event on bit 4 of port D.  */
+  controller->clk_pin = ~controller->clk_pin;
+  set_bit_port (me, cpu, M6811_PORTD, (1 << 4), controller->clk_pin);
+      
+  /* Transmit is now complete for this byte.  */
+  if (controller->mode == SPI_START_BIT && controller->tx_bit < 0)
+    {
+      controller->rx_clear_scsr = 0;
+      cpu->ios[M6811_SPSR] |= M6811_SPIF;
+      if (cpu->ios[M6811_SPCR] & M6811_SPIE)
+        check_interrupt = 1;
+    }
+  else
+    {
+      controller->spi_event = hw_event_queue_schedule (me, controller->clock,
+                                                       m68hc11spi_clock,
+                                                       NULL);
+    }
+
+  if (check_interrupt)
+    interrupts_update_pending (&cpu->cpu_interrupts);
+}
+
+/* Flags of the SPCR register.  */
+io_reg_desc spcr_desc[] = {
+  { M6811_SPIE, "SPIE ", "Serial Peripheral Interrupt Enable" },
+  { M6811_SPE,  "SPE  ",  "Serial Peripheral System Enable" },
+  { M6811_DWOM, "DWOM ", "Port D Wire-OR mode option" },
+  { M6811_MSTR, "MSTR ", "Master Mode Select" },
+  { M6811_CPOL, "CPOL ", "Clock Polarity" },
+  { M6811_CPHA, "CPHA ", "Clock Phase" },
+  { M6811_SPR1, "SPR1 ", "SPI Clock Rate Select" },
+  { M6811_SPR0, "SPR0 ", "SPI Clock Rate Select" },
+  { 0,  0, 0 }
+};
+
+
+/* Flags of the SPSR register.  */
+io_reg_desc spsr_desc[] = {
+  { M6811_SPIF,        "SPIF ", "SPI Transfer Complete flag" },
+  { M6811_WCOL, "WCOL ", "Write Collision" },
+  { M6811_MODF, "MODF ", "Mode Fault" },
+  { 0,  0, 0 }
+};
+
+static void
+m68hc11spi_info (struct hw *me)
+{
+  SIM_DESC sd;
+  uint16 base = 0;
+  sim_cpu *cpu;
+  struct m68hc11spi *controller;
+  uint8 val;
+  
+  sd = hw_system (me);
+  cpu = STATE_CPU (sd, 0);
+  controller = hw_data (me);
+  
+  sim_io_printf (sd, "M68HC11 SPI:\n");
+
+  base = cpu_get_io_base (cpu);
+
+  val = cpu->ios[M6811_SPCR];
+  print_io_byte (sd, "SPCR", spcr_desc, val, base + M6811_SPCR);
+  sim_io_printf (sd, "\n");
+
+  val = cpu->ios[M6811_SPSR];
+  print_io_byte (sd, "SPSR", spsr_desc, val, base + M6811_SPSR);
+  sim_io_printf (sd, "\n");
+
+  if (controller->spi_event)
+    {
+      signed64 t;
+
+      t = hw_event_remain_time (me, controller->spi_event);
+      sim_io_printf (sd, "  SPI operation finished in %ld cycles\n",
+                    (long) t);
+    }
+}
+
+static int
+m68hc11spi_ioctl (struct hw *me,
+                  hw_ioctl_request request,
+                  va_list ap)
+{
+  m68hc11spi_info (me);
+  return 0;
+}
+
+/* generic read/write */
+
+static unsigned
+m68hc11spi_io_read_buffer (struct hw *me,
+                           void *dest,
+                           int space,
+                           unsigned_word base,
+                           unsigned nr_bytes)
+{
+  SIM_DESC sd;
+  struct m68hc11spi *controller;
+  sim_cpu *cpu;
+  unsigned8 val;
+  
+  HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
+
+  sd  = hw_system (me);
+  cpu = STATE_CPU (sd, 0);
+  controller = hw_data (me);
+
+  switch (base)
+    {
+    case M6811_SPSR:
+      controller->rx_clear_scsr = cpu->ios[M6811_SCSR]
+        & (M6811_SPIF | M6811_WCOL | M6811_MODF);
+      
+    case M6811_SPCR:
+      val = cpu->ios[base];
+      break;
+      
+    case M6811_SPDR:
+      if (controller->rx_clear_scsr)
+        {
+          cpu->ios[M6811_SPSR] &= ~controller->rx_clear_scsr;
+          controller->rx_clear_scsr = 0;
+        }
+      val = controller->rx_char;
+      break;
+      
+    default:
+      return 0;
+    }
+  *((unsigned8*) dest) = val;
+  return 1;
+}
+
+static unsigned
+m68hc11spi_io_write_buffer (struct hw *me,
+                            const void *source,
+                            int space,
+                            unsigned_word base,
+                            unsigned nr_bytes)
+{
+  SIM_DESC sd;
+  struct m68hc11spi *controller;
+  sim_cpu *cpu;
+  unsigned8 val;
+
+  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)
+    {
+    case M6811_SPCR:
+      cpu->ios[M6811_SPCR] = val;
+
+      /* The SPI clock rate is 2, 4, 16, 32 of the internal CPU clock.
+         We have to drive the clock pin and need a 2x faster clock.  */
+      switch (val & (M6811_SPR1 | M6811_SPR0))
+        {
+        case 0:
+          controller->clock = 1;
+          break;
+
+        case 1:
+          controller->clock = 2;
+          break;
+
+        case 2:
+          controller->clock = 8;
+          break;
+
+        default:
+          controller->clock = 16;
+          break;
+        }
+
+      /* Set the clock pin.  */
+      if ((val & M6811_CPOL)
+          && (controller->spi_event == 0
+              || ((val & M6811_CPHA) && controller->mode == 1)))
+        controller->clk_pin = 1;
+      else
+        controller->clk_pin = 0;
+
+      set_bit_port (me, cpu, M6811_PORTD, (1 << 4), controller->clk_pin);
+      break;
+      
+      /* Can't write to SPSR.  */
+    case M6811_SPSR:
+      break;
+      
+    case M6811_SPDR:
+      if (!(cpu->ios[M6811_SPCR] & M6811_SPE))
+        {
+          return 0;
+        }
+
+      /* If transfer is taking place, a write to SPDR
+         generates a collision.  */
+      if (controller->spi_event)
+        {
+          cpu->ios[M6811_SPSR] |= M6811_WCOL;
+          break;
+        }
+
+      /* Refuse the write if there was no read of SPSR.  */
+      /* ???? TBD. */
+
+      /* Prepare to send a byte.  */
+      controller->tx_char = val;
+      controller->tx_bit = 7;
+      controller->mode   = 0;
+
+      /* Toggle clock pin internal value when CPHA is 0 so that
+         it will really change in the middle of a bit.  */
+      if (!(cpu->ios[M6811_SPCR] & M6811_CPHA))
+        controller->clk_pin = ~controller->clk_pin;
+
+      cpu->ios[M6811_SPDR] = val;
+
+      /* Activate transmission.  */
+      m68hc11spi_clock (me, NULL);
+      break;
+
+    default:
+      return 0;
+    }
+  return nr_bytes;
+}     
+
+
+const struct hw_descriptor dv_m68hc11spi_descriptor[] = {
+  { "m68hc11spi", m68hc11spi_finish, },
+  { NULL },
+};
+
diff --git a/sim/m68hc11/dv-m68hc11tim.c b/sim/m68hc11/dv-m68hc11tim.c
new file mode 100644 (file)
index 0000000..c672d3a
--- /dev/null
@@ -0,0 +1,607 @@
+/*  dv-m68hc11tim.c -- Simulation of the 68HC11 timer devices.
+    Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+    Written by Stephane Carrez (stcarrez@worldnet.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.
+    
+    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.
+    
+    */
+
+
+#include "sim-main.h"
+#include "hw-main.h"
+#include "sim-assert.h"
+
+
+/* DEVICE
+
+        m68hc11tim - m68hc11 timer devices
+
+   
+   DESCRIPTION
+   
+        Implements the m68hc11 timer as described in Chapter 10
+        of the pink book.
+
+   
+   PROPERTIES
+
+        none
+
+   
+   PORTS
+
+   reset (input)
+
+        Reset the timer device.  This port must be connected to
+        the cpu-reset output port.
+
+   */
+
+
+
+/* port ID's */
+
+enum
+{
+  RESET_PORT
+};
+
+
+static const struct hw_port_descriptor m68hc11tim_ports[] = 
+{
+  { "reset", RESET_PORT, 0, input_port, },
+  { NULL, },
+};
+
+
+/* Timer Controller information.  */
+struct m68hc11tim 
+{
+  unsigned long cop_delay;
+  unsigned long rti_delay;
+  unsigned long ovf_delay;
+  signed64      clock_prescaler;
+  signed64      tcnt_adjust;
+
+  /* Periodic timers.  */
+  struct hw_event *rti_timer_event;
+  struct hw_event *cop_timer_event;
+  struct hw_event *tof_timer_event;
+  struct hw_event *cmp_timer_event;
+};
+
+
+
+/* Finish off the partially created hw device.  Attach our local
+   callbacks.  Wire up our port names etc.  */
+
+static hw_io_read_buffer_method m68hc11tim_io_read_buffer;
+static hw_io_write_buffer_method m68hc11tim_io_write_buffer;
+static hw_port_event_method m68hc11tim_port_event;
+static hw_ioctl_method m68hc11tim_ioctl;
+
+#define M6811_TIMER_FIRST_REG (M6811_TCTN)
+#define M6811_TIMER_LAST_REG  (M6811_PACNT)
+
+
+static void
+attach_m68hc11tim_regs (struct hw *me,
+                        struct m68hc11tim *controller)
+{
+  hw_attach_address (hw_parent (me), 0, io_map,
+                     M6811_TIMER_FIRST_REG,
+                     M6811_TIMER_LAST_REG - M6811_TIMER_FIRST_REG + 1,
+                    me);
+}
+
+
+static void
+m68hc11tim_finish (struct hw *me)
+{
+  struct m68hc11tim *controller;
+
+  controller = HW_ZALLOC (me, struct m68hc11tim);
+  me->overlap_mode_hw = 1;
+  set_hw_data (me, controller);
+  set_hw_io_read_buffer (me, m68hc11tim_io_read_buffer);
+  set_hw_io_write_buffer (me, m68hc11tim_io_write_buffer);
+  set_hw_ports (me, m68hc11tim_ports);
+  set_hw_port_event (me, m68hc11tim_port_event);
+#ifdef set_hw_ioctl
+  set_hw_ioctl (me, m68hc11tim_ioctl);
+#else
+  me->to_ioctl = m68hc11tim_ioctl;
+#endif
+
+  /* Preset defaults.  */
+  controller->clock_prescaler = 1;
+  controller->tcnt_adjust = 0;
+  
+  /* Attach ourself to our parent bus.  */
+  attach_m68hc11tim_regs (me, controller);
+}
+
+
+
+/* An event arrives on an interrupt port.  */
+
+static void
+m68hc11tim_port_event (struct hw *me,
+                       int my_port,
+                       struct hw *source,
+                       int source_port,
+                       int level)
+{
+  SIM_DESC sd;
+  struct m68hc11tim *controller;
+  sim_cpu *cpu;
+  unsigned8 val;
+  
+  controller = hw_data (me);
+  sd         = hw_system (me);
+  cpu        = STATE_CPU (sd, 0);
+  switch (my_port)
+    {
+    case RESET_PORT:
+      {
+       HW_TRACE ((me, "Timer reset"));
+
+        /* Cancel all timer events.  */
+        if (controller->rti_timer_event)
+          {
+            hw_event_queue_deschedule (me, controller->rti_timer_event);
+            controller->rti_timer_event = 0;
+          }
+        if (controller->cop_timer_event)
+          {
+            hw_event_queue_deschedule (me, controller->cop_timer_event);
+            controller->cop_timer_event = 0;
+          }
+        if (controller->tof_timer_event)
+          {
+            hw_event_queue_deschedule (me, controller->tof_timer_event);
+            controller->tof_timer_event = 0;
+          }
+        if (controller->cmp_timer_event)
+          {
+            hw_event_queue_deschedule (me, controller->cmp_timer_event);
+            controller->cmp_timer_event = 0;
+          }
+
+        /* Reset the state of Timer registers.  This also restarts
+           the timer events (overflow and RTI clock).  */
+        val = 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;
+      }
+
+    default:
+      hw_abort (me, "Event on unknown port %d", my_port);
+      break;
+    }
+}
+
+enum event_type
+{
+  COP_EVENT,
+  RTI_EVENT,
+  OVERFLOW_EVENT,
+  COMPARE_EVENT
+};
+
+void
+m68hc11tim_timer_event (struct hw *me, void *data)
+{
+  SIM_DESC sd;
+  struct m68hc11tim *controller;
+  sim_cpu *cpu;
+  enum event_type type;
+  unsigned long delay;
+  struct hw_event **eventp;
+  int check_interrupt = 0;
+  unsigned mask;
+  unsigned flags;
+  unsigned long tcnt;
+  int i;
+  
+  controller = hw_data (me);
+  sd         = hw_system (me);
+  cpu        = STATE_CPU (sd, 0);
+  type       = (enum event_type) ((long) data) & 0x0FF;
+
+  delay = 0;
+  switch (type)
+    {
+    case COP_EVENT:
+      eventp = &controller->cop_timer_event;
+      delay  = controller->cop_delay;
+      check_interrupt = 1;
+      break;
+
+    case RTI_EVENT:
+      eventp = &controller->rti_timer_event;
+      delay  = controller->rti_delay;
+      if (((long) (data) & 0x0100) == 0)
+        {
+          cpu->ios[M6811_TFLG2] |= M6811_RTIF;
+          check_interrupt = 1;
+        }
+      break;
+
+    case OVERFLOW_EVENT:
+      eventp = &controller->tof_timer_event;
+      delay  = controller->ovf_delay;
+      cpu->ios[M6811_TFLG2] |= M6811_TOF;
+      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;
+      
+      flags = cpu->ios[M6811_TMSK1];
+      mask  = 0x80;
+      delay = 65536;
+
+      /* 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))
+            {
+              cpu->ios[M6811_TFLG1] |= mask;
+              check_interrupt++;
+            }
+
+          /* Compute how many times for the next match.  */
+          if (compare > tcnt)
+            compare = compare - tcnt;
+          else
+            compare = compare - tcnt + 65536;
+          
+          if (compare < delay)
+            delay = compare;
+        }
+      delay = delay * controller->clock_prescaler;
+
+      /* Deactivate the compare timer if no output compare is enabled.  */
+      if ((flags & 0xF0) == 0)
+        delay = 0;
+      break;
+
+    default:
+      eventp = 0;
+      break;
+    }
+
+  if (*eventp)
+    {
+      hw_event_queue_deschedule (me, *eventp);
+      *eventp = 0;
+    }
+
+  if (delay != 0)
+    {
+      *eventp = hw_event_queue_schedule (me, delay,
+                                         m68hc11tim_timer_event,
+                                         (void*) type);
+    }
+
+  if (check_interrupt)
+    interrupts_update_pending (&cpu->cpu_interrupts);
+}
+
+
+/* Descriptions of the Timer I/O ports.  These descriptions are only used to
+   give information of the Timer device under GDB.  */
+io_reg_desc tmsk2_desc[] = {
+  { M6811_TOI,    "TOI   ", "Timer Overflow Interrupt Enable" },
+  { M6811_RTII,   "RTII  ", "RTI Interrupt Enable" },
+  { M6811_PAOVI,  "PAOVI ", "Pulse Accumulator Overflow Interrupt Enable" },
+  { M6811_PAII,   "PAII  ", "Pulse Accumulator Interrupt Enable" },
+  { M6811_PR1,    "PR1   ", "Timer prescaler (PR1)" },
+  { M6811_PR0,    "PR0   ", "Timer prescaler (PR0)" },
+  { M6811_TPR_1,  "TPR_1 ", "Timer prescaler div 1" },
+  { M6811_TPR_4,  "TPR_4 ", "Timer prescaler div 4" },
+  { M6811_TPR_8,  "TPR_8 ", "Timer prescaler div 8" },
+  { M6811_TPR_16, "TPR_16", "Timer prescaler div 16" },
+  { 0,  0, 0 }
+};
+
+io_reg_desc tflg2_desc[] = {
+  { M6811_TOF,   "TOF   ", "Timer Overflow Bit" },
+  { M6811_RTIF,  "RTIF  ", "Read Time Interrupt Flag" },
+  { M6811_PAOVF, "PAOVF ", "Pulse Accumulator Overflow Interrupt Flag" },
+  { M6811_PAIF,  "PAIF  ", "Pulse Accumulator Input Edge" },
+  { 0,  0, 0 }
+};
+
+io_reg_desc pactl_desc[] = {
+  { M6811_DDRA7,  "DDRA7 ", "Data Direction for Port A bit-7" },
+  { M6811_PAEN,   "PAEN  ", "Pulse Accumulator System Enable" },
+  { M6811_PAMOD,  "PAMOD ", "Pulse Accumulator Mode" },
+  { M6811_PEDGE,  "PEDGE ", "Pulse Accumulator Edge Control" },
+  { M6811_RTR1,   "RTR1  ", "RTI Interrupt rate select (RTR1)" },
+  { M6811_RTR0,   "RTR0  ", "RTI Interrupt rate select (RTR0)" },
+  { 0,  0, 0 }
+};
+
+static double
+to_realtime (sim_cpu *cpu, signed64 t)
+{
+  return (double) (t) / (double) (cpu->cpu_frequency / 4);
+}
+
+static void
+m68hc11tim_print_timer (struct hw *me, const char *name,
+                        struct hw_event *event)
+{
+  SIM_DESC sd;
+  
+  sd = hw_system (me);
+  if (event == 0)
+    {
+      sim_io_printf (sd, "  No %s interrupt will be raised.\n", 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);
+    }
+}
+
+static void
+m68hc11tim_info (struct hw *me)
+{
+  SIM_DESC sd;
+  uint16 base = 0;
+  sim_cpu *cpu;
+  struct m68hc11tim *controller;
+  uint8 val;
+  
+  sd = hw_system (me);
+  cpu = STATE_CPU (sd, 0);
+  controller = hw_data (me);
+  
+  sim_io_printf (sd, "M68HC11 Timer:\n");
+
+  base = cpu_get_io_base (cpu);
+
+  val  = cpu->ios[M6811_TMSK2];
+  print_io_byte (sd, "TMSK2 ", tmsk2_desc, val, base + M6811_TMSK2);
+  sim_io_printf (sd, "\n");
+
+  val = cpu->ios[M6811_TFLG2];
+  print_io_byte (sd, "TFLG2", tflg2_desc, val, base + M6811_TFLG2);
+  sim_io_printf (sd, "\n");
+
+  val = cpu->ios[M6811_PACTL];
+  print_io_byte (sd, "PACTL", pactl_desc, val, base + M6811_PACTL);
+  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);
+  m68hc11tim_print_timer (me, "OVERFLOW", controller->tof_timer_event);
+  m68hc11tim_print_timer (me, "COMPARE", controller->cmp_timer_event);
+}
+
+static int
+m68hc11tim_ioctl (struct hw *me,
+                  hw_ioctl_request request,
+                  va_list ap)
+{
+  m68hc11tim_info (me);
+  return 0;
+}
+
+/* generic read/write */
+
+static unsigned
+m68hc11tim_io_read_buffer (struct hw *me,
+                           void *dest,
+                           int space,
+                           unsigned_word base,
+                           unsigned nr_bytes)
+{
+  SIM_DESC sd;
+  struct m68hc11tim *controller;
+  sim_cpu *cpu;
+  unsigned8 val;
+  
+  HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
+
+  sd  = hw_system (me);
+  cpu = STATE_CPU (sd, 0);
+  controller = hw_data (me);
+
+  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;
+
+    default:
+      val = cpu->ios[base];
+      break;
+    }
+  *((unsigned8*) dest) = val;
+  return 1;
+}
+
+static unsigned
+m68hc11tim_io_write_buffer (struct hw *me,
+                            const void *source,
+                            int space,
+                            unsigned_word base,
+                            unsigned nr_bytes)
+{
+  SIM_DESC sd;
+  struct m68hc11tim *controller;
+  sim_cpu *cpu;
+  unsigned8 val, n;
+  signed64 adj;
+  int reset_compare = 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)
+    {
+      /* 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;
+
+    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_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;
+          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;
+
+      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;
+
+      /* 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_TOC1:
+    case M6811_TOC2:
+    case M6811_TOC3:
+    case M6811_TOC4:
+    case M6811_TOC5:
+      cpu->ios[base] = val;
+      reset_compare = 1;
+      break;
+      
+    default:
+      return 0;
+    }
+
+  /* Re-compute the next timer compare event.  */
+  if (reset_compare)
+    {
+      m68hc11tim_timer_event (me, (void*) (COMPARE_EVENT));
+    }
+  return nr_bytes;
+}     
+
+
+const struct hw_descriptor dv_m68hc11tim_descriptor[] = {
+  { "m68hc11tim", m68hc11tim_finish, },
+  { NULL },
+};
+
diff --git a/sim/m68hc11/dv-nvram.c b/sim/m68hc11/dv-nvram.c
new file mode 100644 (file)
index 0000000..6ffea5d
--- /dev/null
@@ -0,0 +1,361 @@
+/*  dv-nvram.c -- Generic driver for a non volatile ram (battery saved)
+    Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+    Written by Stephane Carrez (stcarrez@worldnet.fr)
+    (From a driver model Contributed by Cygnus Solutions.)
+    
+    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 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.
+    
+    */
+
+
+#include "sim-main.h"
+#include "hw-main.h"
+#include "sim-assert.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+
+/* DEVICE
+
+        nvram - Non Volatile Ram
+
+   
+   DESCRIPTION
+
+        Implements a generic battery saved CMOS ram. This ram device does
+        not contain any realtime clock and does not generate any interrupt.
+        The ram content is loaded from a file and saved when it is changed.
+        It is intended to be generic.
+
+   
+   PROPERTIES
+
+   overlap? <bool>
+
+        Boolean property which indicates whether the device can overlap
+        another device.  By default, overlapping is not allowed.
+
+   reg <base> <length>
+
+        Base and size of the non-volatile ram bank.
+
+   file <path>
+
+        Path where the memory must be saved or loaded when we start.
+
+   mode {map | save-modified | save-all}
+
+        Controls how to load and save the memory content.
+
+           map            The file is mapped in memory
+           save-modified  The simulator keeps an open file descriptor to
+                          the file and saves portion of memory which are
+                          modified. 
+           save-all       The simulator saves the complete memory each time
+                          it's modified (it does not keep an open file
+                          descriptor).
+
+
+   PORTS
+
+        None.
+
+
+   NOTES
+
+        This device is independent of the Motorola 68hc11.
+
+   */
+
+
+
+/* static functions */
+
+/* Control of how to access the ram and save its content.  */
+
+enum nvram_mode
+{
+  /* Save the complete ram block each time it's changed.
+     We don't keep an open file descriptor.  This should be
+     ok for small memory banks.  */
+  NVRAM_SAVE_ALL,
+
+  /* Save only the memory bytes which are modified.
+     This mode means that we have to keep an open file
+     descriptor (O_RDWR).  It's good for middle sized memory banks.  */
+  NVRAM_SAVE_MODIFIED,
+
+  /* Map file in memory (not yet implemented).
+     This mode is suitable for large memory banks.  We don't allocate
+     a buffer to represent the ram, instead it's mapped in memory
+     with mmap.  */
+  NVRAM_MAP_FILE
+};
+
+struct nvram 
+{
+  address_word    base_address; /* Base address of ram.  */
+  unsigned        size;         /* Size of ram.  */
+  unsigned8       *data;        /* Pointer to ram memory.  */
+  const char      *file_name;   /* Path of ram file.  */
+  int             fd;           /* File description of opened ram file.  */
+  enum nvram_mode mode;         /* How load/save ram file.  */
+};
+
+
+
+/* Finish off the partially created hw device.  Attach our local
+   callbacks.  Wire up our port names etc.  */
+
+static hw_io_read_buffer_method  nvram_io_read_buffer;
+static hw_io_write_buffer_method nvram_io_write_buffer;
+
+
+
+static void
+attach_nvram_regs (struct hw *me, struct nvram *controller)
+{
+  unsigned_word attach_address;
+  int attach_space;
+  unsigned attach_size;
+  reg_property_spec reg;
+  int result, oerrno;
+
+  /* Get the flag that controls overlapping of ram bank to another device.  */
+  if (hw_find_property (me, "overlap?") != NULL
+      && hw_find_boolean_property (me, "overlap?"))
+    me->overlap_mode_hw = 1;
+
+  /* Get ram bank description (base and size).  */
+  if (hw_find_property (me, "reg") == NULL)
+    hw_abort (me, "Missing \"reg\" property");
+
+  if (!hw_find_reg_array_property (me, "reg", 0, &reg))
+    hw_abort (me, "\"reg\" property must contain one addr/size entry");
+
+  hw_unit_address_to_attach_address (hw_parent (me),
+                                    &reg.address,
+                                    &attach_space,
+                                    &attach_address,
+                                    me);
+  hw_unit_size_to_attach_size (hw_parent (me),
+                              &reg.size,
+                              &attach_size, me);
+
+  hw_attach_address (hw_parent (me), 0,
+                    attach_space, attach_address, attach_size,
+                    me);
+
+  controller->mode         = NVRAM_SAVE_ALL;
+  controller->base_address = attach_address;
+  controller->size         = attach_size;
+  controller->fd           = -1;
+  
+  /* Get the file where the ram content must be loaded/saved.  */
+  if(hw_find_property (me, "file") == NULL)
+    hw_abort (me, "Missing \"file\" property");
+  
+  controller->file_name = hw_find_string_property (me, "file");
+
+  /* Get the mode which defines how to save the memory.  */
+  if(hw_find_property (me, "mode") != NULL)
+    {
+      const char *value = hw_find_string_property (me, "mode");
+
+      if (strcmp (value, "map") == 0)
+        controller->mode = NVRAM_MAP_FILE;
+      else if (strcmp (value, "save-modified") == 0)
+        controller->mode = NVRAM_SAVE_MODIFIED;
+      else if (strcmp (value, "save-all") == 0)
+        controller->mode = NVRAM_SAVE_ALL;
+      else
+       hw_abort (me, "illegal value for mode parameter `%s': "
+                  "use map, save-modified or save-all", value);
+    }
+
+  /* Initialize the ram by loading/mapping the file in memory.
+     If the file does not exist, create and give it some content.  */
+  switch (controller->mode)
+    {
+    case NVRAM_MAP_FILE:
+      hw_abort (me, "'map' mode is not yet implemented, use 'save-modified'");
+      break;
+
+    case NVRAM_SAVE_MODIFIED:
+    case NVRAM_SAVE_ALL:
+      controller->data = (char*) malloc (attach_size);
+      if (controller->data == 0)
+        hw_abort (me, "Not enough memory, try to use the mode 'map'");
+
+      memset (controller->data, 0, attach_size);
+      controller->fd = open (controller->file_name, O_RDWR);
+      if (controller->fd < 0)
+        {
+          controller->fd = open (controller->file_name,
+                                 O_RDWR | O_CREAT, 0644);
+          if (controller->fd < 0)
+            hw_abort (me, "Cannot open or create file '%s'",
+                      controller->file_name);
+          result = write (controller->fd, controller->data, attach_size);
+          if (result != attach_size)
+            {
+              oerrno = errno;
+              free (controller->data);
+              close (controller->fd);
+              errno = oerrno;
+              hw_abort (me, "Failed to save the ram content");
+            }
+        }
+      else
+        {
+          result = read (controller->fd, controller->data, attach_size);
+          if (result != attach_size)
+            {
+              oerrno = errno;
+              free (controller->data);
+              close (controller->fd);
+              errno = oerrno;
+              hw_abort (me, "Failed to load the ram content");
+            }
+        }
+      if (controller->mode == NVRAM_SAVE_ALL)
+        {
+          close (controller->fd);
+          controller->fd = -1;
+        }
+      break;
+
+    default:
+      break;
+    }
+}
+
+
+static void
+nvram_finish (struct hw *me)
+{
+  struct nvram *controller;
+
+  controller = HW_ZALLOC (me, struct nvram);
+
+  set_hw_data (me, controller);
+  set_hw_io_read_buffer (me, nvram_io_read_buffer);
+  set_hw_io_write_buffer (me, nvram_io_write_buffer);
+
+  /* Attach ourself to our parent bus.  */
+  attach_nvram_regs (me, controller);
+}
+
+
+
+/* generic read/write */
+
+static unsigned
+nvram_io_read_buffer (struct hw *me,
+                      void *dest,
+                      int space,
+                      unsigned_word base,
+                      unsigned nr_bytes)
+{
+  struct nvram *controller = hw_data (me);
+  
+  HW_TRACE ((me, "read 0x%08lx %d [%ld]",
+             (long) base, (int) nr_bytes,
+             (long) (base - controller->base_address)));
+
+  base -= controller->base_address;
+  if (base + nr_bytes > controller->size)
+    nr_bytes = controller->size - base;
+  
+  memcpy (dest, &controller->data[base], nr_bytes);
+  return nr_bytes;
+}
+
+
+
+static unsigned
+nvram_io_write_buffer (struct hw *me,
+                       const void *source,
+                       int space,
+                       unsigned_word base,
+                       unsigned nr_bytes)
+{
+  struct nvram *controller = hw_data (me);
+
+  HW_TRACE ((me, "write 0x%08lx %d [%ld]",
+             (long) base, (int) nr_bytes,
+             (long) (base - controller->base_address)));
+
+  base -= controller->base_address;
+  if (base + nr_bytes > controller->size)
+    nr_bytes = controller->size - base;
+  
+  switch (controller->mode)
+    {
+    case NVRAM_SAVE_ALL:
+      {
+        int fd, result, oerrno;
+        
+        fd = open (controller->file_name, O_WRONLY, 0644);
+        if (fd < 0)
+          {
+            return 0;
+          }
+
+        memcpy (&controller->data[base], source, nr_bytes);
+        result = write (fd, controller->data, controller->size);
+        oerrno = errno;
+        close (fd);
+        errno = oerrno;
+  
+        if (result != controller->size)
+          {
+            return 0;
+          }
+        return nr_bytes;
+      }
+      
+    case NVRAM_SAVE_MODIFIED:
+      {
+        off_t pos;
+        int result;
+
+        pos = lseek (controller->fd, (off_t) base, SEEK_SET);
+        if (pos != (off_t) base)
+          return 0;
+
+        result = write (controller->fd, source, nr_bytes);
+        if (result < 0)
+          return 0;
+
+        nr_bytes = result;
+        break;
+      }
+
+    default:
+      break;
+    }
+  memcpy (&controller->data[base], source, nr_bytes);
+  return nr_bytes;
+}
+
+
+const struct hw_descriptor dv_nvram_descriptor[] = {
+  { "nvram", nvram_finish, },
+  { NULL },
+};
+
diff --git a/sim/m68hc11/emulos.c b/sim/m68hc11/emulos.c
new file mode 100644 (file)
index 0000000..bb9f27b
--- /dev/null
@@ -0,0 +1,161 @@
+/* emulos.c -- Small OS emulation
+   Copyright 1999, 2000 Free Software Foundation, Inc.
+   Written by Stephane Carrez (stcarrez@worldnet.fr)
+
+This file is part of GDB, GAS, and the GNU binutils.
+
+GDB, GAS, and the GNU binutils are free software; you can redistribute
+them and/or modify them under the terms of the GNU General Public
+License as published by the Free Software Foundation; either version
+1, or (at your option) any later version.
+
+GDB, GAS, and the GNU binutils are distributed in the hope that they
+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 file; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "sim-main.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifndef WIN32
+#include <sys/types.h>
+#include <sys/time.h>
+
+/* This file emulates some OS system calls.
+   It's basically used to give access to the host OS facilities
+   like: stdin, stdout, files, time of day.  */
+static int bench_mode = -1;
+static struct timeval bench_start;
+static struct timeval bench_stop;
+
+void
+emul_bench (struct _sim_cpu* cpu)
+{
+  int op;
+
+  op = cpu_get_d (cpu);
+  switch (op)
+    {
+    case 0:
+      bench_mode = 0;
+      gettimeofday (&bench_start, 0);
+      break;
+
+    case 1:
+      gettimeofday (&bench_stop, 0);
+      if (bench_mode != 0)
+        printf ("bench start not called...\n");
+      bench_mode = 1;
+      break;
+
+    case 2:
+      {
+        int sz = 0;
+        int addr = cpu_get_x (cpu);
+        double t_start, t_stop, t;
+        char buf[1024];
+
+        op = cpu_get_y (cpu);
+        t_start = (double) (bench_start.tv_sec) * 1.0e6;
+        t_start += (double) (bench_start.tv_usec);
+        t_stop  = (double) (bench_stop.tv_sec) * 1.0e6;
+        t_stop  += (double) (bench_stop.tv_usec);
+        
+        while (sz < 1024)
+          {
+            buf[sz] = memory_read8 (cpu, addr);
+            if (buf[sz] == 0)
+              break;
+
+            sz ++;
+            addr++;
+          }
+        buf[1023] = 0;
+
+        if (bench_mode != 1)
+          printf ("bench_stop not called");
+
+        bench_mode = -1;
+        t = t_stop - t_start;
+        printf ("%-40.40s [%6d] %3.3f us\n", buf,
+                op, t / (double) (op));
+        break;
+      }
+    }
+}
+#endif
+
+void
+emul_write(struct _sim_cpu* state)
+{
+  int addr = cpu_get_x (state) & 0x0FFFF;
+  int size = cpu_get_d (state) & 0x0FFFF;
+
+  if (addr + size > 0x0FFFF) {
+    size = 0x0FFFF - addr;
+  }
+  state->cpu_running = 0;
+  while (size)
+    {
+      uint8 val = memory_read8 (state, addr);
+        
+      write(0, &val, 1);
+      addr ++;
+      size--;
+    }
+}
+
+/* emul_exit () is used by the default startup code of GCC to implement
+   the exit ().  For a real target, this will create an ILLEGAL fault.
+   But doing an exit () on a real target is really a non-sense.
+   exit () is important for the validation of GCC.  The exit status
+   is passed in 'D' register.  */
+void
+emul_exit (sim_cpu *cpu)
+{
+  sim_engine_halt (CPU_STATE (cpu), cpu,
+                  NULL, NULL_CIA, sim_exited,
+                  cpu_get_d (cpu));
+}
+
+void
+emul_os (int code, sim_cpu *proc)
+{
+  proc->cpu_current_cycle = 8;
+  switch (code)
+    {
+    case 0x0:
+      break;
+
+      /* 0xCD 0x01 */
+    case 0x01:
+      emul_write (proc);
+      break;
+
+      /* 0xCD 0x02 */
+    case 0x02:
+      break;
+
+      /* 0xCD 0x03 */
+    case 0x03:
+      emul_exit (proc);
+      break;
+
+      /* 0xCD 0x04 */
+    case 0x04:
+#ifndef WIN32
+      emul_bench (proc);
+#endif
+      break;
+        
+    default:
+      break;
+    }
+}
+
diff --git a/sim/m68hc11/gencode.c b/sim/m68hc11/gencode.c
new file mode 100644 (file)
index 0000000..a5bff86
--- /dev/null
@@ -0,0 +1,1484 @@
+/* gencode.c -- Motorola 68hc11 Emulator Generator
+   Copyright 1999, 2000 Free Software Foundation, Inc.
+   Written by Stephane Carrez (stcarrez@worldnet.fr)
+
+This file is part of GDB, GAS, and the GNU binutils.
+
+GDB, GAS, and the GNU binutils are free software; you can redistribute
+them and/or modify them 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.
+
+GDB, GAS, and the GNU binutils are distributed in the hope that they
+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.  */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#include "ansidecl.h"
+#include "opcode/m68hc11.h"
+
+#define TABLE_SIZE(X)      (sizeof(X) / sizeof(X[0]))
+
+/* Combination of CCR flags.  */
+#define M6811_ZC_BIT   M6811_Z_BIT|M6811_C_BIT
+#define M6811_NZ_BIT   M6811_N_BIT|M6811_Z_BIT
+#define M6811_NZV_BIT  M6811_N_BIT|M6811_Z_BIT|M6811_V_BIT
+#define M6811_NVC_BIT  M6811_N_BIT|M6811_V_BIT|M6811_C_BIT
+#define M6811_ZVC_BIT  M6811_Z_BIT|M6811_V_BIT|M6811_C_BIT
+#define M6811_NZVC_BIT M6811_ZVC_BIT|M6811_N_BIT
+#define M6811_HNZVC_BIT M6811_NZVC_BIT|M6811_H_BIT
+
+/* Flags when the insn only changes some CCR flags.  */
+#define CHG_NONE       0,0,0
+#define CHG_Z          0,0,M6811_Z_BIT
+#define CHG_C          0,0,M6811_C_BIT
+#define CHG_ZVC                0,0,M6811_ZVC_BIT
+#define CHG_NZV                0,0,M6811_NZV_BIT
+#define CHG_NZVC       0,0,M6811_NZVC_BIT
+#define CHG_HNZVC      0,0,M6811_HNZVC_BIT
+#define CHG_ALL                0,0,0xff
+
+/* The insn clears and changes some flags.  */
+#define CLR_I          0,M6811_I_BIT,0
+#define CLR_C          0,M6811_C_BIT,0
+#define CLR_V          0,M6811_V_BIT,0
+#define CLR_V_CHG_ZC   0,M6811_V_BIT,M6811_ZC_BIT
+#define CLR_V_CHG_NZ   0,M6811_V_BIT,M6811_NZ_BIT
+#define CLR_V_CHG_ZVC  0,M6811_V_BIT,M6811_ZVC_BIT
+#define CLR_N_CHG_ZVC  0,M6811_N_BIT,M6811_ZVC_BIT /* Used by lsr */
+
+/* The insn sets some flags.  */
+#define SET_I          M6811_I_BIT,0,0
+#define SET_C          M6811_C_BIT,0,0
+#define SET_V          M6811_V_BIT,0,0
+#define SET_Z_CLR_NVC  M6811_Z_BIT,M6811_NVC_BIT,0
+#define SET_C_CLR_V_CHG_NZ M6811_C_BIT,M6811_V_BIT,M6811_NZ_BIT
+
+#define _M 0xff
+
+
+struct m6811_opcode_pattern 
+{
+  const char *name;
+  const char *pattern;
+  const char *ccr_update;
+};
+
+/*
+ *  { "test", M6811_OP_NONE, 1, 0x00, 5, _M,  CHG_NONE },
+ * Name -+                                      +---- Insn CCR changes
+ * Format  ------+                        +---------- Max # cycles
+ * Size            -----------------+        +--------------- Min # cycles
+ *                              +-------------------- Opcode
+ */
+struct m6811_opcode_pattern m6811_opcode_patterns[] = {
+  /* Move 8 and 16 bits.  We need two implementations: one that sets the
+     flags and one that preserve them. */
+  { "movtst8", "dst8 = src8",   "cpu_ccr_update_tst8 (proc, dst8)" },
+  { "movtst16", "dst16 = src16", "cpu_ccr_update_tst16 (proc, dst16)" },
+  { "mov8",    "dst8 = src8" },
+  { "mov16",   "dst16 = src16" },
+
+  /* Conditional branches.  'addr' is the address of the branch.  */
+  { "bra", "cpu_set_pc (proc, addr)" },
+  { "bhi",
+   "if ((cpu_get_ccr (proc) & (M6811_C_BIT|M6811_Z_BIT)) == 0)\n@ \
+     cpu_set_pc (proc, addr)" },
+  { "bls",
+    "if ((cpu_get_ccr (proc) & (M6811_C_BIT|M6811_Z_BIT)))\n@ \
+     cpu_set_pc (proc, addr)" },
+  { "bcc", "if (!cpu_get_ccr_C (proc))\n@ cpu_set_pc (proc, addr)" },
+  { "bcs", "if (cpu_get_ccr_C (proc))\n@ cpu_set_pc (proc, addr)" },
+  { "bne", "if (!cpu_get_ccr_Z (proc))\n@ cpu_set_pc (proc, addr)" },
+  { "beq", "if (cpu_get_ccr_Z (proc))\n@ cpu_set_pc (proc, addr)" },
+  { "bvc", "if (!cpu_get_ccr_V (proc))\n@ cpu_set_pc (proc, addr)" },
+  { "bvs", "if (cpu_get_ccr_V (proc))\n@ cpu_set_pc (proc, addr)" },
+  { "bpl", "if (!cpu_get_ccr_N (proc))\n@ cpu_set_pc (proc, addr)" },
+  { "bmi", "if (cpu_get_ccr_N (proc))\n@ cpu_set_pc (proc, addr)" },
+  { "bge", "if ((cpu_get_ccr_N (proc) ^ cpu_get_ccr_V (proc)) == 0)\n@ cpu_set_pc (proc, addr)" },
+  { "blt", "if ((cpu_get_ccr_N (proc) ^ cpu_get_ccr_V (proc)))\n@ cpu_set_pc (proc, addr)" },
+  { "bgt",
+    "if ((cpu_get_ccr_Z (proc) | (cpu_get_ccr_N (proc) ^ cpu_get_ccr_V (proc))) == 0)\n@ \
+     cpu_set_pc (proc, addr)" },
+  { "ble",
+    "if ((cpu_get_ccr_Z (proc) | (cpu_get_ccr_N (proc) ^ cpu_get_ccr_V (proc))))\n@ \
+     cpu_set_pc (proc, addr)" },
+
+  /* brclr and brset perform a test and a conditional jump at the same
+     time.  Flags are not changed.  */
+  { "brclr8",
+    "if ((src8 & dst8) == 0)\n@         cpu_set_pc (proc, addr)" },
+  { "brset8",
+    "if (((~src8) & dst8) == 0)\n@  cpu_set_pc (proc, addr)" },
+  
+
+  { "rts",  "addr = cpu_pop_uint16 (proc); cpu_set_pc (proc, addr); cpu_return(proc)" },
+
+  { "mul16", "dst16 = ((uint16) src8 & 0x0FF) * ((uint16) dst8 & 0x0FF)",
+    "cpu_set_ccr_C (proc, src8 & 0x80)" },
+  { "neg8", "dst8 = - src8",
+    "cpu_set_ccr_C (proc, src8 == 0); cpu_ccr_update_tst8 (proc, dst8)" },
+  { "com8", "dst8 = ~src8",
+    "cpu_set_ccr_C (proc, 1); cpu_ccr_update_tst8 (proc, dst8);" },
+  { "clr8", "dst8 = 0",
+    "cpu_set_ccr (proc, (cpu_get_ccr (proc) & (M6811_S_BIT|M6811_X_BIT|M6811_H_BIT| \
+M6811_I_BIT)) | M6811_Z_BIT)"},
+  { "clr16","dst16 = 0",
+    "cpu_set_ccr (proc, (cpu_get_ccr (proc) & (M6811_S_BIT|M6811_X_BIT|M6811_H_BIT| \
+M6811_I_BIR)) | M6811_Z_BIT)"},
+
+  /* 8-bits shift and rotation.         */
+  { "lsr8",  "dst8 = src8 >> 1",
+    "cpu_set_ccr_C (proc, src8 & 1); cpu_ccr_update_shift8 (proc, dst8)" },
+  { "lsl8",  "dst8 = src8 << 1",
+    "cpu_set_ccr_C (proc, (src8 & 0x80) >> 7); cpu_ccr_update_shift8 (proc, dst8)" },
+  { "asr8",  "dst8 = (src8 >> 1) | (src8 & 0x80)",
+    "cpu_set_ccr_C (proc, src8 & 1); cpu_ccr_update_shift8 (proc, dst8)" },
+  { "ror8",  "dst8 = (src8 >> 1) | (cpu_get_ccr_C (proc) << 7)",
+    "cpu_set_ccr_C (proc, src8 & 1); cpu_ccr_update_shift8 (proc, dst8)" },
+  { "rol8",  "dst8 = (src8 << 1) | (cpu_get_ccr_C (proc))",
+    "cpu_set_ccr_C (proc, (src8 & 0x80) >> 7); cpu_ccr_update_shift8 (proc, dst8)" },
+
+  /* 16-bits shift instructions.  */
+  { "lsl16",  "dst16 = src16 << 1",
+    "cpu_set_ccr_C (proc, (src16&0x8000) >> 15); cpu_ccr_update_shift16 (proc, dst16)"},
+  { "lsr16",  "dst16 = src16 >> 1",
+    "cpu_set_ccr_C (proc, src16 & 1); cpu_ccr_update_shift16 (proc, dst16)"},
+
+  { "dec8", "dst8 = src8 - 1", "cpu_ccr_update_tst8 (proc, dst8)" },
+  { "inc8", "dst8 = src8 + 1", "cpu_ccr_update_tst8 (proc, dst8)" },
+  { "tst8", 0, "cpu_set_ccr_C (proc, 0); cpu_ccr_update_tst8 (proc, src8)" },
+
+  { "sub8", "cpu_ccr_update_sub8 (proc, dst8 - src8, dst8, src8);\
+dst8 = dst8 - src8", 0 },
+  { "add8", "cpu_ccr_update_add8 (proc, dst8 + src8, dst8, src8);\
+dst8 = dst8 + src8", 0 },
+  { "sbc8", "if (cpu_get_ccr_C (proc))\n@ \
+{\n\
+  cpu_ccr_update_sub8 (proc, dst8 - src8 - 1, dst8, src8);\n\
+  dst8 = dst8 - src8 - 1;\n\
+}\n\
+else\n\
+{\n\
+  cpu_ccr_update_sub8 (proc, dst8 - src8, dst8, src8);\n\
+  dst8 = dst8 - src8;\n\
+}", 0 },
+  { "adc8", "if (cpu_get_ccr_C (proc))\n@ \
+{\n\
+  cpu_ccr_update_add8 (proc, dst8 + src8 + 1, dst8, src8);\n\
+  dst8 = dst8 + src8 + 1;\n\
+}\n\
+else\n\
+{\n\
+  cpu_ccr_update_add8 (proc, dst8 + src8, dst8, src8);\n\
+  dst8 = dst8 + src8;\n\
+}",
+    0 },
+
+  /* 8-bits logical operations.         */
+  { "and8", "dst8 = dst8 & src8", "cpu_ccr_update_tst8 (proc, dst8)" },
+  { "eor8", "dst8 = dst8 ^ src8", "cpu_ccr_update_tst8 (proc, dst8)" },
+  { "or8",  "dst8 = dst8 | src8", "cpu_ccr_update_tst8 (proc, dst8)" },
+  { "bclr8","dst8 = (~dst8) & src8", "cpu_ccr_update_tst8 (proc, dst8)" },
+
+  /* 16-bits add and subtract instructions.  */
+  { "sub16", "cpu_ccr_update_sub16 (proc, dst16 - src16, dst16, src16);\
+dst16 = dst16 - src16", 0 },
+  { "add16", "cpu_ccr_update_add16 (proc, dst16 + src16, dst16, src16);\
+dst16 = dst16 + src16", 0 },
+  { "inc16", "dst16 = src16 + 1", "cpu_set_ccr_Z (proc, dst16 == 0)" },
+  { "dec16", "dst16 = src16 - 1", "cpu_set_ccr_Z (proc, dst16 == 0)" },
+
+  /* Special increment/decrement for the stack pointer:
+     flags are not changed.  */
+  { "ins16", "dst16 = src16 + 1" },
+  { "des16", "dst16 = src16 - 1" },
+  
+  { "jsr16", "cpu_push_uint16 (proc, cpu_get_pc (proc)); cpu_call (proc, addr)"},
+
+  /* xgdx and xgdx patterns. Flags are not changed.  */
+  { "xgdxy16", "dst16 = cpu_get_d (proc); cpu_set_d (proc, src16)"},
+  { "stop", ""},
+
+  /* tsx, tsy, txs, tys don't affect the flags.         Sp value is corrected
+     by +/- 1. */
+  { "tsxy16", "dst16 = src16 + 1;"},
+  { "txys16", "dst16 = src16 - 1;"},
+
+  /* Add b to X or Y with an unsigned extension 8->16. Flags not changed.  */
+  { "abxy16","dst16 = dst16 + (uint16) src8"},
+
+  /* After 'daa', the Z flag is undefined. Mark it as changed. */
+  { "daa8",  "" },
+  { "nop",  0 },
+
+
+  /* Integer divide:
+     (parallel (set IX (div D IX))
+              (set D  (mod D IX)))  */
+  { "idiv16", "if (src16 == 0)\n{\n\
+dst16 = 0xffff;\
+}\nelse\n{\n\
+cpu_set_d (proc, dst16 % src16);\
+dst16 = dst16 / src16;\
+}",
+  "cpu_set_ccr_Z (proc, dst16 == 0); cpu_set_ccr_V (proc, 0);\
+cpu_set_ccr_C (proc, src16 == 0)" },
+
+  /* Fractional divide:
+     (parallel (set IX (div (mul D 65536) IX)
+              (set D  (mod (mul D 65536) IX))))  */
+  { "fdiv16", "if (src16 <= dst16 )\n{\n\
+dst16 = 0xffff;\n\
+cpu_set_ccr_Z (proc, 0);\n\
+cpu_set_ccr_V (proc, 1);\n\
+cpu_set_ccr_C (proc, dst16 == 0);\n\
+}\nelse\n{\n\
+unsigned long l = (unsigned long) (dst16) << 16;\n\
+cpu_set_d (proc, (uint16) (l % (unsigned long) (src16)));\n\
+dst16 = (uint16) (l / (unsigned long) (src16));\n\
+cpu_set_ccr_V (proc, 0);\n\
+cpu_set_ccr_C (proc, 0);\n\
+cpu_set_ccr_Z (proc, dst16 == 0);\n\
+}", 0 },
+
+  /* Operations to get/set the CCR.  */
+  { "clv",  0, "cpu_set_ccr_V (proc, 0)" },
+  { "sev",  0, "cpu_set_ccr_V (proc, 1)" },
+  { "clc",  0, "cpu_set_ccr_C (proc, 0)" },
+  { "sec",  0, "cpu_set_ccr_C (proc, 1)" },
+  { "cli",  0, "cpu_set_ccr_I (proc, 0)" },
+  { "sei",  0, "cpu_set_ccr_I (proc, 1)" },
+
+  /* Some special instructions are implemented by 'cpu_special'.  */
+  { "rti",  "cpu_special (proc, M6811_RTI)" },
+  { "wai",  "cpu_special (proc, M6811_WAI)" },
+  { "test", "cpu_special (proc, M6811_TEST)" },
+  { "swi",  "cpu_special (proc, M6811_SWI)" },
+  { "syscall","cpu_special (proc, M6811_EMUL_SYSCALL)" },
+
+  { "page2", "cpu_page2_interp (proc)", 0 },
+  { "page3", "cpu_page3_interp (proc)", 0 },
+  { "page4", "cpu_page4_interp (proc)", 0 }
+};
+
+/* Definition of an opcode of the 68HC11.  */
+struct m6811_opcode_def
+{
+  const char    *name;
+  const char    *operands;
+  const char    *insn_pattern;
+  unsigned char         insn_size;
+  unsigned char         insn_code;
+  unsigned char         insn_min_cycles;
+  unsigned char         insn_max_cycles;
+  unsigned char         set_flags_mask;
+  unsigned char         clr_flags_mask;
+  unsigned char         chg_flags_mask;
+};
+
+
+/*
+ *  { "dex", "x->x", "dec16", 1, 0x00, 5, _M,  CHG_NONE },
+ * Name -+                                      +----- Insn CCR changes
+ * Operands  ---+                        +------------ Max # cycles
+ * Pattern   -----------+             +--------------- Min # cycles
+ * Size             -----------------+   +-------------------- Opcode
+ *
+ * Operands   Fetch operand            Save result
+ * -------    --------------           ------------
+ * x->x              src16 = x                 x = dst16
+ * d->d              src16 = d                 d = dst16
+ * b,a->a     src8 = b dst8 = a                a = dst8
+ * sp->x      src16 = sp               x = dst16
+ * (sp)->a    src8 = pop8              a = dst8
+ * a->(sp)    src8 = a                 push8 dst8
+ * (x)->(x)   src8 = (IND, X)          (IND, X) = dst8
+ * (y)->a     src8 = (IND, Y)          a = dst8
+ * ()->b      src8 = (EXT)             b = dst8
+ */
+const struct m6811_opcode_def m6811_page1_opcodes[] = {
+  { "test", 0,         0,           1, 0x00,  5, _M,  CHG_NONE },
+  { "nop",  0,         0,           1, 0x01,  2,  2,  CHG_NONE },
+  { "idiv", "x,d->x",  "idiv16",    1, 0x02,  3, 41,  CLR_V_CHG_ZC},
+  { "fdiv", "x,d->x",  "fdiv16",    1, 0x03,  3, 41,  CHG_ZVC},
+  { "lsrd", "d->d",    "lsr16",     1, 0x04,  3,  3,  CLR_N_CHG_ZVC },
+  { "asld", "d->d",    "lsl16",     1, 0x05,  3,  3,  CHG_NZVC },
+  { "lsld", "d->d",    "lsl16",     1, 0x05,  3,  3,  CHG_NZVC },
+  { "tap",  "a->ccr",  "mov8",      1, 0x06,  2,  2,  CHG_ALL},
+  { "tpa",  "ccr->a",  "mov8",      1, 0x07,  2,  2,  CHG_NONE },
+  { "inx",  "x->x",    "inc16",     1, 0x08,  3,  3,  CHG_Z },
+  { "dex",  "x->x",    "dec16",     1, 0x09,  3,  3,  CHG_Z },
+  { "clv",  0,         0,           1, 0x0a,  2,  2,  CLR_V },
+  { "sev",  0,         0,           1, 0x0b,  2,  2,  SET_V },
+  { "clc",  0,         0,           1, 0x0c,  2,  2,  CLR_C },
+  { "sec",  0,         0,           1, 0x0d,  2,  2,  SET_C },
+  { "cli",  0,         0,           1, 0x0e,  2,  2,  CLR_I },
+  { "sei",  0,         0,           1, 0x0f,  2,  2,  SET_I },
+  { "sba",  "b,a->a",  "sub8",      1, 0x10,  2,  2,  CHG_NZVC },
+  { "cba",  "b,a",     "sub8",      1, 0x11,  2,  2,  CHG_NZVC },
+  { "brset","*,#,r",   "brset8",    4, 0x12,  6,  6, CHG_NONE },
+  { "brclr","*,#,r",   "brclr8",    4, 0x13,  6,  6, CHG_NONE },
+  { "bset", "*,#->*",  "or8",       3, 0x14,  6,  6, CLR_V_CHG_NZ },
+  { "bclr", "*,#->*",  "bclr8",     3, 0x15,  6,  6, CLR_V_CHG_NZ },
+  { "tab",  "a->b",    "movtst8",   1, 0x16,  2,  2, CLR_V_CHG_NZ },
+  { "tba",  "b->a",    "movtst8",   1, 0x17,  2,  2, CLR_V_CHG_NZ },
+  { "page2", 0,                "page2",     1, 0x18,  0,  0, CHG_NONE },
+  { "page3", 0,                "page3",     1, 0x1a,  0,  0, CHG_NONE },
+
+  /* After 'daa', the Z flag is undefined.  Mark it as changed.         */
+  { "daa",  "a->a",    "daa8",      1, 0x19,  2,  2, CHG_NZVC },
+  { "aba",  "b,a->a",  "add8",      1, 0x1b,  2,  2, CHG_HNZVC},
+  { "bset", "(x),#->(x)","or8",             3, 0x1c,  7,  7, CLR_V_CHG_NZ },
+  { "bclr", "(x),#->(x)","bclr8",    3, 0x1d,  7,  7, CLR_V_CHG_NZ },
+  { "brset","(x),#,r", "brset8",    4, 0x1e,  7,  7, CHG_NONE },
+  { "brclr","(x),#,r", "brclr8",    4, 0x1f,  7,  7, CHG_NONE },
+
+  /* Relative branch.  All of them take 3 bytes.  Flags not changed.  */
+  { "bra",  "r",       0,           2, 0x20,  3,  3, CHG_NONE },
+  { "brn",  "r",       "nop",       2, 0x21,  3,  3, CHG_NONE },
+  { "bhi",  "r",       0,           2, 0x22,  3,  3, CHG_NONE },
+  { "bls",  "r",       0,           2, 0x23,  3,  3, CHG_NONE },
+  { "bcc",  "r",       0,           2, 0x24,  3,  3, CHG_NONE },
+  { "bhs",  "r",       0,           2, 0x24,  3,  3, CHG_NONE },
+  { "bcs",  "r",       0,           2, 0x25,  3,  3, CHG_NONE },
+  { "blo",  "r",       0,           2, 0x25,  3,  3, CHG_NONE },
+  { "bne",  "r",       0,           2, 0x26,  3,  3, CHG_NONE },
+  { "beq",  "r",       0,           2, 0x27,  3,  3, CHG_NONE },
+  { "bvc",  "r",       0,           2, 0x28,  3,  3, CHG_NONE },
+  { "bvs",  "r",       0,           2, 0x29,  3,  3, CHG_NONE },
+  { "bpl",  "r",       0,           2, 0x2a,  3,  3, CHG_NONE },
+  { "bmi",  "r",       0,           2, 0x2b,  3,  3, CHG_NONE },
+  { "bge",  "r",       0,           2, 0x2c,  3,  3, CHG_NONE },
+  { "blt",  "r",       0,           2, 0x2d,  3,  3, CHG_NONE },
+  { "bgt",  "r",       0,           2, 0x2e,  3,  3, CHG_NONE },
+  { "ble",  "r",       0,           2, 0x2f,  3,  3, CHG_NONE },
+
+  { "tsx",  "sp->x",   "tsxy16",    1, 0x30,  3,  3, CHG_NONE },
+  { "ins",  "sp->sp",  "ins16",     1, 0x31,  3,  3, CHG_NONE },
+  { "pula", "(sp)->a", "mov8",      1, 0x32,  4,  4, CHG_NONE },
+  { "pulb", "(sp)->b", "mov8",      1, 0x33,  4,  4, CHG_NONE },
+  { "des",  "sp->sp",  "des16",     1, 0x34,  3,  3, CHG_NONE },
+  { "txs",  "x->sp",   "txys16",    1, 0x35,  3,  3, CHG_NONE },
+  { "psha", "a->(sp)", "mov8",      1, 0x36,  3,  3, CHG_NONE },
+  { "pshb", "b->(sp)", "mov8",      1, 0x37,  3,  3, CHG_NONE },
+  { "pulx", "(sp)->x", "mov16",     1, 0x38,  5,  5, CHG_NONE },
+  { "rts",  0,         0,           1, 0x39,  5,  5, CHG_NONE },
+  { "abx",  "b,x->x",  "abxy16",    1, 0x3a,  3,  3, CHG_NONE },
+  { "rti",  0,         0,           1, 0x3b, 12, 12, CHG_ALL},
+  { "pshx", "x->(sp)", "mov16",     1, 0x3c,  4,  4, CHG_NONE },
+  { "mul",  "b,a->d",  "mul16",     1, 0x3d,  3, 10, CHG_C },
+  { "wai",  0,         0,           1, 0x3e, 14, _M, CHG_NONE },
+  { "swi",  0,         0,           1, 0x3f, 14, _M, CHG_NONE },
+  { "nega", "a->a",    "neg8",      1, 0x40,  2,  2, CHG_NZVC },
+  { "syscall", "",     "syscall",   1, 0x41,  2,  2, CHG_NONE },
+  { "coma", "a->a",    "com8",      1, 0x43,  2,  2, SET_C_CLR_V_CHG_NZ },
+  { "lsra", "a->a",    "lsr8",      1, 0x44,  2,  2, CLR_N_CHG_ZVC},
+  { "rora", "a->a",    "ror8",      1, 0x46,  2,  2, CHG_NZVC },
+  { "asra", "a->a",    "asr8",      1, 0x47,  2,  2, CHG_NZVC },
+  { "asla", "a->a",    "lsl8",      1, 0x48,  2,  2, CHG_NZVC },
+  { "lsla", "a->a",    "lsl8",      1, 0x48,  2,  2, CHG_NZVC },
+  { "rola", "a->a",    "rol8",      1, 0x49,  2,  2, CHG_NZVC },
+  { "deca", "a->a",    "dec8",      1, 0x4a,  2,  2, CHG_NZV },
+  { "inca", "a->a",    "inc8",      1, 0x4c,  2,  2, CHG_NZV },
+  { "tsta", "a",       "tst8",      1, 0x4d,  2,  2, CLR_V_CHG_NZ },
+  { "clra", "->a",     "clr8",      1, 0x4f,  2,  2, SET_Z_CLR_NVC },
+  { "negb", "b->b",    "neg8",      1, 0x50,  2,  2, CHG_NZVC },
+  { "comb", "b->b",    "com8",      1, 0x53,  2,  2, SET_C_CLR_V_CHG_NZ },
+  { "lsrb", "b->b",    "lsr8",      1, 0x54,  2,  2, CLR_N_CHG_ZVC },
+  { "rorb", "b->b",    "ror8",      1, 0x56,  2,  2, CHG_NZVC },
+  { "asrb", "b->b",    "asr8",      1, 0x57,  2,  2, CHG_NZVC },
+  { "aslb", "b->b",    "lsl8",      1, 0x58,  2,  2, CHG_NZVC },
+  { "lslb", "b->b",    "lsl8",      1, 0x58,  2,  2, CHG_NZVC },
+  { "rolb", "b->b",    "rol8",      1, 0x59,  2,  2, CHG_NZVC },
+  { "decb", "b->b",    "dec8",      1, 0x5a,  2,  2, CHG_NZV },
+  { "incb", "b->b",    "inc8",      1, 0x5c,  2,  2, CHG_NZV },
+  { "tstb", "b",       "tst8",      1, 0x5d,  2,  2, CLR_V_CHG_NZ },
+  { "clrb", "->b",     "clr8",      1, 0x5f,  2,  2, SET_Z_CLR_NVC },
+  { "neg",  "(x)->(x)", "neg8",             2, 0x60,  6,  6, CHG_NZVC },
+  { "com",  "(x)->(x)", "com8",             2, 0x63,  6,  6, SET_C_CLR_V_CHG_NZ },
+  { "lsr",  "(x)->(x)", "lsr8",             2, 0x64,  6,  6, CLR_N_CHG_ZVC },
+  { "ror",  "(x)->(x)", "ror8",             2, 0x66,  6,  6, CHG_NZVC },
+  { "asr",  "(x)->(x)", "asr8",             2, 0x67,  6,  6, CHG_NZVC },
+  { "asl",  "(x)->(x)", "lsl8",             2, 0x68,  6,  6, CHG_NZVC },
+  { "lsl",  "(x)->(x)", "lsl8",             2, 0x68,  6,  6, CHG_NZVC },
+  { "rol",  "(x)->(x)", "rol8",             2, 0x69,  6,  6, CHG_NZVC },
+  { "dec",  "(x)->(x)", "dec8",             2, 0x6a,  6,  6, CHG_NZV },
+  { "inc",  "(x)->(x)", "inc8",             2, 0x6c,  6,  6, CHG_NZV },
+  { "tst",  "(x)",     "tst8",      2, 0x6d,  6,  6, CLR_V_CHG_NZ },
+  { "jmp",  "&(x)",    "bra",       2, 0x6e,  3,  3, CHG_NONE },
+  { "clr",  "->(x)",   "clr8",      2, 0x6f,  6,  6, SET_Z_CLR_NVC },
+  { "neg",  "()->()",  "neg8",      3, 0x70,  6,  6, CHG_NZVC },
+  { "com",  "()->()",  "com8",      3, 0x73,  6,  6, SET_C_CLR_V_CHG_NZ },
+  { "lsr",  "()->()",  "lsr8",      3, 0x74,  6,  6, CLR_V_CHG_ZVC },
+  { "ror",  "()->()",  "ror8",      3, 0x76,  6,  6, CHG_NZVC },
+  { "asr",  "()->()",  "asr8",      3, 0x77,  6,  6, CHG_NZVC },
+  { "asl",  "()->()",  "lsl8",      3, 0x78,  6,  6, CHG_NZVC },
+  { "lsl",  "()->()",  "lsl8",      3, 0x78,  6,  6, CHG_NZVC },
+  { "rol",  "()->()",  "rol8",      3, 0x79,  6,  6, CHG_NZVC },
+  { "dec",  "()->()",  "dec8",      3, 0x7a,  6,  6, CHG_NZV },
+  { "inc",  "()->()",  "inc8",      3, 0x7c,  6,  6, CHG_NZV },
+  { "tst",  "()",      "tst8",      3, 0x7d,  6,  6, CLR_V_CHG_NZ },
+  { "jmp",  "&()",     "bra",       3, 0x7e,  3,  3, CHG_NONE },
+  { "clr",  "->()",    "clr8",      3, 0x7f,  6,  6, SET_Z_CLR_NVC },
+  { "suba", "#,a->a",  "sub8",      2, 0x80,  2,  2, CHG_NZVC },
+  { "cmpa", "#,a",     "sub8",      2, 0x81,  2,  2, CHG_NZVC },
+  { "sbca", "#,a->a",  "sbc8",      2, 0x82,  2,  2, CHG_NZVC },
+  { "subd", "#,d->d",  "sub16",     3, 0x83,  4,  4, CHG_NZVC },
+  { "anda", "#,a->a",  "and8",      2, 0x84,  2,  2, CLR_V_CHG_NZ },
+  { "bita", "#,a",     "and8",      2, 0x85,  2,  2, CLR_V_CHG_NZ },
+  { "ldaa", "#->a",    "movtst8",   2, 0x86,  2,  2, CLR_V_CHG_NZ },
+  { "eora", "#,a->a",  "eor8",      2, 0x88,  2,  2, CLR_V_CHG_NZ },
+  { "adca", "#,a->a",  "adc8",      2, 0x89,  2,  2, CHG_HNZVC },
+  { "oraa", "#,a->a",  "or8",       2, 0x8a,  2,  2, CLR_V_CHG_NZ },
+  { "adda", "#,a->a",  "add8",      2, 0x8b,  2,  2, CHG_HNZVC },
+  { "cmpx", "#,x",     "sub16",     3, 0x8c,  4,  4, CHG_NZVC },
+  { "cpx",  "#,x",     "sub16",     3, 0x8c,  4,  4, CHG_NZVC },
+  { "bsr",  "r",       "jsr16",     2, 0x8d,  6,  6, CHG_NONE },
+  { "lds",  "#->sp",   "movtst16",  3, 0x8e,  3,  3, CLR_V_CHG_NZ },
+  { "xgdx", "x->x",    "xgdxy16",   1, 0x8f,  3,  3, CHG_NONE },
+  { "suba", "*,a->a",  "sub8",      2, 0x90,  3,  3, CHG_NZVC },
+  { "cmpa", "*,a",     "sub8",      2, 0x91,  3,  3, CHG_NZVC },
+  { "sbca", "*,a->a",  "sbc8",      2, 0x92,  3,  3, CHG_NZVC },
+  { "subd", "*,d->d",  "sub16",     2, 0x93,  5,  5, CHG_NZVC },
+  { "anda", "*,a->a",  "and8",      2, 0x94,  3,  3, CLR_V_CHG_NZ },
+  { "bita", "*,a",     "and8",      2, 0x95,  3,  3, CLR_V_CHG_NZ },
+  { "ldaa", "*->a",    "movtst8",   2, 0x96,  3,  3, CLR_V_CHG_NZ },
+  { "staa", "a->*",    "movtst8",   2, 0x97,  3,  3, CLR_V_CHG_NZ },
+  { "eora", "*,a->a",  "eor8",      2, 0x98,  3,  3, CLR_V_CHG_NZ },
+  { "adca", "*,a->a",  "adc8",      2, 0x99,  3,  3, CHG_HNZVC },
+  { "oraa", "*,a->a",  "or8",       2, 0x9a,  3,  3, CLR_V_CHG_NZ },
+  { "adda", "*,a->a",  "add8",      2, 0x9b,  3,  3, CHG_HNZVC },
+  { "cmpx", "*,x",     "sub16",     2, 0x9c,  5,  5, CHG_NZVC },
+  { "cpx",  "*,x",     "sub16",     2, 0x9c,  5,  5, CHG_NZVC },
+  { "jsr",  "*",       "jsr16",     2, 0x9d,  5,  5, CHG_NONE },
+  { "lds",  "*->sp",   "movtst16",  2, 0x9e,  4,  4, CLR_V_CHG_NZ },
+  { "sts",  "sp->*",   "movtst16",  2, 0x9f,  4,  4, CLR_V_CHG_NZ },
+  { "suba", "(x),a->a", "sub8",             2, 0xa0,  4,  4, CHG_NZVC },
+  { "cmpa", "(x),a",   "sub8",      2, 0xa1,  4,  4, CHG_NZVC },
+  { "sbca", "(x),a->a", "sbc8",             2, 0xa2,  4,  4, CHG_NZVC },
+  { "subd", "(x),d->d", "sub16",     2, 0xa3,  6,  6, CHG_NZVC },
+  { "anda", "(x),a->a", "and8",             2, 0xa4,  4,  4, CLR_V_CHG_NZ },
+  { "bita", "(x),a",   "and8",      2, 0xa5,  4,  4, CLR_V_CHG_NZ },
+  { "ldaa", "(x)->a",  "movtst8",   2, 0xa6,  4,  4, CLR_V_CHG_NZ },
+  { "staa", "a->(x)",  "movtst8",   2, 0xa7,  4,  4, CLR_V_CHG_NZ },
+  { "eora", "(x),a->a", "eor8",             2, 0xa8,  4,  4, CLR_V_CHG_NZ },
+  { "adca", "(x),a->a", "adc8",             2, 0xa9,  4,  4, CHG_HNZVC },
+  { "oraa", "(x),a->a", "or8",      2, 0xaa,  4,  4, CLR_V_CHG_NZ },
+  { "adda", "(x),a->a", "add8",             2, 0xab,  4,  4, CHG_HNZVC },
+  { "cmpx", "(x),x",   "sub16",     2, 0xac,  6,  6, CHG_NZVC },
+  { "cpx",  "(x),x",   "sub16",     2, 0xac,  6,  6, CHG_NZVC },
+  { "jsr",  "&(x)",    "jsr16",     2, 0xad,  6,  6, CHG_NONE },
+  { "lds",  "(x)->sp", "movtst16",  2, 0xae,  5,  5, CLR_V_CHG_NZ },
+  { "sts",  "sp->(x)", "movtst16",  2, 0xaf,  5,  5, CLR_V_CHG_NZ },
+  { "suba", "(),a->a", "sub8",      3, 0xb0,  4,  4, CHG_NZVC },
+  { "cmpa", "(),a",    "sub8",      3, 0xb1,  4,  4, CHG_NZVC },
+  { "sbca", "(),a->a", "sbc8",      3, 0xb2,  4,  4, CHG_NZVC },
+  { "subd", "(),d->d", "sub16",     3, 0xb3,  6,  6, CHG_NZVC },
+  { "anda", "(),a->a", "and8",      3, 0xb4,  4,  4, CLR_V_CHG_NZ },
+  { "bita", "(),a",    "and8",      3, 0xb5,  4,  4, CLR_V_CHG_NZ },
+  { "ldaa", "()->a",   "movtst8",   3, 0xb6,  4,  4, CLR_V_CHG_NZ },
+  { "staa", "a->()",   "movtst8",   3, 0xb7,  4,  4, CLR_V_CHG_NZ },
+  { "eora", "(),a->a", "eor8",      3, 0xb8,  4,  4, CLR_V_CHG_NZ },
+  { "adca", "(),a->a", "adc8",      3, 0xb9,  4,  4, CHG_HNZVC },
+  { "oraa", "(),a->a", "or8",       3, 0xba,  4,  4, CLR_V_CHG_NZ },
+  { "adda", "(),a->a", "add8",      3, 0xbb,  4,  4, CHG_HNZVC },
+  { "cmpx", "(),x",    "sub16",     3, 0xbc,  5,  5, CHG_NZVC },
+  { "cpx",  "(),x",    "sub16",     3, 0xbc,  5,  5, CHG_NZVC },
+  { "jsr",  "&()",     "jsr16",     3, 0xbd,  6,  6, CHG_NONE },
+  { "lds",  "()->sp",  "movtst16",  3, 0xbe,  5,  5, CLR_V_CHG_NZ },
+  { "sts",  "sp->()",  "movtst16",  3, 0xbf,  5,  5, CLR_V_CHG_NZ },
+  { "subb", "#,b->b",  "sub8",      2, 0xc0,  2,  2, CHG_NZVC },
+  { "cmpb", "#,b",     "sub8",      2, 0xc1,  2,  2, CHG_NZVC },
+  { "sbcb", "#,b->b",  "sbc8",      2, 0xc2,  2,  2, CHG_NZVC },
+  { "addd", "#,d->d",  "add16",     3, 0xc3,  4,  4, CHG_NZVC },
+  { "andb", "#,b->b",  "and8",      2, 0xc4,  2,  2, CLR_V_CHG_NZ },
+  { "bitb", "#,b",     "and8",      2, 0xc5,  2,  2, CLR_V_CHG_NZ },
+  { "ldab", "#->b",    "movtst8",   2, 0xc6,  2,  2, CLR_V_CHG_NZ },
+  { "eorb", "#,b->b",  "eor8",      2, 0xc8,  2,  2, CLR_V_CHG_NZ },
+  { "adcb", "#,b->b",  "adc8",      2, 0xc9,  2,  2, CHG_HNZVC },
+  { "orab", "#,b->b",  "or8",       2, 0xca,  2,  2, CLR_V_CHG_NZ },
+  { "addb", "#,b->b",  "add8",      2, 0xcb,  2,  2, CHG_HNZVC },
+  { "ldd",  "#->d",    "movtst16",  3, 0xcc,  3,  3, CLR_V_CHG_NZ },
+  { "page4",0,         "page4",     1, 0xcd,  0,  0, CHG_NONE },
+  { "ldx",  "#->x",    "movtst16",  3, 0xce,  3,  3, CLR_V_CHG_NZ },
+  { "stop", 0,         0,           1, 0xcf,  2,  2, CHG_NONE },
+  { "subb", "*,b->b",  "sub8",      2, 0xd0,  3,  3, CHG_NZVC },
+  { "cmpb", "*,b",     "sub8",      2, 0xd1,  3,  3, CHG_NZVC },
+  { "sbcb", "*,b->b",  "sbc8",      2, 0xd2,  3,  3, CHG_NZVC },
+  { "addd", "*,d->d",  "add16",     2, 0xd3,  5,  5, CHG_NZVC },
+  { "andb", "*,b->b",  "and8",      2, 0xd4,  3,  3, CLR_V_CHG_NZ },
+  { "bitb", "*,b",     "and8",      2, 0xd5,  3,  3, CLR_V_CHG_NZ },
+  { "ldab", "*->b",    "movtst8",   2, 0xd6,  3,  3, CLR_V_CHG_NZ },
+  { "stab", "b->*",    "movtst8",   2, 0xd7,  3,  3, CLR_V_CHG_NZ },
+  { "eorb", "*,b->b",  "eor8",      2, 0xd8,  3,  3, CLR_V_CHG_NZ },
+  { "adcb", "*,b->b",  "adc8",      2, 0xd9,  3,  3, CHG_HNZVC },
+  { "orab", "*,b->b",  "or8",       2, 0xda,  3,  3, CLR_V_CHG_NZ },
+  { "addb", "*,b->b",  "add8",      2, 0xdb,  3,  3, CHG_HNZVC },
+  { "ldd",  "*->d",    "movtst16",  2, 0xdc,  4,  4, CLR_V_CHG_NZ },
+  { "std",  "d->*",    "movtst16",  2, 0xdd,  4,  4, CLR_V_CHG_NZ },
+  { "ldx",  "*->x",    "movtst16",  2, 0xde,  4,  4, CLR_V_CHG_NZ },
+  { "stx",  "x->*",    "movtst16",  2, 0xdf,  4,  4, CLR_V_CHG_NZ },
+  { "subb", "(x),b->b", "sub8",             2, 0xe0,  4,  4, CHG_NZVC },
+  { "cmpb", "(x),b",   "sub8",      2, 0xe1,  4,  4, CHG_NZVC },
+  { "sbcb", "(x),b->b", "sbc8",             2, 0xe2,  4,  4, CHG_NZVC },
+  { "addd", "(x),d->d", "add16",     2, 0xe3,  6,  6, CHG_NZVC },
+  { "andb", "(x),b->b", "and8",             2, 0xe4,  4,  4, CLR_V_CHG_NZ },
+  { "bitb", "(x),b",   "and8",      2, 0xe5,  4,  4, CLR_V_CHG_NZ },
+  { "ldab", "(x)->b",  "movtst8",   2, 0xe6,  4,  4, CLR_V_CHG_NZ },
+  { "stab", "b->(x)",  "movtst8",   2, 0xe7,  4,  4, CLR_V_CHG_NZ },
+  { "eorb", "(x),b->b", "eor8",             2, 0xe8,  4,  4, CLR_V_CHG_NZ },
+  { "adcb", "(x),b->b", "adc8",             2, 0xe9,  4,  4, CHG_HNZVC },
+  { "orab", "(x),b->b", "or8",      2, 0xea,  4,  4, CLR_V_CHG_NZ },
+  { "addb", "(x),b->b", "add8",             2, 0xeb,  4,  4, CHG_HNZVC },
+  { "ldd",  "(x)->d",  "movtst16",  2, 0xec,  5,  5, CLR_V_CHG_NZ },
+  { "std",  "d->(x)",  "movtst16",  2, 0xed,  5,  5, CLR_V_CHG_NZ },
+  { "ldx",  "(x)->x",  "movtst16",  2, 0xee,  5,  5, CLR_V_CHG_NZ },
+  { "stx",  "x->(x)",  "movtst16",  2, 0xef,  5,  5, CLR_V_CHG_NZ },
+  { "subb", "(),b->b", "sub8",      3, 0xf0,  4,  4, CHG_NZVC },
+  { "cmpb", "(),b",    "sub8",      3, 0xf1,  4,  4, CHG_NZVC },
+  { "sbcb", "(),b->b", "sbc8",      3, 0xf2,  4,  4, CHG_NZVC },
+  { "addd", "(),d->d", "add16",     3, 0xf3,  6,  6, CHG_NZVC },
+  { "andb", "(),b->b", "and8",      3, 0xf4,  4,  4, CLR_V_CHG_NZ },
+  { "bitb", "(),b",    "and8",      3, 0xf5,  4,  4, CLR_V_CHG_NZ },
+  { "ldab", "()->b",   "movtst8",   3, 0xf6,  4,  4, CLR_V_CHG_NZ },
+  { "stab", "b->()",   "movtst8",   3, 0xf7,  4,  4, CLR_V_CHG_NZ },
+  { "eorb", "(),b->b", "eor8",      3, 0xf8,  4,  4, CLR_V_CHG_NZ },
+  { "adcb", "(),b->b", "eor8",      3, 0xf9,  4,  4, CHG_HNZVC },
+  { "orab", "(),b->b", "or8",       3, 0xfa,  4,  4, CLR_V_CHG_NZ },
+  { "addb", "(),b->b", "add8",      3, 0xfb,  4,  4, CHG_HNZVC },
+  { "ldd",  "()->d",   "movtst16",  3, 0xfc,  5,  5, CLR_V_CHG_NZ },
+  { "std",  "d->()",   "movtst16",  3, 0xfd,  5,  5, CLR_V_CHG_NZ },
+  { "ldx",  "()->x",   "movtst16",  3, 0xfe,  5,  5, CLR_V_CHG_NZ },
+  { "stx",  "x->()",   "movtst16",  3, 0xff,  5,  5, CLR_V_CHG_NZ }
+};
+
+
+/* Page 2 opcodes */
+/*
+ *  { "dex", "x->x", "dec16", 1, 0x00, 5, _M,  CHG_NONE },
+ * Name -+                                      +----- Insn CCR changes
+ * Operands  ---+                        +------------ Max # cycles
+ * Pattern   -----------+             +--------------- Min # cycles
+ * Size             -----------------+   +-------------------- Opcode
+ */
+const struct m6811_opcode_def m6811_page2_opcodes[] = {
+  { "iny",  "y->y",    "inc16",     2, 0x08, 4, 4, CHG_Z },
+  { "dey",  "y->y",    "dec16",     2, 0x09, 4, 4, CHG_Z },
+  { "bset", "(y),#->(y)","or8",             4, 0x1c, 8, 8, CLR_V_CHG_NZ },
+  { "bclr", "(y),#->(y)","bclr8",    4, 0x1d, 8, 8, CLR_V_CHG_NZ },
+  { "brset","(y),#,r",  "brset8",   5, 0x1e, 8, 8, CHG_NONE },
+  { "brclr","(y),#,r", "brclr8",    5, 0x1f, 8, 8, CHG_NONE },
+  { "tsy",  "sp->y",   "tsxy16",    2, 0x30, 4, 4, CHG_NONE },
+  { "tys",  "y->sp",   "txys16",    2, 0x35, 4, 4, CHG_NONE },
+  { "puly", "(sp)->y", "mov16",     2, 0x38, 6, 6, CHG_NONE },
+  { "aby",  "b,y->y",  "abxy16",    2, 0x3a, 4, 4, CHG_NONE },
+  { "pshy", "y->(sp)", "mov16",     2, 0x3c, 5, 5, CHG_NONE },
+  { "neg",  "(y)->(y)", "neg8",             3, 0x60, 7, 7, CHG_NZVC },
+  { "com",  "(y)->(y)", "com8",             3, 0x63, 7, 7, SET_C_CLR_V_CHG_NZ},
+  { "lsr",  "(y)->(y)", "lsr8",             3, 0x64, 7, 7, CLR_V_CHG_ZVC },
+  { "ror",  "(y)->(y)", "ror8",             3, 0x66, 7, 7, CHG_NZVC },
+  { "asr",  "(y)->(y)", "asr8",             3, 0x67, 7, 7, CHG_NZVC },
+  { "asl",  "(y)->(y)", "lsl8",             3, 0x68, 7, 7, CHG_NZVC },
+  { "lsl",  "(y)->(y)", "lsl8",             3, 0x68, 7, 7, CHG_NZVC },
+  { "rol",  "(y)->(y)", "rol8",             3, 0x69, 7, 7, CHG_NZVC },
+  { "dec",  "(y)->(y)", "dec8",             3, 0x6a, 7, 7, CHG_NZV },
+  { "inc",  "(y)->(y)", "inc8",             3, 0x6c, 7, 7, CHG_NZV },
+  { "tst",  "(y)",     "tst8",      3, 0x6d, 7, 7, CLR_V_CHG_NZ },
+  { "jmp",  "&(y)",    "bra",       3, 0x6e, 4, 4, CHG_NONE },
+  { "clr",  "->(y)",   "clr8",      3, 0x6f, 7, 7, SET_Z_CLR_NVC },
+  { "cmpy", "#,y",     "sub16",     4, 0x8c, 5, 5, CHG_NZVC },
+  { "cpy",  "#,y",     "sub16",     4, 0x8c, 5, 5, CHG_NZVC },
+  { "xgdy", "y->y",    "xgdxy16",   2, 0x8f, 4, 4, CHG_NONE },
+  { "cmpy", "*,y",     "sub16",     3, 0x9c, 6, 6, CHG_NZVC },
+  { "cpy",  "*,y",     "sub16",     3, 0x9c, 6, 6, CHG_NZVC },
+  { "suba", "(y),a->a", "sub8",             3, 0xa0, 5, 5, CHG_NZVC },
+  { "cmpa", "(y),a",   "sub8",      3, 0xa1, 5, 5, CHG_NZVC },
+  { "sbca", "(y),a->a", "sbc8",             3, 0xa2, 5, 5, CHG_NZVC },
+  { "subd", "(y),d->d", "sub16",     3, 0xa3, 7, 7, CHG_NZVC },
+  { "anda", "(y),a->a", "and8",             3, 0xa4, 5, 5, CLR_V_CHG_NZ },
+  { "bita", "(y),a",   "and8",      3, 0xa5, 5, 5, CLR_V_CHG_NZ },
+  { "ldaa", "(y)->a",  "movtst8",   3, 0xa6, 5, 5, CLR_V_CHG_NZ },
+  { "staa", "a->(y)",  "movtst8",   3, 0xa7, 5, 5, CLR_V_CHG_NZ },
+  { "eora", "(y),a->a", "eor8",             3, 0xa8, 5, 5, CLR_V_CHG_NZ },
+  { "adca", "(y),a->a", "adc8",             3, 0xa9, 5, 5, CHG_HNZVC },
+  { "oraa", "(y),a->a", "or8",      3, 0xaa, 5, 5, CLR_V_CHG_NZ },
+  { "adda", "(y),a->a", "add8",             3, 0xab, 5, 5, CHG_HNZVC },
+  { "cmpy", "(y),y",   "sub16",     3, 0xac, 7, 7, CHG_NZVC },
+  { "cpy",  "(y),y",   "sub16",     3, 0xac, 7, 7, CHG_NZVC },
+  { "jsr",  "&(y)",    "jsr16",     3, 0xad, 6, 6, CHG_NONE },
+  { "lds",  "(y)->sp", "movtst16",  3, 0xae, 6, 6, CLR_V_CHG_NZ },
+  { "sts",  "sp->(y)", "movtst16",  3, 0xaf, 6, 6, CLR_V_CHG_NZ },
+  { "cmpy", "(),y",    "sub16",     4, 0xbc, 7, 7, CHG_NZVC },
+  { "cpy",  "(),y",    "sub16",     4, 0xbc, 7, 7, CHG_NZVC },
+  { "ldy",  "#->y",    "movtst16",  4, 0xce, 4, 4, CLR_V_CHG_NZ },
+  { "ldy",  "*->y",    "movtst16",  3, 0xde, 5, 5, CLR_V_CHG_NZ },
+  { "sty",  "y->*",    "movtst16",  3, 0xdf, 5, 5, CLR_V_CHG_NZ },
+  { "subb", "(y),b->b", "sub8",             3, 0xe0, 5, 5, CHG_NZVC },
+  { "cmpb", "(y),b",   "sub8",      3, 0xe1, 5, 5, CHG_NZVC },
+  { "sbcb", "(y),b->b", "sbc8",             3, 0xe2, 5, 5, CHG_NZVC },
+  { "addd", "(y),d->d", "add16",     3, 0xe3, 7, 7, CHG_NZVC },
+  { "andb", "(y),b->b", "and8",             3, 0xe4, 5, 5, CLR_V_CHG_NZ },
+  { "bitb", "(y),b",   "and8",      3, 0xe5, 5, 5, CLR_V_CHG_NZ },
+  { "ldab", "(y)->b",  "movtst8",   3, 0xe6, 5, 5, CLR_V_CHG_NZ },
+  { "stab", "b->(y)",  "movtst8",   3, 0xe7, 5, 5, CLR_V_CHG_NZ },
+  { "eorb", "(y),b->b", "eor8",             3, 0xe8, 5, 5, CLR_V_CHG_NZ },
+  { "adcb", "(y),b->b", "adc8",             3, 0xe9, 5, 5, CHG_HNZVC },
+  { "orab", "(y),b->b", "or8",      3, 0xea, 5, 5, CLR_V_CHG_NZ },
+  { "addb", "(y),b->b", "add8",             3, 0xeb, 5, 5, CHG_HNZVC },
+  { "ldd",  "(y)->d",  "movtst16",  3, 0xec, 6, 6, CLR_V_CHG_NZ },
+  { "std",  "d->(y)",  "movtst16",  3, 0xed, 6, 6, CLR_V_CHG_NZ },
+  { "ldy",  "(y)->y",  "movtst16",  3, 0xee, 6, 6, CLR_V_CHG_NZ },
+  { "sty",  "y->(y)",  "movtst16",  3, 0xef, 6, 6, CLR_V_CHG_NZ },
+  { "ldy",  "()->y",   "movtst16",  4, 0xfe, 6, 6, CLR_V_CHG_NZ },
+  { "sty",  "y->()",   "movtst16",  4, 0xff, 6, 6, CLR_V_CHG_NZ }
+};
+
+/* Page 3 opcodes */
+/*
+ *  { "dex", "x->x", "dec16", 1, 0x00, 5, _M,  CHG_NONE },
+ * Name -+                                      +----- Insn CCR changes
+ * Operands  ---+                        +------------ Max # cycles
+ * Pattern   -----------+             +--------------- Min # cycles
+ * Size             -----------------+   +-------------------- Opcode
+ */
+const struct m6811_opcode_def m6811_page3_opcodes[] = {
+  { "cmpd", "#,d",     "sub16",     4, 0x83, 5, 5, CHG_NZVC },
+  { "cpd",  "#,d",     "sub16",     4, 0x83, 5, 5, CHG_NZVC },
+  { "cmpd", "*,d",     "sub16",     3, 0x93, 6, 6, CHG_NZVC },
+  { "cpd",  "*,d",     "sub16",     3, 0x93, 6, 6, CHG_NZVC },
+  { "cmpd", "(x),d",   "sub16",     3, 0xa3, 7, 7, CHG_NZVC },
+  { "cpd",  "(x),d",   "sub16",     3, 0xa3, 7, 7, CHG_NZVC },
+  { "cmpy", "(x),y",   "sub16",     3, 0xac, 7, 7, CHG_NZVC },
+  { "cpy",  "(x),y",   "sub16",     3, 0xac, 7, 7, CHG_NZVC },
+  { "cmpd", "(),d",    "sub16",     4, 0xb3, 7, 7, CHG_NZVC },
+  { "cpd",  "(),d",    "sub16",     4, 0xb3, 7, 7, CHG_NZVC },
+  { "ldy",  "(x)->y",  "movtst16",  3, 0xee, 6, 6, CLR_V_CHG_NZ },
+  { "sty",  "y->(x)",  "movtst16",  3, 0xef, 6, 6, CLR_V_CHG_NZ }
+};
+
+/* Page 4 opcodes */
+/*
+ *  { "dex", "x->x", "dec16", 1, 0x00, 5, _M,  CHG_NONE },
+ * Name -+                                      +----- Insn CCR changes
+ * Operands  ---+                        +------------ Max # cycles
+ * Pattern   -----------+             +--------------- Min # cycles
+ * Size             -----------------+   +-------------------- Opcode
+ */
+const struct m6811_opcode_def m6811_page4_opcodes[] = {
+  { "syscall", "",     "syscall",   2, 0x03, 6, 6, CHG_NONE },
+  { "cmpd", "(y),d",   "sub16",     3, 0xa3, 7, 7, CHG_NZVC },
+  { "cpd",  "(y),d",   "sub16",     3, 0xa3, 7, 7, CHG_NZVC },
+  { "cmpx", "(y),x",   "sub16",     3, 0xac, 7, 7, CHG_NZVC },
+  { "cpx",  "(y),x",   "sub16",     3, 0xac, 7, 7, CHG_NZVC },
+  { "ldx",  "(y)->x",  "movtst16",  3, 0xee, 6, 6, CLR_V_CHG_NZ },
+  { "stx",  "x->(y)",  "movtst16",  3, 0xef, 6, 6, CLR_V_CHG_NZ }
+};
+
+void fatal_error (const struct m6811_opcode_def*, const char*);
+void print (FILE*, int, const char*,...);
+int gen_fetch_operands (FILE*, int, const struct m6811_opcode_def*,
+                       const char*);
+void gen_save_result (FILE*, int, const struct m6811_opcode_def*,
+                     int, const char*);
+const struct m6811_opcode_pattern*
+find_opcode_pattern (const struct m6811_opcode_def*);
+void gen_interp (FILE*, int, const struct m6811_opcode_def*);
+void gen_interpreter_for_table (FILE*, int,
+                               const struct m6811_opcode_def*,
+                               int, const char*);
+void gen_interpreter (FILE*);
+
+
+static int indent_level = 2;
+static int current_insn_size = 0;
+
+/* Fatal error message and exit.  This method is called when an inconsistency
+   is detected in the generation table.         */
+void
+fatal_error (const struct m6811_opcode_def *opcode, const char *msg)
+{
+  fprintf (stderr, "Fatal error: %s\n", msg);
+  if (opcode)
+    {
+      fprintf (stderr, "Opcode: 0x%02x %s %s\n",
+              opcode->insn_code, opcode->name, opcode->operands);
+    }
+  exit (1);
+}
+
+
+/* Format and pretty print for the code generation.  (printf like format).  */
+void
+print (FILE *fp, int col, const char *msg, ...)
+{
+  va_list argp;
+  char buf[1024];
+  int cur_col = -1;
+  int i;
+
+  /* Format in a buffer.  */
+  va_start (argp, msg);
+  vsprintf (buf, msg, argp);
+  va_end (argp);
+
+  /* Basic pretty print:
+     - Every line is indented at column 'col',
+     - Indentation is updated when '{' and '}' are found,
+     - Indentation is incremented by the special character '@' (not displayed).
+     - New lines inserted automatically after ';'  */
+  for (i = 0; buf[i]; i++)
+    {
+      if (buf[i] == '{')
+       col += indent_level;
+      else if (buf[i] == '}')
+       col -= indent_level;
+      else if (buf[i] == '@')
+       {
+         col += indent_level;
+         continue;
+       }
+      if (cur_col == -1 && buf[i] != ' ' && buf[i] != '\t' && buf[i] != '\n')
+       {
+         cur_col = 0;
+         while (cur_col < col)
+           {
+             fputc (' ', fp);
+             cur_col++;
+           }
+       }
+      if (buf[i] == '}')
+       col -= indent_level;
+      else if (buf[i] == '{')
+       col += indent_level;
+      else if (buf[i] == '\n')
+       cur_col = -1;
+
+      if (cur_col != -1 || buf[i] == '\n')
+       fputc (buf[i], fp);
+
+      if (buf[i] == ';')
+       {
+         fputc ('\n', fp);
+         cur_col = -1;
+       }
+    }
+}
+
+
+/* Generate the code to obtain the operands before execution of the
+   instruction.         Operands are copied in local variables.  This allows to
+   have the same instruction pattern and different operand formats.
+   There is a maximum of 3 variables:
+                      8-bits          16-bits
+   1st operand:                src8            src16
+   2nd operand:                dst8            dst16
+   alt operand:                addr            addr
+  
+   The operand string is interpreted as follows:
+   a   Copy A register in the local 8-bits variable.
+   b   "    B "
+   ccr "    ccr "
+   d   "    D "        "      "    16-bits variable.
+   x   "    X "
+   y   "    Y "
+   sp  "    SP "
+   *   68HC11 page0 memory pointer.
+       Get 8-bits page0 offset from program, set up 'addr' local
+       variable to refer to the location in page0.
+       Copy the 8/16-bits value pointed to by 'addr' in a 8/16-bits variable.
+   (x) 68HC11 indirect access with X register.
+       Get 8-bits unsigned offset from program, set up 'addr' = X + offset.
+       Copy the 8/16-bits value pointed to by 'addr' in a 8/16-bits variable.
+   (y) Same as (x) with Y register.
+   ()  68HC11 extended address mode (global variable).
+       Get 16-bits address from program and set 'addr'.
+       Copy the 8/16-bits value pointed to by 'addr' in a 8/16-bits variable.
+   (sp) Pop
+       Pop a 8/16-bits value from stack and set in a 8/16-bits variable.
+   r   Relative branch
+       Get 8-bits relative branch, compute absolute address and set 'addr'
+   #   68HC11 immediate value
+       Get a 8/16-bits value from program and set a 8/16-bits variable.
+   &(x)
+   &(y)
+   &() Similar to (x), (y) and () except that we don't read the
+       value pointed to by 'addr' (ie, only 'addr' is setup). Used by jmp/jsr.
+   ,   Operand separator.
+   -   End of input operands.
+  
+   Example:
+       (x),a->a              addr = x + (uint16) (fetch8 (proc));
+                     src8 = a
+       *,#,r         addr = (uint16) (fetch8 (proc))  <- Temporary 'addr'
+                     src8 = read_mem8 (proc, addr)
+                     dst8 = fetch8 (proc)
+                     addr = fetch_relbranch (proc)    <- Final 'addr'
+  
+   Returns 1 if the 'addr' operand is set, 0 otherwise.         */
+int
+gen_fetch_operands (FILE *fp, int col,
+                   const struct m6811_opcode_def *opcode,
+                   const char *operand_size)
+{
+  static char *vars[2] = {
+    "src",
+    "dst"
+  };
+  char c;
+  int addr_set = 0;
+  int cur_var = 0;
+  const char *operands = opcode->operands;
+  
+  if (operands == 0)
+    operands = "";
+
+  while ((c = *operands++) != 0)
+    {
+      switch (c)
+       {
+       case 'a':
+         if (cur_var >= 2)
+           fatal_error (opcode, "Too many locals");
+         
+         print (fp, col, "%s8 = cpu_get_a (proc);", vars[cur_var]);
+         break;
+
+       case 'b':
+         if (cur_var >= 2)
+           fatal_error (opcode, "Too many locals");
+
+         print (fp, col, "%s8 = cpu_get_b (proc);", vars[cur_var]);
+         break;
+
+       case 'd':
+         if (cur_var >= 2)
+           fatal_error (opcode, "Too many locals");
+
+         print (fp, col, "%s16 = cpu_get_d (proc);", vars[cur_var]);
+         break;
+
+       case 'x':
+         if (cur_var >= 2)
+           fatal_error (opcode, "Too many locals");
+
+         print (fp, col, "%s16 = cpu_get_x (proc);", vars[cur_var]);
+         break;
+
+       case 'y':
+         if (cur_var >= 2)
+           fatal_error (opcode, "Too many locals");
+
+         print (fp, col, "%s16 = cpu_get_y (proc);", vars[cur_var]);
+         break;
+
+       case '*':
+         if (cur_var >= 2)
+           fatal_error (opcode, "Too many locals");
+
+         if (addr_set)
+           fatal_error (opcode, "Wrong use of '*', 'addr' already used");
+         
+         addr_set = 1;
+         current_insn_size += 1;
+         print (fp, col, "addr = (uint16) cpu_fetch8 (proc);");
+         print (fp, col, "%s%s = memory_read%s (proc, addr);",
+                vars[cur_var], operand_size, operand_size);
+         break;
+
+       case '&':
+         if (addr_set)
+           fatal_error (opcode, "Wrong use of '&', 'addr' already used");
+         
+         addr_set = 1;
+         if (strncmp (operands, "(x)", 3) == 0)
+           {
+             current_insn_size += 1;
+             print (fp, col, "addr = cpu_get_x (proc) + (uint16) cpu_fetch8 (proc);");
+             operands += 3;
+           }
+         else if (strncmp (operands, "(y)", 3) == 0)
+           {
+             current_insn_size += 1;
+             print (fp, col, "addr = cpu_get_y (proc) + (uint16) cpu_fetch8 (proc);");
+             operands += 3;
+           }
+         else if (strncmp (operands, "()", 2) == 0)
+           {
+             current_insn_size += 2;
+             print (fp, col, "addr = cpu_fetch16 (proc);");
+             operands += 2;
+           }
+         else
+           {
+             fatal_error (opcode, "Unknown operand");
+           }
+         break;
+         
+       case '(':
+         if (cur_var >= 2)
+           fatal_error (opcode, "Too many locals");
+         
+         if (addr_set)
+           fatal_error (opcode, "Wrong use of '(', 'addr' already used");
+         
+         if (strncmp (operands, "x)", 2) == 0)
+           {
+             addr_set = 1;
+             current_insn_size += 1;
+             print (fp, col, "addr = cpu_get_x (proc) + (uint16) cpu_fetch8 (proc);");
+             print (fp, col, "%s%s = memory_read%s (proc, addr);",
+                    vars[cur_var], operand_size, operand_size);
+             operands += 2;
+           }
+         else if (strncmp (operands, "y)", 2) == 0)
+           {
+             addr_set = 1;
+             current_insn_size += 1;
+             print (fp, col, "addr = cpu_get_y (proc) + (uint16) cpu_fetch8 (proc);");
+             print (fp, col, "%s%s = memory_read%s (proc, addr);",
+                    vars[cur_var], operand_size, operand_size);
+             operands += 2;
+           }
+         else if (strncmp (operands, ")", 1) == 0)
+           {
+             addr_set = 1;
+             current_insn_size += 2;
+             print (fp, col, "addr = cpu_fetch16 (proc);");
+             print (fp, col, "%s%s = memory_read%s (proc, addr);",
+                    vars[cur_var], operand_size, operand_size);
+             operands++;
+           }
+         else if (strncmp (operands, "sp)", 3) == 0)
+           {
+             print (fp, col, "%s%s = cpu_pop_uint%s (proc);",
+                    vars[cur_var], operand_size, operand_size);
+             operands += 3;
+           }
+         else
+           {
+             fatal_error (opcode, "Unknown operand");
+           }
+         break;
+
+       case 's':
+         if (cur_var >= 2)
+           fatal_error (opcode, "Too many locals");
+         
+         if (strncmp (operands, "p", 1) == 0)
+           {
+             print (fp, col, "%s16 = cpu_get_sp (proc);", vars[cur_var]);
+             operands++;
+           }
+         else
+           {
+             fatal_error (opcode, "Unknown operands");
+           }
+         break;
+
+       case 'c':
+         if (strncmp (operands, "cr", 2) == 0)
+           {
+             print (fp, col, "%s8 = cpu_get_ccr (proc);", vars[cur_var]);
+             operands += 2;
+           }
+         else
+           {
+             fatal_error (opcode, "Unknown operands");
+           }
+         break;
+         
+       case 'r':
+         if (addr_set && cur_var != 2)
+           fatal_error (opcode, "Wrong use of 'r'");
+
+         addr_set = 1;
+         current_insn_size += 1;
+         print (fp, col, "addr = cpu_fetch_relbranch (proc);");
+         break;
+
+       case '#':
+         if (strcmp (operand_size, "8") == 0)
+           {
+             current_insn_size += 1;
+           }
+         else
+           {
+             current_insn_size += 2;
+           }
+         print (fp, col, "%s%s = cpu_fetch%s (proc);", vars[cur_var],
+                operand_size, operand_size);
+         break;
+         
+       case ',':
+         cur_var ++;
+         break;
+
+       case '-':
+         return addr_set;
+
+       default:
+         fatal_error (opcode, "Invalid operands");
+         break;
+       }
+    }
+  return addr_set;
+}
+
+
+/* Generate the code to save the instruction result.  The result is in
+   a local variable: either 'dst8' or 'dst16'.
+   There may be only one result.  Instructions with 2 results (ie idiv
+   and fdiv), take care of saving the first value.
+  
+   The operand string is the same as for 'gen_fetch_operands'.
+   Everything before '->' is ignored.  If the '->' is not found, it
+   is assumed that there is nothing to save.  After '->', the operand
+   string is interpreted as follows:
+  
+   a   Save 'dst8' in A register
+   b   "              B "
+   ccr "              CCR "
+   d   "    'dst16'   D "
+   x   "              X "
+   y   "              Y "
+   sp  "              SP "
+   *   68HC11 page0 memory pointer.
+   (x) 68HC11 indirect access with X register.
+   (y) Same as (x) with Y register.
+   ()  68HC11 extended address mode (global variable).
+       For these modes, if they were used as an input operand,
+       the 'addr' variable contains the address of memory where
+       the result must be saved.
+       If they were not used an input operand, 'addr' is computed
+       (as in gen_fetch_operands()), and the result is saved.
+   (sp) Push
+       Push the 8/16-bits result on the stack.  */
+void
+gen_save_result (FILE *fp, int col,
+                const struct m6811_opcode_def *opcode,
+                int addr_set,
+                const char *operand_size)
+{
+  char c;
+  const char *operands = opcode->operands;
+
+  /* When the result is saved, 'result_size' is a string which
+     indicates the size of the saved result ("8" or "16").  This
+     is a sanity check with 'operand_size' to detect inconsistencies
+     in the different tables.  */
+  const char *result_size = 0;
+  
+  if (operands == 0)
+    operands = "";
+
+  operands = strchr (operands, '-');
+  if (operands == 0)
+    return;
+
+  operands++;
+  if (*operands++ != '>')
+    {
+      fatal_error (opcode, "Invalid operand");
+    }
+
+  c = *operands++;
+  switch (c)
+    {
+    case 'a':
+      result_size = "8";
+      print (fp, col, "cpu_set_a (proc, dst8);");
+      break;
+
+    case 'b':
+      result_size = "8";
+      print (fp, col, "cpu_set_b (proc, dst8);");
+      break;
+
+    case 'd':
+      result_size = "16";
+      print (fp, col, "cpu_set_d (proc, dst16);");
+      break;
+
+    case 'x':
+      result_size = "16";
+      print (fp, col, "cpu_set_x (proc, dst16);");
+      break;
+
+    case 'y':
+      result_size = "16";
+      print (fp, col, "cpu_set_y (proc, dst16);");
+      break;
+
+    case '*':
+      if (addr_set == 0)
+       {
+         current_insn_size += 1;
+         print (fp, col, "addr = (uint16) cpu_fetch8 (proc);");
+       }
+      result_size = operand_size;
+      print (fp, col, "memory_write%s (proc, addr, dst%s);",
+            operand_size, operand_size);
+      break;
+
+    case '(':
+      if (strncmp (operands, "x)", 2) == 0)
+       {
+         if (addr_set == 0)
+           {
+             current_insn_size += 1;
+             print (fp, col, "addr = cpu_get_x (proc) + cpu_fetch8 (proc);");
+           }
+         print (fp, col, "memory_write%s (proc, addr, dst%s);",
+                operand_size, operand_size);
+         operands += 2;
+         result_size = operand_size;
+       }
+      else if (strncmp (operands, "y)", 2) == 0)
+       {
+         if (addr_set == 0)
+           {
+             current_insn_size += 1;
+             print (fp, col, "addr = cpu_get_y (proc) + cpu_fetch8 (proc);");
+           }
+         print (fp, col, "memory_write%s (proc, addr, dst%s);",
+                operand_size, operand_size);
+         operands += 2;
+         result_size = operand_size;
+       }
+      else if (strncmp (operands, ")", 1) == 0)
+       {
+         if (addr_set == 0)
+           {
+             current_insn_size += 2;
+             print (fp, col, "addr = cpu_fetch16 (proc);");
+           }
+         print (fp, col, "memory_write%s (proc, addr, dst%s);",
+                operand_size, operand_size);
+         operands++;
+         result_size = operand_size;
+       }
+      else if (strncmp (operands, "sp)", 3) == 0)
+       {
+         print (fp, col, "cpu_push_uint%s (proc, dst%s);",
+                operand_size, operand_size);
+         operands += 3;
+         result_size = operand_size;
+       }
+      else
+       {
+         fatal_error (opcode, "Invalid operand");
+       }
+      break;
+
+    case 's':
+      if (strncmp (operands, "p", 1) == 0)
+       {
+         print (fp, col, "cpu_set_sp (proc, dst16);");
+         operands++;
+         result_size = "16";
+       }
+      else
+       {
+         fatal_error (opcode, "Invalid operand");
+       }
+      break;
+
+    case 'c':
+      if (strncmp (operands, "cr", 2) == 0)
+       {
+         print (fp, col, "cpu_set_ccr (proc, dst8);");
+         operands += 2;
+         result_size = "8";
+       }
+      else
+       {
+         fatal_error (opcode, "Invalid operand");
+       }
+      break;
+         
+    default:
+      fatal_error (opcode, "Invalid operand");
+      break;
+    }
+
+  if (*operands != 0)
+    fatal_error (opcode, "Garbage at end of operand");
+  
+  if (result_size == 0)
+    fatal_error (opcode, "? No result seems to be saved");
+
+  if (strcmp (result_size, operand_size) != 0)
+    fatal_error (opcode, "Result saved different than pattern size");
+}
+
+
+/* Find the instruction pattern for a given instruction.  */
+const struct m6811_opcode_pattern*
+find_opcode_pattern (const struct m6811_opcode_def *opcode)
+{
+  int i;
+  const char *pattern = opcode->insn_pattern;
+  
+  if (pattern == 0)
+    {
+      pattern = opcode->name;
+    }
+  for (i = 0; i < TABLE_SIZE(m6811_opcode_patterns); i++)
+    {
+      if (strcmp (m6811_opcode_patterns[i].name, pattern) == 0)
+       {
+         return &m6811_opcode_patterns[i];
+       }
+    }
+  fatal_error (opcode, "Unknown instruction pattern");
+  return 0;
+}
+
+
+/* Generate the code for interpretation of instruction 'opcode'.  */
+void
+gen_interp (FILE *fp, int col, const struct m6811_opcode_def *opcode)
+{
+  const char *operands = opcode->operands;
+  int addr_set;
+  const char *pattern = opcode->insn_pattern;
+  const struct m6811_opcode_pattern *op;
+  const char *operand_size;
+  
+  if (pattern == 0)
+    {
+      pattern = opcode->name;
+    }
+
+  /* Find out the size of the operands: 8 or 16-bits.  */
+  if (strcmp(&pattern[strlen(pattern) - 1], "8") == 0)
+    {
+      operand_size = "8";
+    }
+  else if (strcmp (&pattern[strlen(pattern) - 2], "16") == 0)
+    {
+      operand_size = "16";
+    }
+  else
+    {
+      operand_size = "";
+    }
+  
+  if (operands == 0)
+    operands = "";
+
+  /* Generate entry point for the instruction. */
+  print (fp, col, "case 0x%02x: /* %s %s */\n", opcode->insn_code,
+        opcode->name, operands);
+  col += indent_level;
+
+  /* Generate the code to get the instruction operands.         */
+  addr_set = gen_fetch_operands (fp, col, opcode, operand_size);
+
+  /* Generate instruction interpretation.  */
+  op = find_opcode_pattern (opcode);
+  if (op->pattern)
+    {
+      print (fp, col, "%s;", op->pattern);
+    }
+
+  /* Generate the code to save the result.  */
+  gen_save_result (fp, col, opcode, addr_set, operand_size);
+
+  /* For some instructions, generate the code to update the flags.  */
+  if (op && op->ccr_update)
+    {
+      print (fp, col, "%s;", op->ccr_update);
+    }
+  print (fp, col, "break;");
+}
+
+
+/* Generate the interpretor for a given 68HC11 page set.  */
+void
+gen_interpreter_for_table (FILE *fp, int col,
+                          const struct m6811_opcode_def *table,
+                          int size,
+                          const char *cycles_table_name)
+{
+  int i;
+  int init_size;
+
+  init_size = table == m6811_page1_opcodes ? 1 : 2;
+  
+  /* Get the opcode and dispatch directly.  */
+  print (fp, col, "op = cpu_fetch8 (proc);");
+  print (fp, col, "cpu_add_cycles (proc, %s[op]);", cycles_table_name);
+  
+  print (fp, col, "switch (op)\n");
+  col += indent_level;
+  print (fp, col, "{\n");
+  
+  for (i = 0; i < size; i++)
+    {
+      /* The table contains duplicate entries (ie, instruction aliases).  */
+      if (i > 0 && table[i].insn_code == table[i - 1].insn_code)
+       continue;
+
+      current_insn_size = init_size;
+      gen_interp (fp, col, &table[i]);
+      if (current_insn_size != table[i].insn_size)
+       {
+         fatal_error (&table[i], "Insn size inconsistency");
+       }
+    }
+
+  print (fp, col, "default:\n");
+  print (fp, col + indent_level, "cpu_special (proc, M6811_ILLEGAL);");
+  print (fp, col + indent_level, "break;");
+  print (fp, col, "}\n");
+}
+
+/* Generate the table of instruction cycle.  These tables are indexed
+   by the opcode number to allow a fast cycle time computation.         */
+void
+gen_cycle_table (FILE *fp, const char *name,
+                const struct m6811_opcode_def *table,
+                int size)
+{
+  int i;
+  char cycles[256];
+  int page1;
+
+  page1 = table == m6811_page1_opcodes;
+
+  /* Build the cycles table.  The table is indexed by the opcode.  */
+  memset (cycles, 0, sizeof (cycles));
+  while (--size >= 0)
+    {
+      if (table->insn_min_cycles > table->insn_max_cycles)
+       fatal_error (table, "Wrong insn cycles");
+
+      if (table->insn_max_cycles == _M)
+       cycles[table->insn_code] = table->insn_min_cycles;
+      else
+       cycles[table->insn_code] = table->insn_max_cycles;
+
+      table++;
+    }
+
+  /* Some check: for the page1 opcode, the cycle type of the page2/3/4
+     opcode must be 0. */
+  if (page1 && (cycles[M6811_OPCODE_PAGE2] != 0
+               || cycles[M6811_OPCODE_PAGE3] != 0
+               || cycles[M6811_OPCODE_PAGE4] != 0))
+      fatal_error (0, "Invalid cycle table");
+
+  /* Generates the cycles table.  */
+  print (fp, 0, "static const unsigned char %s[256] = {\n", name);
+  for (i = 0; i < 256; i++)
+    {
+      if ((i % 16) == 0)
+       {
+         print (fp, indent_level, "/* %3d */ ", i);
+       }
+      fprintf (fp, "%2d", cycles[i]);
+      if (i != 255)
+       fprintf (fp, ",");
+
+      if ((i % 16) != 15)
+       fprintf (fp, " ");
+      else
+       fprintf (fp, "\n");
+    }
+  print (fp, 0, "};\n\n");
+}
+
+void
+gen_function_entry (FILE *fp, const char *name)
+{
+  /* Generate interpretor entry point. */
+  print (fp, 0, "%s (proc)\n", name);
+  print (fp, indent_level, "struct _sim_cpu* proc;");
+  print (fp, indent_level, "{\n");
+
+  /* Interpretor local variables.  */
+  print (fp, indent_level, "unsigned char op;");
+  print (fp, indent_level, "uint16 addr, src16, dst16;");
+  print (fp, indent_level, "uint8 src8, dst8;\n");
+}
+
+void
+gen_function_close (FILE *fp)
+{
+  print (fp, 0, "}\n");
+}
+
+void
+gen_interpreter (FILE *fp)
+{
+  int col = 0;
+
+  /* Generate header of interpretor.  */
+  print (fp, col, "/* File generated automatically by gencode. */\n");
+  print (fp, col, "#include \"sim-main.h\"\n\n");
+
+  gen_cycle_table (fp, "cycles_page1", m6811_page1_opcodes,
+                  TABLE_SIZE (m6811_page1_opcodes));
+  gen_cycle_table (fp, "cycles_page2", m6811_page2_opcodes,
+                  TABLE_SIZE (m6811_page2_opcodes));
+  gen_cycle_table (fp, "cycles_page3", m6811_page3_opcodes,
+                  TABLE_SIZE (m6811_page3_opcodes));
+  gen_cycle_table (fp, "cycles_page4", m6811_page4_opcodes,
+                  TABLE_SIZE (m6811_page4_opcodes));
+
+  /* Generate the page 2, 3 and 4 handlers.  */
+  gen_function_entry (fp, "static void\ncpu_page2_interp");
+  gen_interpreter_for_table (fp, indent_level,
+                            m6811_page2_opcodes,
+                            TABLE_SIZE(m6811_page2_opcodes),
+                            "cycles_page2");
+  gen_function_close (fp);
+  
+  gen_function_entry (fp, "static void\ncpu_page3_interp");
+  gen_interpreter_for_table (fp, indent_level,
+                            m6811_page3_opcodes,
+                            TABLE_SIZE(m6811_page3_opcodes),
+                            "cycles_page3");
+  gen_function_close (fp);
+  
+  gen_function_entry (fp, "static void\ncpu_page4_interp");
+  gen_interpreter_for_table (fp, indent_level,
+                            m6811_page4_opcodes,
+                            TABLE_SIZE(m6811_page4_opcodes),
+                            "cycles_page4");
+  gen_function_close (fp);
+
+  /* Generate the interpretor entry point.  */
+  gen_function_entry (fp, "void\ncpu_interp");
+
+  gen_interpreter_for_table (fp, indent_level, m6811_page1_opcodes,
+                            TABLE_SIZE(m6811_page1_opcodes),
+                            "cycles_page1");
+  gen_function_close (fp);
+}
+
+int
+main (int argc, char *argv[])
+{
+  gen_interpreter (stdout);
+  if (fclose (stdout) != 0)
+    {
+      fprintf (stderr, "Error while generating the interpreter: %d\n",
+              errno);
+      return 1;
+    }
+  return 0;
+}
diff --git a/sim/m68hc11/interp.c b/sim/m68hc11/interp.c
new file mode 100644 (file)
index 0000000..c05f1b8
--- /dev/null
@@ -0,0 +1,517 @@
+/* interp.c -- Simulator for Motorola 68HC11
+   Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+   Written by Stephane Carrez (stcarrez@worldnet.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.
+
+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.  */
+
+#include "sim-main.h"
+#include "sim-assert.h"
+#include "sim-hw.h"
+#include "sim-options.h"
+#include "hw-tree.h"
+#include "hw-device.h"
+#include "hw-ports.h"
+
+#ifndef MONITOR_BASE
+# define MONITOR_BASE (0x0C000)
+# define MONITOR_SIZE (0x04000)
+#endif
+
+static void sim_get_info (SIM_DESC sd, char *cmd);
+
+
+char *interrupt_names[] = {
+  "reset",
+  "nmi",
+  "int",
+  NULL
+};
+
+#ifndef INLINE
+#if defined(__GNUC__) && defined(__OPTIMIZE__)
+#define INLINE __inline__
+#else
+#define INLINE
+#endif
+#endif
+
+struct sim_info_list
+{
+  const char *name;
+  const char *device;
+};
+
+struct sim_info_list dev_list[] = {
+  {"cpu", "/m68hc11"},
+  {"timer", "/m68hc11/m68hc11tim"},
+  {"sio", "/m68hc11/m68hc11sio"},
+  {"spi", "/m68hc11/m68hc11spi"},
+  {"eeprom", "/m68hc11/m68hc11eepr"},
+  {0, 0}
+};
+
+/* Give some information about the simulator.  */
+static void
+sim_get_info (SIM_DESC sd, char *cmd)
+{
+  sim_cpu *cpu;
+
+  if (cmd != 0 && (cmd[0] == ' ' || cmd[0] == '-'))
+    {
+      int i;
+      struct hw *hw_dev;
+      cmd++;
+
+      for (i = 0; dev_list[i].name; i++)
+       if (strcmp (cmd, dev_list[i].name) == 0)
+         break;
+
+      if (dev_list[i].name == 0)
+       {
+         sim_io_eprintf (sd, "Device '%s' not found.\n", cmd);
+         sim_io_eprintf (sd, "Valid devices: cpu timer sio eeprom\n");
+         return;
+       }
+      hw_dev = sim_hw_parse (sd, dev_list[i].device);
+      if (hw_dev == 0)
+       {
+         sim_io_eprintf (sd, "Device '%s' not found\n", dev_list[i].device);
+         return;
+       }
+      hw_ioctl (hw_dev, 23, 0);
+      return;
+    }
+
+  cpu = STATE_CPU (sd, 0);
+  cpu_info (sd, cpu);
+  interrupts_info (sd, &cpu->cpu_interrupts);
+}
+
+
+void
+sim_board_reset (SIM_DESC sd)
+{
+  struct hw *hw_cpu;
+  sim_cpu *cpu;
+
+  cpu = STATE_CPU (sd, 0);
+  /*  hw_cpu = sim_hw_parse (sd, "/"); */
+  hw_cpu = sim_hw_parse (sd, "/m68hc11");
+  if (hw_cpu == 0)
+    {
+      sim_io_eprintf (sd, "m68hc11 cpu not found in device tree.");
+      return;
+    }
+
+  cpu_reset (cpu);
+  hw_port_event (hw_cpu, 3, 0);
+  cpu_restart (cpu);
+}
+
+SIM_DESC
+sim_open (SIM_OPEN_KIND kind, host_callback *callback,
+          struct _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);
+
+  SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
+
+  /* for compatibility */
+  current_alignment = NONSTRICT_ALIGNMENT;
+  current_target_byte_order = BIG_ENDIAN;
+
+  cpu_initialize (sd, cpu);
+
+  cpu->cpu_use_elf_start = 1;
+  if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
+    return 0;
+
+  /* getopt will print the error message so we just have to exit if this fails.
+     FIXME: Hmmm...  in the case of gdb we need getopt to call
+     print_filtered.  */
+  if (sim_parse_args (sd, argv) != SIM_RC_OK)
+    {
+      /* Uninstall the modules to avoid memory leaks,
+         file descriptor leaks, etc.  */
+      sim_module_uninstall (sd);
+      return 0;
+    }
+
+  device_tree = sim_hw_parse (sd, "/");
+  if (hw_tree_find_property (device_tree, "/m68hc11/reg") == 0)
+    {
+      /* Allocate core managed memory */
+
+      /* the monitor  */
+      sim_do_commandf (sd, "memory region 0x%lx,0x%lx",
+                      /* MONITOR_BASE, MONITOR_SIZE */
+                      0x8000, 0x8000);
+      sim_do_command (sd, " memory region 0x000,0x8000");
+      sim_hw_parse (sd, "/m68hc11/reg 0x1000 0x03F");
+    }
+
+  if (hw_tree_find_property (device_tree, "/m68hc11/m68hc11sio/reg") == 0)
+    {
+      sim_hw_parse (sd, "/m68hc11/m68hc11sio/reg 0x2b 0x5");
+      sim_hw_parse (sd, "/m68hc11/m68hc11sio/backend stdio");
+      sim_hw_parse (sd, "/m68hc11 > cpu-reset reset /m68hc11/m68hc11sio");
+    }
+  if (hw_tree_find_property (device_tree, "/m68hc11/m68hc11tim/reg") == 0)
+    {
+      /* M68hc11 Timer configuration. */
+      sim_hw_parse (sd, "/m68hc11/m68hc11tim/reg 0x1b 0x5");
+      sim_hw_parse (sd, "/m68hc11 > cpu-reset reset /m68hc11/m68hc11tim");
+    }
+
+  /* Create the SPI device.  */
+  if (hw_tree_find_property (device_tree, "/m68hc11/m68hc11spi/reg") == 0)
+    {
+      sim_hw_parse (sd, "/m68hc11/m68hc11spi/reg 0x28 0x3");
+      sim_hw_parse (sd, "/m68hc11 > cpu-reset reset /m68hc11/m68hc11spi");
+    }
+  if (hw_tree_find_property (device_tree, "/m68hc11/pram/reg") == 0)
+    {
+      /* M68hc11 persistent ram configuration. */
+      sim_hw_parse (sd, "/m68hc11/nvram/reg 0x0 256");
+      sim_hw_parse (sd, "/m68hc11/nvram/file m68hc11.ram");
+      sim_hw_parse (sd, "/m68hc11/nvram/mode save-modified");
+      sim_hw_parse (sd, "/m68hc11/nvram/overlap? true");
+      /*sim_hw_parse (sd, "/m68hc11 > cpu-reset reset /m68hc11/pram"); */
+    }
+  if (hw_tree_find_property (device_tree, "/m68hc11/m68hc11eepr/reg") == 0)
+    {
+      sim_hw_parse (sd, "/m68hc11/m68hc11eepr/reg 0xb000 512");
+      /* Connect the CPU reset to all devices. */
+      sim_hw_parse (sd, "/m68hc11 > cpu-reset reset /m68hc11/m68hc11eepr");
+    }
+
+  /* Check for/establish the a reference program image.  */
+  if (sim_analyze_program (sd,
+                          (STATE_PROG_ARGV (sd) != NULL
+                           ? *STATE_PROG_ARGV (sd)
+                           : NULL), abfd) != SIM_RC_OK)
+    {
+      sim_module_uninstall (sd);
+      return 0;
+    }
+
+  /* Establish any remaining configuration options.  */
+  if (sim_config (sd) != SIM_RC_OK)
+    {
+      sim_module_uninstall (sd);
+      return 0;
+    }
+
+  if (sim_post_argv_init (sd) != SIM_RC_OK)
+    {
+      /* Uninstall the modules to avoid memory leaks,
+         file descriptor leaks, etc.  */
+      sim_module_uninstall (sd);
+      return 0;
+    }
+
+  if (abfd != NULL)
+    {
+      cpu->cpu_elf_start = bfd_get_start_address (abfd);
+    }
+
+  sim_board_reset (sd);
+
+  /* Fudge our descriptor.  */
+  return sd;
+}
+
+
+void
+sim_close (SIM_DESC sd, int quitting)
+{
+  /* shut down modules */
+  sim_module_uninstall (sd);
+
+  /* Ensure that any resources allocated through the callback
+     mechanism are released: */
+  sim_io_shutdown (sd);
+
+  /* FIXME - free SD */
+
+  return;
+}
+
+void
+sim_set_profile (int n)
+{
+}
+
+void
+sim_set_profile_size (int n)
+{
+}
+
+/* Generic implementation of sim_engine_run that works within the
+   sim_engine setjmp/longjmp framework. */
+
+void
+sim_engine_run (SIM_DESC sd,
+                int next_cpu_nr,       /* ignore */
+               int nr_cpus,    /* ignore */
+               int siggnal)    /* ignore */
+{
+  sim_cpu *cpu;
+
+  SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
+  cpu = STATE_CPU (sd, 0);
+  while (1)
+    {
+      cpu_single_step (cpu);
+
+      /* process any events */
+      if (sim_events_tickn (sd, cpu->cpu_current_cycle))
+       {
+         sim_events_process (sd);
+       }
+    }
+}
+
+int
+sim_trace (SIM_DESC sd)
+{
+  sim_resume (sd, 0, 0);
+  return 1;
+}
+
+void
+sim_info (SIM_DESC sd, int verbose)
+{
+  sim_io_eprintf (sd, "Simulator info:\n");
+  sim_io_eprintf (sd, "  CPU Motorola 68HC11\n");
+  sim_get_info (sd, 0);
+  sim_module_info (sd, verbose || STATE_VERBOSE_P (sd));
+}
+
+SIM_RC
+sim_create_inferior (SIM_DESC sd, struct _bfd *abfd,
+                     char **argv, char **env)
+{
+  sim_cpu *cpu;
+  int i;
+
+  cpu = STATE_CPU (sd, 0);
+
+  if (abfd != NULL)
+    {
+      cpu->cpu_elf_start = bfd_get_start_address (abfd);
+    }
+
+  /* reset all state information */
+  sim_board_reset (sd);
+
+  /* Get information about the number of pseudo registers.  */
+  for (i = FIRST_SOFT_REGNUM; i <= ZD32_REGNUM; i++)
+    {
+      switch (i)
+       {
+       case TMP_REGNUM:
+         cpu->cpu_page0_reg[i - FIRST_SOFT_REGNUM] = 0;
+         break;
+       case Z_REGNUM:
+       case ZS_REGNUM:
+         cpu->cpu_page0_reg[i - FIRST_SOFT_REGNUM] = 2;
+         break;
+       case XY_REGNUM:
+         cpu->cpu_page0_reg[i - FIRST_SOFT_REGNUM] = 4;
+         break;
+       case FP_REGNUM:
+         cpu->cpu_page0_reg[i - FIRST_SOFT_REGNUM] = 6;
+         break;
+       default:
+         cpu->cpu_page0_reg[i - FIRST_SOFT_REGNUM]
+           = ((i - FIRST_SOFT_REGNUM) * 2) - 2;
+         break;
+       }
+    }
+  cpu->cpu_nb_pseudo_regs = 8;
+
+  return SIM_RC_OK;
+}
+
+
+void
+sim_set_callbacks (host_callback *p)
+{
+  /*  m6811_callback = p; */
+}
+
+
+int
+sim_fetch_register (SIM_DESC sd, int rn, unsigned char *memory, int length)
+{
+  sim_cpu *cpu;
+  uint16 val;
+
+  cpu = STATE_CPU (sd, 0);
+  switch (rn)
+    {
+    case A_REGNUM:
+      val = cpu_get_a (cpu);
+      break;
+
+    case B_REGNUM:
+      val = cpu_get_b (cpu);
+      break;
+
+    case D_REGNUM:
+      val = cpu_get_d (cpu);
+      break;
+
+    case X_REGNUM:
+      val = cpu_get_x (cpu);
+      break;
+
+    case Y_REGNUM:
+      val = cpu_get_y (cpu);
+      break;
+
+    case SP_REGNUM:
+      val = cpu_get_sp (cpu);
+      break;
+
+    case PC_REGNUM:
+      val = cpu_get_pc (cpu);
+      break;
+
+    case PSW_REGNUM:
+      val = cpu_get_ccr (cpu);
+      break;
+
+
+      /* Read a pseudo register. Pseudo registers are located at
+         beginning of page 0.  Each of them is 2 bytes.  */
+    default:
+      if (rn < FIRST_SOFT_REGNUM || rn >= ZD32_REGNUM)
+       {
+         val = 0;
+       }
+      else
+       {
+         uint16 addr;
+
+         addr = cpu->cpu_page0_reg[rn - FIRST_SOFT_REGNUM];
+         val = memory_read16 (cpu, addr);
+       }
+      break;
+    }
+  memory[0] = val >> 8;
+  memory[1] = val & 0x0FF;
+  return 2;
+}
+
+int
+sim_store_register (SIM_DESC sd, int rn, unsigned char *memory, int length)
+{
+  uint16 val;
+  sim_cpu *cpu;
+
+  cpu = STATE_CPU (sd, 0);
+
+  val = *memory++;
+  if (length == 2)
+    val = (val << 8) | *memory;
+
+  switch (rn)
+    {
+    case D_REGNUM:
+      cpu_set_d (cpu, val);
+      break;
+
+    case A_REGNUM:
+      cpu_set_a (cpu, val);
+      break;
+
+    case B_REGNUM:
+      cpu_set_b (cpu, val);
+      break;
+
+    case X_REGNUM:
+      cpu_set_x (cpu, val);
+      break;
+
+    case Y_REGNUM:
+      cpu_set_y (cpu, val);
+      break;
+
+    case SP_REGNUM:
+      cpu_set_sp (cpu, val);
+      break;
+
+    case PC_REGNUM:
+      cpu_set_pc (cpu, val);
+      break;
+
+    case PSW_REGNUM:
+      cpu_set_ccr (cpu, val);
+      break;
+
+      /* Write a pseudo register.  Pseudo registers are located at
+         beginning of page 0.  Each of them is 2 bytes.  */
+    default:
+      if (rn >= FIRST_SOFT_REGNUM && rn <= ZD32_REGNUM)
+       {
+         uint16 addr;
+
+         addr = cpu->cpu_page0_reg[rn - FIRST_SOFT_REGNUM];
+         memory_write16 (cpu, addr, val);
+       }
+      break;
+    }
+
+  return 2;
+}
+
+void
+sim_size (int s)
+{
+  ;
+}
+
+void
+sim_do_command (SIM_DESC sd, char *cmd)
+{
+  char *mm_cmd = "memory-map";
+  char *int_cmd = "interrupt";
+
+  /* Commands available from GDB:   */
+  if (sim_args_command (sd, cmd) != SIM_RC_OK)
+    {
+      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");
+      else if (strncmp (cmd, int_cmd, strlen (int_cmd)) == 0)
+       sim_io_eprintf (sd, "`interrupt' command replaced by `sim watch'\n");
+      else
+       sim_io_eprintf (sd, "Unknown command `%s'\n", cmd);
+    }
+}
diff --git a/sim/m68hc11/interrupts.c b/sim/m68hc11/interrupts.c
new file mode 100644 (file)
index 0000000..f172276
--- /dev/null
@@ -0,0 +1,297 @@
+/* interrupts.c -- 68HC11 Interrupts Emulation
+   Copyright 1999, 2000 Free Software Foundation, Inc.
+   Written by Stephane Carrez (stcarrez@worldnet.fr)
+
+This file is part of GDB, GAS, and the GNU binutils.
+
+GDB, GAS, and the GNU binutils are free software; you can redistribute
+them and/or modify them under the terms of the GNU General Public
+License as published by the Free Software Foundation; either version
+1, or (at your option) any later version.
+
+GDB, GAS, and the GNU binutils are distributed in the hope that they
+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 file; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "sim-main.h"
+
+struct interrupt_def idefs[] = {
+  /* Serial interrupts.  */
+  { M6811_INT_SCI,      M6811_SCSR,   M6811_TDRE,  M6811_SCCR2,  M6811_TIE },
+  { M6811_INT_SCI,      M6811_SCSR,   M6811_TC,    M6811_SCCR2,  M6811_TCIE },
+  { M6811_INT_SCI,      M6811_SCSR,   M6811_RDRF,  M6811_SCCR2,  M6811_RIE },
+  { M6811_INT_SCI,      M6811_SCSR,   M6811_IDLE,  M6811_SCCR2,  M6811_ILIE },
+
+  /* SPI interrupts.  */
+  { M6811_INT_SPI,      M6811_SPSR,   M6811_SPIF,  M6811_SPCR,   M6811_SPIE },
+
+  /* Realtime interrupts.  */
+  { M6811_INT_TCTN,     M6811_TFLG2,  M6811_TOF,   M6811_TMSK2,  M6811_TOI },
+  { M6811_INT_RT,       M6811_TFLG2,  M6811_RTIF,  M6811_TMSK2,  M6811_RTII },
+
+  /* Output compare interrupts.  */
+  { M6811_INT_OUTCMP1,  M6811_TFLG1,  M6811_OC1F,  M6811_TMSK1,  M6811_OC1I },
+  { M6811_INT_OUTCMP2,  M6811_TFLG1,  M6811_OC2F,  M6811_TMSK1,  M6811_OC2I },
+  { M6811_INT_OUTCMP3,  M6811_TFLG1,  M6811_OC3F,  M6811_TMSK1,  M6811_OC3I },
+  { M6811_INT_OUTCMP4,  M6811_TFLG1,  M6811_OC4F,  M6811_TMSK1,  M6811_OC4I },
+  { M6811_INT_OUTCMP5,  M6811_TFLG1,  M6811_OC5F,  M6811_TMSK1,  M6811_OC5I },
+
+  /* Input compare interrupts.  */
+  { M6811_INT_INCMP1,   M6811_TFLG1,  M6811_IC1F,  M6811_TMSK1,  M6811_IC1I },
+  { M6811_INT_INCMP2,   M6811_TFLG1,  M6811_IC2F,  M6811_TMSK1,  M6811_IC2I },
+  { M6811_INT_INCMP3,   M6811_TFLG1,  M6811_IC3F,  M6811_TMSK1,  M6811_IC3I },
+#if 0
+  { M6811_INT_COPRESET, M6811_CONFIG, M6811_NOCOP, 0,            0 },
+  { M6811_INT_COPFAIL,  M6811_CONFIG, M6811_NOCOP, 0,            0 }
+#endif
+};
+
+#define TableSize(X) (sizeof X / sizeof(X[0]))
+#define CYCLES_MAX ((((signed64) 1) << 62) - 1)
+
+/* Initialize the interrupts of the processor.  */
+int
+interrupts_initialize (struct _sim_cpu *proc)
+{
+  struct interrupts *interrupts = &proc->cpu_interrupts;
+  int i;
+  
+  interrupts->cpu          = proc;
+  interrupts->pending_mask = 0;
+  interrupts->vectors_addr = 0xffc0;
+  interrupts->nb_interrupts_raised = 0;
+  interrupts->min_mask_cycles = CYCLES_MAX;
+  interrupts->max_mask_cycles = 0;
+  interrupts->start_mask_cycle = -1;
+  interrupts->xirq_start_mask_cycle = -1;
+  interrupts->xirq_max_mask_cycles = 0;
+  interrupts->xirq_min_mask_cycles = CYCLES_MAX;
+  
+  for (i = 0; i < M6811_INT_NUMBER; i++)
+    {
+      interrupts->interrupt_order[i] = i;
+    }
+  return 0;
+}
+
+
+/* Update the mask of pending interrupts.  This operation must be called
+   when the state of some 68HC11 IO registers changes.  It looks the
+   different registers that indicate a pending interrupt (timer, SCI, SPI,
+   ...) and records the interrupt if it's there and enabled.  */
+void
+interrupts_update_pending (struct interrupts *interrupts)
+{
+  int i;
+  uint8 *ioregs;
+
+  ioregs = &interrupts->cpu->ios[0];
+  
+  for (i = 0; i < TableSize(idefs); i++)
+    {
+      struct interrupt_def *idef = &idefs[i];
+      uint8 data;
+      
+      /* Look if the interrupt is enabled.  */
+      if (idef->enable_paddr)
+       {
+         data = ioregs[idef->enable_paddr];
+         if (!(data & idef->enabled_mask))
+           continue;
+       }
+
+      /* Interrupt is enabled, see if it's there.  */
+      data = ioregs[idef->int_paddr];
+      if (!(data & idef->int_mask))
+       continue;
+
+      /* Ok, raise it.  */
+      interrupts->pending_mask |= (1 << idef->int_number);
+    }
+}
+
+
+/* Finds the current active and non-masked interrupt.
+   Returns the interrupt number (index in the vector table) or -1
+   if no interrupt can be serviced.  */
+int
+interrupts_get_current (struct interrupts *interrupts)
+{
+  int i;
+  
+  if (interrupts->pending_mask == 0)
+    return -1;
+
+  /* SWI and illegal instructions are simulated by an interrupt.
+     They are not maskable.  */
+  if (interrupts->pending_mask & (1 << M6811_INT_SWI))
+    {
+      interrupts->pending_mask &= ~(1 << M6811_INT_SWI);
+      return M6811_INT_SWI;
+    }
+  if (interrupts->pending_mask & (1 << M6811_INT_ILLEGAL))
+    {
+      interrupts->pending_mask &= ~(1 << M6811_INT_ILLEGAL);
+      return M6811_INT_ILLEGAL;
+    }
+  
+  /* If there is a non maskable interrupt, go for it (unless we are masked
+     by the X-bit.  */
+  if (interrupts->pending_mask & (1 << M6811_INT_XIRQ))
+    {
+      if (cpu_get_ccr_X (interrupts->cpu) == 0)
+       {
+         interrupts->pending_mask &= ~(1 << M6811_INT_XIRQ);
+         return M6811_INT_XIRQ;
+       }
+      return -1;
+    }
+
+  /* Interrupts are masked, do nothing.  */
+  if (cpu_get_ccr_I (interrupts->cpu) == 1)
+    {
+      return -1;
+    }
+
+  /* Returns the first interrupt number which is pending.
+     The interrupt priority is specified by the table `interrupt_order'.  */
+  for (i = 0; i < M6811_INT_NUMBER; i++)
+    {
+      enum M6811_INT int_number = interrupts->interrupt_order[i];
+
+      if (interrupts->pending_mask & (1 << int_number))
+       {
+         interrupts->pending_mask &= ~(1 << int_number);
+         return int_number;
+       }
+    }
+  return -1;
+}
+
+
+/* Process the current interrupt if there is one.  This operation must
+   be called after each instruction to handle the interrupts.  If interrupts
+   are masked, it does nothing.  */
+int
+interrupts_process (struct interrupts *interrupts)
+{
+  int id;
+  uint8 ccr;
+
+  /* See if interrupts are enabled/disabled and keep track of the
+     number of cycles the interrupts are masked.  Such information is
+     then reported by the info command.  */
+  ccr = cpu_get_ccr (interrupts->cpu);
+  if (ccr & M6811_I_BIT)
+    {
+      if (interrupts->start_mask_cycle < 0)
+        interrupts->start_mask_cycle = cpu_current_cycle (interrupts->cpu);
+    }
+  else if (interrupts->start_mask_cycle >= 0
+           && (ccr & M6811_I_BIT) == 0)
+    {
+      signed64 t = cpu_current_cycle (interrupts->cpu);
+
+      t -= interrupts->start_mask_cycle;
+      if (t < interrupts->min_mask_cycles)
+        interrupts->min_mask_cycles = t;
+      if (t > interrupts->max_mask_cycles)
+        interrupts->max_mask_cycles = t;
+      interrupts->start_mask_cycle = -1;
+    }
+  if (ccr & M6811_X_BIT)
+    {
+      if (interrupts->xirq_start_mask_cycle < 0)
+        interrupts->xirq_start_mask_cycle
+         = cpu_current_cycle (interrupts->cpu);
+    }
+  else if (interrupts->xirq_start_mask_cycle >= 0
+           && (ccr & M6811_X_BIT) == 0)
+    {
+      signed64 t = cpu_current_cycle (interrupts->cpu);
+
+      t -= interrupts->xirq_start_mask_cycle;
+      if (t < interrupts->xirq_min_mask_cycles)
+        interrupts->xirq_min_mask_cycles = t;
+      if (t > interrupts->xirq_max_mask_cycles)
+        interrupts->xirq_max_mask_cycles = t;
+      interrupts->xirq_start_mask_cycle = -1;
+    }
+
+  id = interrupts_get_current (interrupts);
+  if (id >= 0)
+    {
+      uint16 addr;
+      
+      cpu_push_all (interrupts->cpu);
+      addr = memory_read16 (interrupts->cpu,
+                            interrupts->vectors_addr + id * 2);
+      cpu_call (interrupts->cpu, addr);
+
+      /* Now, protect from nested interrupts.  */
+      if (id == M6811_INT_XIRQ)
+       {
+         cpu_set_ccr_X (interrupts->cpu, 1);
+       }
+      else
+       {
+         cpu_set_ccr_I (interrupts->cpu, 1);
+       }
+
+      interrupts->nb_interrupts_raised++;
+      cpu_add_cycles (interrupts->cpu, 14);
+      return 1;
+    }
+  return 0;
+}
+
+void
+interrupts_raise (struct interrupts *interrupts, enum M6811_INT number)
+{
+  interrupts->pending_mask |= (1 << number);
+  interrupts->nb_interrupts_raised ++;
+}
+
+
+
+void
+interrupts_info (SIM_DESC sd, struct interrupts *interrupts)
+{
+  if (interrupts->start_mask_cycle >= 0)
+    {
+      signed64 t = cpu_current_cycle (interrupts->cpu);
+
+      t -= interrupts->start_mask_cycle;
+      if (t > interrupts->max_mask_cycles)
+        interrupts->max_mask_cycles = t;
+    }
+  if (interrupts->xirq_start_mask_cycle >= 0)
+    {
+      signed64 t = cpu_current_cycle (interrupts->cpu);
+
+      t -= interrupts->xirq_start_mask_cycle;
+      if (t > interrupts->xirq_max_mask_cycles)
+        interrupts->xirq_max_mask_cycles = t;
+    }
+
+  sim_io_printf (sd, "Interrupts Info:\n");
+  sim_io_printf (sd, "  Interrupts raised: %lu\n",
+                 interrupts->nb_interrupts_raised);
+  sim_io_printf (sd, "  Min interrupts masked sequence: %llu cycles\n",
+                 interrupts->min_mask_cycles == CYCLES_MAX ?
+                 interrupts->max_mask_cycles :
+                 interrupts->min_mask_cycles);
+  sim_io_printf (sd, "  Max interrupts masked sequence: %llu cycles\n",
+                 interrupts->max_mask_cycles);
+  sim_io_printf (sd, "  XIRQ Min interrupts masked sequence: %llu cycles\n",
+                 interrupts->xirq_min_mask_cycles == CYCLES_MAX ?
+                 interrupts->xirq_max_mask_cycles :
+                 interrupts->xirq_min_mask_cycles);
+  sim_io_printf (sd, "  XIRQ Max interrupts masked sequence: %llu cycles\n",
+                 interrupts->xirq_max_mask_cycles);
+}
diff --git a/sim/m68hc11/interrupts.h b/sim/m68hc11/interrupts.h
new file mode 100644 (file)
index 0000000..39069cd
--- /dev/null
@@ -0,0 +1,132 @@
+/* interrupts.h -- 68HC11 Interrupts Emulation
+   Copyright 1999, 2000 Free Software Foundation, Inc.
+   Written by Stephane Carrez (stcarrez@worldnet.fr)
+
+This file is part of GDB, GAS, and the GNU binutils.
+
+GDB, GAS, and the GNU binutils are free software; you can redistribute
+them and/or modify them under the terms of the GNU General Public
+License as published by the Free Software Foundation; either version
+1, or (at your option) any later version.
+
+GDB, GAS, and the GNU binutils are distributed in the hope that they
+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 file; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifndef _M6811_SIM_INTERRUPTS_H
+#define _M6811_SIM_INTERRUPTS_H
+
+/* Definition of 68HC11 interrupts.  These enum are used as an index
+   in the interrupt table.  */
+enum M6811_INT
+{
+  M6811_INT_RESERVED1 = 0,
+  M6811_INT_RESERVED2,
+  M6811_INT_RESERVED3,
+  M6811_INT_RESERVED4,
+  M6811_INT_RESERVED5,
+  M6811_INT_RESERVED6,
+  M6811_INT_RESERVED7,
+  M6811_INT_RESERVED8,
+
+  M6811_INT_RESERVED9,
+  M6811_INT_RESERVED10,
+  M6811_INT_RESERVED11,
+
+  M6811_INT_SCI,
+  M6811_INT_SPI,
+  M6811_INT_AINPUT,
+  M6811_INT_AOVERFLOW,
+  M6811_INT_TCTN,
+
+  M6811_INT_OUTCMP5,
+  M6811_INT_OUTCMP4,
+  M6811_INT_OUTCMP3,
+  M6811_INT_OUTCMP2,
+  M6811_INT_OUTCMP1,
+
+  M6811_INT_INCMP3,
+  M6811_INT_INCMP2,
+  M6811_INT_INCMP1,
+
+  M6811_INT_RT,
+  M6811_INT_IRQ,
+  M6811_INT_XIRQ,
+  M6811_INT_SWI,
+  M6811_INT_ILLEGAL,
+
+  M6811_INT_COPRESET,
+  M6811_INT_COPFAIL,
+
+  M6811_INT_RESET,
+  M6811_INT_NUMBER
+};
+
+
+/* Structure to describe how to recognize an interrupt in the
+   68hc11 IO regs.  */
+struct interrupt_def
+{
+  enum M6811_INT   int_number;
+  unsigned char    int_paddr;
+  unsigned char    int_mask;
+  unsigned char    enable_paddr;
+  unsigned char    enabled_mask;
+};
+
+/* Management of 68HC11 interrupts:
+    - We use a table of 'interrupt_def' to describe the interrupts that must be
+      raised depending on IO register flags (enable and present flags).
+    - We keep a mask of pending interrupts.  This mask is refreshed by
+      calling 'interrupts_update_pending'.  It must be refreshed each time
+      an IO register is changed.
+    - 'interrupts_process' must be called after each insn. It has two purposes:
+      first it maintains a min/max count of CPU cycles between which interrupts
+      are masked; second it checks for pending interrupts and raise one if
+      interrupts are enabled.  */
+struct interrupts {
+  struct _sim_cpu   *cpu;
+
+  /* Mask of current pending interrupts.  */
+  unsigned long     pending_mask;
+
+  /* Address of vector table.  This is set depending on the
+     68hc11 init mode.  */
+  uint16            vectors_addr;
+
+  /* Priority order of interrupts.  This is controlled by setting the HPRIO
+     IO register.  */
+  enum M6811_INT    interrupt_order[M6811_INT_NUMBER];
+
+  /* Simulator statistics to report useful debug information to users.  */
+
+  /* - Max/Min number of CPU cycles executed with interrupts masked.  */
+  signed64          start_mask_cycle;
+  signed64          min_mask_cycles;
+  signed64          max_mask_cycles;
+
+  /* - Same for XIRQ.  */
+  signed64          xirq_start_mask_cycle;
+  signed64          xirq_min_mask_cycles;
+  signed64          xirq_max_mask_cycles;
+
+  /* - Total number of interrupts raised.  */
+  unsigned long     nb_interrupts_raised;
+};
+
+extern int  interrupts_initialize     (struct _sim_cpu* cpu);
+extern void interrupts_update_pending (struct interrupts* interrupts);
+extern int  interrupts_get_current    (struct interrupts* interrupts);
+extern int  interrupts_process        (struct interrupts* interrupts);
+extern void interrupts_raise          (struct interrupts* interrupts,
+                                       enum M6811_INT number);
+
+extern void interrupts_info           (SIM_DESC sd,
+                                       struct interrupts* interrupts);
+
+#endif
diff --git a/sim/m68hc11/m68hc11_sim.c b/sim/m68hc11/m68hc11_sim.c
new file mode 100644 (file)
index 0000000..fbdf386
--- /dev/null
@@ -0,0 +1,639 @@
+/* m6811_cpu.c -- 68HC11 CPU Emulation
+   Copyright 1999, 2000 Free Software Foundation, Inc.
+   Written by Stephane Carrez (stcarrez@worldnet.fr)
+
+This file is part of GDB, GAS, and the GNU binutils.
+
+GDB, GAS, and the GNU binutils are free software; you can redistribute
+them and/or modify them under the terms of the GNU General Public
+License as published by the Free Software Foundation; either version
+1, or (at your option) any later version.
+
+GDB, GAS, and the GNU binutils are distributed in the hope that they
+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 file; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "sim-main.h"
+#include "sim-assert.h"
+#include "sim-module.h"
+#include "sim-options.h"
+
+void cpu_free_frame (sim_cpu* cpu, struct cpu_frame *frame);
+
+enum {
+  OPTION_CPU_RESET = OPTION_START,
+  OPTION_EMUL_OS,
+  OPTION_CPU_CONFIG,
+  OPTION_CPU_MODE
+};
+
+static DECLARE_OPTION_HANDLER (cpu_option_handler);
+
+static const OPTION cpu_options[] =
+{
+  { {"cpu-reset", no_argument, NULL, OPTION_CPU_RESET },
+      '\0', NULL, "Reset the CPU",
+      cpu_option_handler },
+
+  { {"emulos",    no_argument, NULL, OPTION_EMUL_OS },
+      '\0', NULL, "Emulate some OS system calls (read, write, ...)",
+      cpu_option_handler },
+
+  { {"cpu-config", required_argument, NULL, OPTION_CPU_CONFIG },
+      '\0', NULL, "Specify the initial CPU configuration register",
+      cpu_option_handler },
+
+  { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
+};
+
+
+static SIM_RC
+cpu_option_handler (SIM_DESC sd, sim_cpu *cpu,
+                    int opt, char *arg, int is_command)
+{
+  sim_cpu *cpu;
+  int val;
+  
+  cpu = STATE_CPU (sd, 0);
+  switch (opt)
+    {
+    case OPTION_CPU_RESET:
+      sim_board_reset (sd);
+      break;
+
+    case OPTION_EMUL_OS:
+      cpu->cpu_emul_syscall = 1;
+      break;
+
+    case OPTION_CPU_CONFIG:
+      if (sscanf(arg, "0x%x", &val) == 1
+          || sscanf(arg, "%d", &val) == 1)
+        {
+          cpu->cpu_config = val;
+          cpu->cpu_use_local_config = 1;
+        }
+      else
+        cpu->cpu_use_local_config = 0;
+      break;
+      
+    case OPTION_CPU_MODE:
+      break;
+    }
+
+  return SIM_RC_OK;
+}
+
+/* Tentative to keep track of the cpu frame.  */
+struct cpu_frame*
+cpu_find_frame (sim_cpu *cpu, uint16 sp)
+{
+  struct cpu_frame_list *flist;
+
+  flist = cpu->cpu_frames;
+  while (flist)
+    {
+      struct cpu_frame *frame;
+
+      frame = flist->frame;
+      while (frame)
+       {
+         if (frame->sp_low <= sp && frame->sp_high >= sp)
+           {
+             cpu->cpu_current_frame = flist;
+             return frame;
+           }
+
+         frame = frame->up;
+       }
+      flist = flist->next;
+    }
+  return 0;
+}
+
+struct cpu_frame_list*
+cpu_create_frame_list (sim_cpu *cpu)
+{
+  struct cpu_frame_list *flist;
+
+  flist = (struct cpu_frame_list*) malloc (sizeof (struct cpu_frame_list));
+  flist->frame = 0;
+  flist->next  = cpu->cpu_frames;
+  flist->prev  = 0;
+  if (flist->next)
+    flist->next->prev = flist;
+  cpu->cpu_frames = flist;
+  cpu->cpu_current_frame = flist;
+  return flist;
+}
+
+void
+cpu_remove_frame_list (sim_cpu *cpu, struct cpu_frame_list *flist)
+{
+  struct cpu_frame *frame;
+  
+  if (flist->prev == 0)
+    cpu->cpu_frames = flist->next;
+  else
+    flist->prev->next = flist->next;
+  if (flist->next)
+    flist->next->prev = flist->prev;
+
+  frame = flist->frame;
+  while (frame)
+    {
+      struct cpu_frame* up = frame->up;
+      cpu_free_frame (cpu, frame);
+      frame = up;
+    }
+  free (flist);
+}
+  
+    
+struct cpu_frame*
+cpu_create_frame (sim_cpu *cpu, uint16 pc, uint16 sp)
+{
+  struct cpu_frame *frame;
+
+  frame = (struct cpu_frame*) malloc (sizeof(struct cpu_frame));
+  frame->up = 0;
+  frame->pc = pc;
+  frame->sp_low  = sp;
+  frame->sp_high = sp;
+  return frame;
+}
+
+void
+cpu_free_frame (sim_cpu *cpu, struct cpu_frame *frame)
+{
+  free (frame);
+}
+
+uint16
+cpu_frame_reg (sim_cpu *cpu, uint16 rn)
+{
+  struct cpu_frame *frame;
+
+  if (cpu->cpu_current_frame == 0)
+    return 0;
+  
+  frame = cpu->cpu_current_frame->frame;
+  while (frame)
+    {
+      if (rn == 0)
+       return frame->sp_high;
+      frame = frame->up;
+      rn--;
+    }
+  return 0;
+}
+  
+void
+cpu_call (sim_cpu *cpu, uint16 addr)
+{
+#if HAVE_FRAME
+  uint16 pc = cpu->cpu_insn_pc;
+  uint16 sp;
+  struct cpu_frame_list *flist;
+  struct cpu_frame* frame;
+  struct cpu_frame* new_frame;
+#endif
+
+  cpu_set_pc (cpu, addr);
+#if HAVE_FRAME
+  sp = cpu_get_sp (cpu);
+
+  cpu->cpu_need_update_frame = 0;
+  flist = cpu->cpu_current_frame;
+  if (flist == 0)
+    flist = cpu_create_frame_list (cpu);
+
+  frame = flist->frame;
+  if (frame && frame->sp_low > sp)
+    frame->sp_low = sp;
+
+  new_frame = cpu_create_frame (cpu, pc, sp);
+  new_frame->up = frame;
+  flist->frame = new_frame;
+#endif
+}
+
+void
+cpu_update_frame (sim_cpu *cpu, int do_create)
+{
+#if HAVE_FRAME
+  struct cpu_frame *frame;
+
+  frame = cpu_find_frame (cpu, cpu_get_sp (cpu));
+  if (frame)
+    {
+      while (frame != cpu->cpu_current_frame->frame)
+       {
+         struct cpu_frame* up;
+         
+         up = cpu->cpu_current_frame->frame->up;
+         cpu_free_frame (cpu, cpu->cpu_current_frame->frame);
+         cpu->cpu_current_frame->frame = up;
+       }
+      return;
+    }
+
+  if (do_create)
+    {
+      cpu_create_frame_list (cpu);
+      frame = cpu_create_frame (cpu, cpu_get_pc (cpu), cpu_get_sp (cpu));
+      cpu->cpu_current_frame->frame = frame;
+    }
+#endif
+}
+
+void
+cpu_return (sim_cpu *cpu)
+{
+#if HAVE_FRAME
+  uint16 sp = cpu_get_sp (cpu);
+  struct cpu_frame *frame;
+  struct cpu_frame_list *flist;
+
+  cpu->cpu_need_update_frame = 0;
+  flist = cpu->cpu_current_frame;
+  if (flist && flist->frame && flist->frame->up)
+    {
+      frame = flist->frame->up;
+      if (frame->sp_low <= sp && frame->sp_high >= sp)
+       {
+         cpu_free_frame (cpu, flist->frame);
+         flist->frame = frame;
+         return;
+       }
+    }
+  cpu_update_frame (cpu, 1);
+#endif
+}
+
+void
+cpu_print_frame (SIM_DESC sd, sim_cpu *cpu)
+{
+  struct cpu_frame* frame;
+  int level = 0;
+  
+  if (cpu->cpu_current_frame == 0 || cpu->cpu_current_frame->frame == 0)
+    {
+      sim_io_printf (sd, "No frame.\n");
+      return;
+    }
+  sim_io_printf (sd, " #   PC   SP-L  SP-H\n");
+  frame = cpu->cpu_current_frame->frame;
+  while (frame)
+    {
+      sim_io_printf (sd, "%3d 0x%04x 0x%04x 0x%04x\n",
+                    level, frame->pc, frame->sp_low, frame->sp_high);
+      frame = frame->up;
+      level++;
+    }
+}
+
+/* Set the stack pointer and re-compute the current frame.  */
+void
+cpu_set_sp (sim_cpu *cpu, uint16 val)
+{
+  cpu->cpu_regs.sp = val;
+  cpu_update_frame (cpu, 0);
+}
+
+int
+cpu_initialize (SIM_DESC sd, sim_cpu *cpu)
+{
+  int result;
+  
+  sim_add_option_table (sd, 0, cpu_options);
+
+  memset (&cpu->cpu_regs, 0, sizeof(cpu->cpu_regs));
+
+  cpu->cpu_absolute_cycle = 0;
+  cpu->cpu_current_cycle  = 0;
+  cpu->cpu_emul_syscall   = 1;
+  cpu->cpu_running        = 1;
+  cpu->cpu_stop_on_interrupt = 0;
+  cpu->cpu_frequency = 8 * 1000 * 1000;
+  cpu->cpu_frames = 0;
+  cpu->cpu_current_frame = 0;
+  cpu->cpu_use_elf_start = 0;
+  cpu->cpu_elf_start     = 0;
+  cpu->cpu_use_local_config = 0;
+  cpu->cpu_config        = M6811_NOSEC | M6811_NOCOP | M6811_ROMON |
+    M6811_EEON;
+  result = interrupts_initialize (cpu);
+
+  cpu->cpu_is_initialized = 1;
+  return result;
+}
+
+
+/* Reinitialize the processor after a reset.  */
+int
+cpu_reset (sim_cpu *cpu)
+{
+  cpu->cpu_need_update_frame = 0;
+  cpu->cpu_current_frame = 0;
+  while (cpu->cpu_frames)
+    cpu_remove_frame_list (cpu, cpu->cpu_frames);
+
+  /* Initialize the config register.
+     It is only initialized at reset time.  */
+  memset (cpu->ios, 0, sizeof (cpu->ios));
+  cpu->ios[M6811_INIT] = 0x1;
+
+  /* Output compare registers set to 0xFFFF.  */
+  cpu->ios[M6811_TOC1_H] = 0xFF;
+  cpu->ios[M6811_TOC1_L] = 0xFF;
+  cpu->ios[M6811_TOC2_H] = 0xFF;
+  cpu->ios[M6811_TOC2_L] = 0xFF;
+  cpu->ios[M6811_TOC3_H] = 0xFF;
+  cpu->ios[M6811_TOC4_L] = 0xFF;
+  cpu->ios[M6811_TOC5_H] = 0xFF;
+  cpu->ios[M6811_TOC5_L] = 0xFF;
+
+  /* Setup the processor registers.  */
+  memset (&cpu->cpu_regs, 0, sizeof(cpu->cpu_regs));
+  cpu->cpu_absolute_cycle = 0;
+  cpu->cpu_current_cycle  = 0;
+  cpu->cpu_is_initialized = 0;
+
+  /* Reinitialize the CPU operating mode.  */
+  cpu->ios[M6811_HPRIO] = cpu->cpu_mode;
+  return 0;
+}
+
+/* Reinitialize the processor after a reset.  */
+int
+cpu_restart (sim_cpu *cpu)
+{
+  uint16 addr;
+
+  /* Get CPU starting address depending on the CPU mode.  */
+  if (cpu->cpu_use_elf_start == 0)
+    {
+      switch ((cpu->ios[M6811_HPRIO]) & (M6811_SMOD | M6811_MDA))
+        {
+          /* Single Chip  */
+        default:
+        case 0 :
+          addr = memory_read16 (cpu, 0xFFFE);
+          break;
+
+          /* Expanded Multiplexed  */
+        case M6811_MDA:
+          addr = memory_read16 (cpu, 0xFFFE);
+          break;
+
+          /* Special Bootstrap  */
+        case M6811_SMOD:
+          addr = 0;
+          break;
+
+          /* Factory Test  */
+        case M6811_MDA | M6811_SMOD:
+          addr = memory_read16 (cpu, 0xFFFE);
+          break;
+        }
+    }
+  else
+    {
+      addr = cpu->cpu_elf_start;
+    }
+  
+  /* Setup the processor registers.  */
+  cpu->cpu_insn_pc  = addr;
+  cpu->cpu_regs.pc  = addr;
+  cpu->cpu_regs.ccr = M6811_X_BIT | M6811_I_BIT | M6811_S_BIT;
+  cpu->cpu_absolute_cycle = 0;
+  cpu->cpu_is_initialized = 1;
+  cpu->cpu_current_cycle  = 0;
+
+  cpu_call (cpu, addr);
+  
+  return 0;
+}
+
+void
+print_io_reg_desc (SIM_DESC sd, io_reg_desc *desc, int val, int mode)
+{
+  while (desc->mask)
+    {
+      if (val & desc->mask)
+       sim_io_printf (sd, "%s",
+                      mode == 0 ? desc->short_name : desc->long_name);
+      desc++;
+    }
+}
+
+void
+print_io_byte (SIM_DESC sd, const char *name, io_reg_desc *desc,
+              uint8 val, uint16 addr)
+{
+  sim_io_printf (sd, "  %-9.9s @ 0x%04x 0x%02x ", name, addr, val);
+  if (desc)
+    print_io_reg_desc (sd, desc, val, 0);
+}
+
+void
+cpu_ccr_update_tst8 (sim_cpu *proc, uint8 val)
+{
+  cpu_set_ccr_V (proc, 0);
+  cpu_set_ccr_N (proc, val & 0x80 ? 1 : 0);
+  cpu_set_ccr_Z (proc, val == 0 ? 1 : 0);
+}
+
+
+uint16
+cpu_fetch_relbranch (sim_cpu *cpu)
+{
+  uint16 addr = (uint16) cpu_fetch8 (cpu);
+
+  if (addr & 0x0080)
+    {
+      addr |= 0xFF00;
+    }
+  addr += cpu->cpu_regs.pc;
+  return addr;
+}
+
+
+/* Push all the CPU registers (when an interruption occurs).  */
+void
+cpu_push_all (sim_cpu *cpu)
+{
+  cpu_push_uint16 (cpu, cpu->cpu_regs.pc);
+  cpu_push_uint16 (cpu, cpu->cpu_regs.iy);
+  cpu_push_uint16 (cpu, cpu->cpu_regs.ix);
+  cpu_push_uint16 (cpu, cpu->cpu_regs.d);
+  cpu_push_uint8 (cpu, cpu->cpu_regs.ccr);
+}
+
+
+/* Handle special instructions.  */
+void
+cpu_special (sim_cpu *cpu, enum M6811_Special special)
+{
+  switch (special)
+    {
+    case M6811_RTI:
+      {
+        uint8 ccr;
+
+        ccr = cpu_pop_uint8 (cpu);
+        cpu_set_ccr (cpu, ccr);
+        cpu_set_d (cpu, cpu_pop_uint16 (cpu));
+        cpu_set_x (cpu, cpu_pop_uint16 (cpu));
+        cpu_set_y (cpu, cpu_pop_uint16 (cpu));
+        cpu_set_pc (cpu, cpu_pop_uint16 (cpu));
+       cpu_return (cpu);
+        break;
+      }
+      
+    case M6811_WAI:
+      /* In the ELF-start mode, we are in a special mode where
+        the WAI corresponds to an exit.  */
+      if (cpu->cpu_use_elf_start)
+        {
+          cpu_set_pc (cpu, cpu->cpu_insn_pc);
+          sim_engine_halt (CPU_STATE (cpu), cpu,
+                           NULL, NULL_CIA, sim_exited,
+                           cpu_get_d (cpu));
+          return;
+        }
+      /* SCz: not correct... */
+      cpu_push_all (cpu);
+      break;
+      
+    case M6811_SWI:
+      interrupts_raise (&cpu->cpu_interrupts, M6811_INT_SWI);
+      interrupts_process (&cpu->cpu_interrupts);
+      break;
+      
+    case M6811_EMUL_SYSCALL:
+    case M6811_ILLEGAL:
+      if (cpu->cpu_emul_syscall)
+        {
+          uint8 op = memory_read8 (cpu,
+                                   cpu_get_pc (cpu) - 1);
+          if (op == 0x41)
+            {
+             cpu_set_pc (cpu, cpu->cpu_insn_pc);
+             sim_engine_halt (CPU_STATE (cpu), cpu,
+                              NULL, NULL_CIA, sim_exited,
+                              cpu_get_d (cpu));
+             return;
+            }
+          else
+            {
+              emul_os (op, cpu);
+            }
+          return;
+        }
+      
+      interrupts_raise (&cpu->cpu_interrupts, M6811_INT_ILLEGAL);
+      interrupts_process (&cpu->cpu_interrupts);
+      break;
+
+    case M6811_TEST:
+      {
+        SIM_DESC sd;
+
+        sd = CPU_STATE (cpu);
+
+        /* Breakpoint instruction if we are under gdb.  */
+        if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG)
+          {
+            cpu->cpu_regs.pc --;
+            sim_engine_halt (CPU_STATE (cpu), cpu,
+                             0, cpu_get_pc (cpu), sim_stopped,
+                             SIM_SIGTRAP);
+          }
+        /* else this is a nop but not in test factory mode.  */
+        break;
+      }
+    }
+}
+
+
+void
+cpu_single_step (sim_cpu *cpu)
+{
+  cpu->cpu_current_cycle = 0;
+  cpu->cpu_insn_pc = cpu_get_pc (cpu);
+
+  /* Handle the pending interrupts.  If an interrupt is handled,
+     treat this as an single step.  */
+  if (interrupts_process (&cpu->cpu_interrupts))
+    {
+      cpu->cpu_absolute_cycle += cpu->cpu_current_cycle;
+      return;
+    }
+  
+  /*  printf("PC = 0x%04x\n", cpu_get_pc (cpu));*/
+  cpu_interp (cpu);
+  cpu->cpu_absolute_cycle += cpu->cpu_current_cycle;
+}
+
+/* VARARGS */
+void
+sim_memory_error (sim_cpu *cpu, SIM_SIGNAL excep,
+                 uint16 addr, const char *message, ...)
+{
+  char buf[1024];
+  va_list args;
+
+  va_start (args, message);
+  vsprintf (buf, message, args);
+  va_end (args);
+
+  printf("%s\n", buf);
+  cpu_memory_exception (cpu, excep, addr, buf);
+}
+
+
+void
+cpu_memory_exception (sim_cpu *cpu, SIM_SIGNAL excep,
+                      uint16 addr, const char *message)
+{
+  if (cpu->cpu_running == 0)
+    return;
+
+  cpu_set_pc (cpu, cpu->cpu_insn_pc);
+  sim_engine_halt (CPU_STATE (cpu), cpu, NULL,
+                   cpu_get_pc (cpu), sim_stopped, excep);
+  
+#if 0
+  cpu->mem_exception = excep;
+  cpu->fault_addr    = addr;
+  cpu->fault_msg     = strdup (message);
+
+  if (cpu->cpu_use_handler)
+    {
+      longjmp (&cpu->cpu_exception_handler, 1);
+    }
+  (* cpu->callback->printf_filtered)
+    (cpu->callback, "Fault at 0x%04x: %s\n", addr, message);
+#endif
+}
+
+void
+cpu_info (SIM_DESC sd, sim_cpu *cpu)
+{
+  sim_io_printf (sd, "CPU info:\n");
+  sim_io_printf (sd, "  Absolute cycle: %llu\n",
+                 cpu->cpu_absolute_cycle);
+  sim_io_printf (sd, "  Syscall emulation: %s\n",
+                 cpu->cpu_emul_syscall ? "yes, via 0xcd <n>" : "no");
+  sim_io_printf (sd, "  Memory errors detection: %s\n",
+                 cpu->cpu_check_memory ? "yes" : "no");
+  sim_io_printf (sd, "  Stop on interrupt: %s\n",
+                 cpu->cpu_stop_on_interrupt ? "yes" : "no");
+}
+
diff --git a/sim/m68hc11/sim-main.h b/sim/m68hc11/sim-main.h
new file mode 100644 (file)
index 0000000..8825977
--- /dev/null
@@ -0,0 +1,490 @@
+/* sim-main.h -- Simulator for Motorola 68HC11
+   Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+   Written by Stephane Carrez (stcarrez@worldnet.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.
+
+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.  */
+
+#ifndef _SIM_MAIN_H
+#define _SIM_MAIN_H
+
+#define WITH_MODULO_MEMORY 1
+#define WITH_WATCHPOINTS 1
+#define SIM_HANDLES_LMA 1
+
+#include "sim-basics.h"
+
+typedef address_word sim_cia;
+
+#include "sim-signal.h"
+#include "sim-base.h"
+
+#include "bfd.h"
+
+#include "opcode/m68hc11.h"
+
+#include "callback.h"
+#include "remote-sim.h"
+#include "opcode/m68hc11.h"
+#include "sim-types.h"
+
+typedef unsigned8 uint8;
+typedef unsigned16 uint16;
+typedef signed16 int16;
+typedef unsigned32 uint32;
+typedef signed32 int32;
+typedef unsigned64 uint64;
+typedef signed64 int64;
+
+struct _sim_cpu;
+
+#include "interrupts.h"
+#include <setjmp.h>
+
+#define X_REGNUM       0
+#define D_REGNUM       1
+#define Y_REGNUM        2
+#define SP_REGNUM      3
+#define PC_REGNUM      4
+#define A_REGNUM        5
+#define B_REGNUM        6
+#define PSW_REGNUM     7
+#define Z_REGNUM        8
+#define FP_REGNUM       9
+#define TMP_REGNUM     10
+#define ZS_REGNUM      11
+#define XY_REGNUM      12
+#define ZD1_REGNUM     13
+#define ZD32_REGNUM    (ZD1_REGNUM+31)
+
+#define FIRST_SOFT_REGNUM (Z_REGNUM)
+#define MAX_SOFT_REG      (ZD32_REGNUM - Z_REGNUM + 1)
+
+typedef struct m6811_regs {
+    unsigned short      d;
+    unsigned short      ix;
+    unsigned short      iy;
+    unsigned short      sp;
+    unsigned short      pc;
+    unsigned char       ccr;
+} m6811_regs;
+
+
+/* Description of 68HC11 IO registers.  Such description is only provided
+   for the info command to display the current setting of IO registers
+   from GDB.  */
+struct io_reg_desc
+{
+  int        mask;
+  const char *short_name;
+  const char *long_name;
+};
+typedef struct io_reg_desc io_reg_desc;
+
+extern void print_io_reg_desc (SIM_DESC sd, io_reg_desc *desc, int val,
+                              int mode);
+extern void print_io_byte (SIM_DESC sd, const char *name,
+                          io_reg_desc *desc, uint8 val, uint16 addr);
+
+
+/* List of special 68HC11 instructions that are not handled by the
+   'gencode.c' generator.  These complex instructions are implemented
+   by 'cpu_special'.  */
+enum M6811_Special
+{
+  M6811_RTI,
+  M6811_WAI,
+  M6811_SWI,
+  M6811_TEST,
+  M6811_ILLEGAL,
+  M6811_EMUL_SYSCALL
+};
+
+#define CPU_POP 1
+#define CPU_PUSH 2
+
+#define MAX_PORTS 0x40
+
+/* Tentative to keep track of the stack frame.
+   The frame is updated each time a call or a return are made.
+   We also have to take into account changes of stack pointer
+   (either thread switch or longjmp).  */
+struct cpu_frame 
+{
+  struct cpu_frame *up;
+  uint16 pc;
+  uint16 sp_low;
+  uint16 sp_high;
+};
+
+/* Represents a list of frames (or a thread).  */
+struct cpu_frame_list
+{
+  struct cpu_frame_list *next;
+  struct cpu_frame_list *prev;
+  struct cpu_frame      *frame;
+};
+
+struct _sim_cpu {
+  /* CPU registers.  */
+  struct m6811_regs     cpu_regs;
+
+  /* CPU interrupts.  */
+  struct interrupts     cpu_interrupts;
+
+  struct cpu_frame_list *cpu_frames;
+  struct cpu_frame_list *cpu_current_frame;
+  int                   cpu_need_update_frame;
+
+  /* CPU absolute cycle time.  The cycle time is updated after
+     each instruction, by the number of cycles taken by the instruction.
+     It is cleared only when reset occurs.  */
+  signed64              cpu_absolute_cycle;
+
+  /* Number of cycles to increment after the current instruction.
+     This is also the number of ticks for the generic event scheduler.  */
+  uint8                 cpu_current_cycle;
+  int                   cpu_emul_syscall;
+  int                   cpu_is_initialized;
+  int                   cpu_running;
+  int                   cpu_check_memory;
+  int                   cpu_stop_on_interrupt;
+
+  /* When this is set, start execution of program at address specified
+     in the ELF header.  This is used for testing some programs that do not
+     have an interrupt table linked with them.  Programs created during the
+     GCC validation are like this. A normal 68HC11 does not behave like
+     this (unless there is some OS or downloadable feature).  */
+  int                   cpu_use_elf_start;
+
+  /* The starting address specified in ELF header.  */
+  int                   cpu_elf_start;
+  
+  uint16                cpu_insn_pc;
+  unsigned short       cpu_nb_pseudo_regs;
+  uint16                cpu_page0_reg[MAX_SOFT_REG];
+
+  /* CPU frequency.  This is the quartz frequency.  It is divided by 4 to
+     get the cycle time.  This is used for the timer rate and for the baud
+     rate generation.  */
+  unsigned long         cpu_frequency;
+
+  /* The mode in which the CPU is configured (MODA and MODB pins).  */
+  unsigned int          cpu_mode;
+
+  /* Initial value of the CONFIG register.  */
+  uint8                 cpu_config;
+  uint8                 cpu_use_local_config;
+  
+  uint8 ios[0x3F];
+  
+  /* ... base type ... */
+  sim_cpu_base base;
+};
+
+/* Returns the cpu absolute cycle time (A virtual counter incremented
+   at each 68HC11 E clock).  */
+#define cpu_current_cycle(PROC) ((PROC)->cpu_absolute_cycle)
+#define cpu_add_cycles(PROC,T)  ((PROC)->cpu_current_cycle += (signed64) (T))
+#define cpu_is_running(PROC)    ((PROC)->cpu_running)
+
+/* Get the IO/RAM base addresses depending on the M6811_INIT register.  */
+#define cpu_get_io_base(PROC) \
+        (((uint16)(((PROC)->ios[M6811_INIT]) & 0x0F))<<12)
+#define cpu_get_reg_base(PROC) \
+        (((uint16)(((PROC)->ios[M6811_INIT]) & 0xF0))<<8)
+
+/* Returns the different CPU registers.  */
+#define cpu_get_ccr(PROC)          ((PROC)->cpu_regs.ccr)
+#define cpu_get_pc(PROC)           ((PROC)->cpu_regs.pc)
+#define cpu_get_d(PROC)            ((PROC)->cpu_regs.d)
+#define cpu_get_x(PROC)            ((PROC)->cpu_regs.ix)
+#define cpu_get_y(PROC)            ((PROC)->cpu_regs.iy)
+#define cpu_get_sp(PROC)           ((PROC)->cpu_regs.sp)
+#define cpu_get_a(PROC)            ((PROC->cpu_regs.d >> 8) & 0x0FF)
+#define cpu_get_b(PROC)            ((PROC->cpu_regs.d) & 0x0FF)
+
+#define cpu_set_d(PROC,VAL)        (((PROC)->cpu_regs.d) = (VAL))
+#define cpu_set_x(PROC,VAL)        (((PROC)->cpu_regs.ix) = (VAL))
+#define cpu_set_y(PROC,VAL)        (((PROC)->cpu_regs.iy) = (VAL))
+
+#if 0
+/* This is a function in m68hc11_sim.c to keep track of the frame.  */
+#define cpu_set_sp(PROC,VAL)       (((PROC)->cpu_regs.sp) = (VAL))
+#endif
+
+#define cpu_set_pc(PROC,VAL)       (((PROC)->cpu_regs.pc) = (VAL))
+
+#define cpu_set_a(PROC,VAL)  \
+      cpu_set_d(PROC,((VAL) << 8) | cpu_get_b(PROC))
+#define cpu_set_b(PROC,VAL)  \
+      cpu_set_d(PROC,((cpu_get_a(PROC)) << 8)|(VAL & 0x0FF))
+
+#define cpu_set_ccr(PROC,VAL)      ((PROC)->cpu_regs.ccr = (VAL))
+#define cpu_get_ccr_H(PROC)        ((cpu_get_ccr(PROC) & M6811_H_BIT) ? 1: 0)
+#define cpu_get_ccr_X(PROC)        ((cpu_get_ccr(PROC) & M6811_X_BIT) ? 1: 0)
+#define cpu_get_ccr_S(PROC)        ((cpu_get_ccr(PROC) & M6811_S_BIT) ? 1: 0)
+#define cpu_get_ccr_N(PROC)        ((cpu_get_ccr(PROC) & M6811_N_BIT) ? 1: 0)
+#define cpu_get_ccr_V(PROC)        ((cpu_get_ccr(PROC) & M6811_V_BIT) ? 1: 0)
+#define cpu_get_ccr_C(PROC)        ((cpu_get_ccr(PROC) & M6811_C_BIT) ? 1: 0)
+#define cpu_get_ccr_Z(PROC)        ((cpu_get_ccr(PROC) & M6811_Z_BIT) ? 1: 0)
+#define cpu_get_ccr_I(PROC)        ((cpu_get_ccr(PROC) & M6811_I_BIT) ? 1: 0)
+
+#define cpu_set_ccr_flag(S,B,V) \
+cpu_set_ccr(S,(cpu_get_ccr(S) & ~(B)) | ((V) ? B : 0))
+
+#define cpu_set_ccr_H(PROC,VAL)    cpu_set_ccr_flag(PROC, M6811_H_BIT, VAL)
+#define cpu_set_ccr_X(PROC,VAL)    cpu_set_ccr_flag(PROC, M6811_X_BIT, VAL)
+#define cpu_set_ccr_S(PROC,VAL)    cpu_set_ccr_flag(PROC, M6811_S_BIT, VAL)
+#define cpu_set_ccr_N(PROC,VAL)    cpu_set_ccr_flag(PROC, M6811_N_BIT, VAL)
+#define cpu_set_ccr_V(PROC,VAL)    cpu_set_ccr_flag(PROC, M6811_V_BIT, VAL)
+#define cpu_set_ccr_C(PROC,VAL)    cpu_set_ccr_flag(PROC, M6811_C_BIT, VAL)
+#define cpu_set_ccr_Z(PROC,VAL)    cpu_set_ccr_flag(PROC, M6811_Z_BIT, VAL)
+#define cpu_set_ccr_I(PROC,VAL)    cpu_set_ccr_flag(PROC, M6811_I_BIT, VAL)
+
+#undef inline
+#define inline static __inline__
+
+extern void cpu_memory_exception (struct _sim_cpu *proc,
+                                  SIM_SIGNAL excep,
+                                  uint16 addr,
+                                  const char *message);
+
+inline uint8
+memory_read8 (sim_cpu *cpu, uint16 addr)
+{
+  uint8 val;
+  
+  if (sim_core_read_buffer (CPU_STATE (cpu), cpu, 0, &val, addr, 1) != 1)
+    {
+      cpu_memory_exception (cpu, SIM_SIGSEGV, addr,
+                            "Read error");
+    }
+  return val;
+}
+
+inline void
+memory_write8 (sim_cpu *cpu, uint16 addr, uint8 val)
+{
+  if (sim_core_write_buffer (CPU_STATE (cpu), cpu, 0, &val, addr, 1) != 1)
+    {
+      cpu_memory_exception (cpu, SIM_SIGSEGV, addr,
+                            "Write error");
+    }
+}
+
+inline uint16
+memory_read16 (sim_cpu *cpu, uint16 addr)
+{
+  uint8 b[2];
+  
+  if (sim_core_read_buffer (CPU_STATE (cpu), cpu, 0, b, addr, 2) != 2)
+    {
+      cpu_memory_exception (cpu, SIM_SIGSEGV, addr,
+                            "Read error");
+    }
+  return (((uint16) (b[0])) << 8) | ((uint16) b[1]);
+}
+
+inline void
+memory_write16 (sim_cpu *cpu, uint16 addr, uint16 val)
+{
+  uint8 b[2];
+
+  b[0] = val >> 8;
+  b[1] = val;
+  if (sim_core_write_buffer (CPU_STATE (cpu), cpu, 0, b, addr, 2) != 2)
+    {
+      cpu_memory_exception (cpu, SIM_SIGSEGV, addr,
+                            "Write error");
+    }
+}
+extern void
+cpu_ccr_update_tst8 (sim_cpu *proc, uint8 val);
+
+     inline void
+cpu_ccr_update_tst16 (sim_cpu *proc, uint16 val)
+{
+  cpu_set_ccr_V (proc, 0);
+  cpu_set_ccr_N (proc, val & 0x8000 ? 1 : 0);
+  cpu_set_ccr_Z (proc, val == 0 ? 1 : 0);
+}
+
+     inline void
+cpu_ccr_update_shift8 (sim_cpu *proc, uint8 val)
+{
+  cpu_set_ccr_N (proc, val & 0x80 ? 1 : 0);
+  cpu_set_ccr_Z (proc, val == 0 ? 1 : 0);
+  cpu_set_ccr_V (proc, cpu_get_ccr_N (proc) ^ cpu_get_ccr_C (proc));
+}
+
+     inline void
+cpu_ccr_update_shift16 (sim_cpu *proc, uint16 val)
+{
+  cpu_set_ccr_N (proc, val & 0x8000 ? 1 : 0);
+  cpu_set_ccr_Z (proc, val == 0 ? 1 : 0);
+  cpu_set_ccr_V (proc, cpu_get_ccr_N (proc) ^ cpu_get_ccr_C (proc));
+}
+
+inline void
+cpu_ccr_update_add8 (sim_cpu *proc, uint8 r, uint8 a, uint8 b)
+{
+  cpu_set_ccr_C (proc, ((a & b) | (b & ~r) | (a & ~r)) & 0x80 ? 1 : 0);
+  cpu_set_ccr_V (proc, ((a & b & ~r) | (~a & ~b & r)) & 0x80 ? 1 : 0);
+  cpu_set_ccr_Z (proc, r == 0);
+  cpu_set_ccr_N (proc, r & 0x80 ? 1 : 0);
+}
+
+
+inline void
+cpu_ccr_update_sub8 (sim_cpu *proc, uint8 r, uint8 a, uint8 b)
+{
+  cpu_set_ccr_C (proc, ((~a & b) | (b & r) | (~a & r)) & 0x80 ? 1 : 0);
+  cpu_set_ccr_V (proc, ((a & ~b & ~r) | (~a & b & r)) & 0x80 ? 1 : 0);
+  cpu_set_ccr_Z (proc, r == 0);
+  cpu_set_ccr_N (proc, r & 0x80 ? 1 : 0);
+}
+
+inline void
+cpu_ccr_update_add16 (sim_cpu *proc, uint16 r, uint16 a, uint16 b)
+{
+  cpu_set_ccr_C (proc, ((a & b) | (b & ~r) | (a & ~r)) & 0x8000 ? 1 : 0);
+  cpu_set_ccr_V (proc, ((a & b & ~r) | (~a & ~b & r)) & 0x8000 ? 1 : 0);
+  cpu_set_ccr_Z (proc, r == 0);
+  cpu_set_ccr_N (proc, r & 0x8000 ? 1 : 0);
+}
+
+inline void
+cpu_ccr_update_sub16 (sim_cpu *proc, uint16 r, uint16 a, uint16 b)
+{
+  cpu_set_ccr_C (proc, ((~a & b) | (b & r) | (~a & r)) & 0x8000 ? 1 : 0);
+  cpu_set_ccr_V (proc, ((a & ~b & ~r) | (~a & b & r)) & 0x8000 ? 1 : 0);
+  cpu_set_ccr_Z (proc, r == 0);
+  cpu_set_ccr_N (proc, r & 0x8000 ? 1 : 0);
+}
+
+
+inline void
+cpu_push_uint8 (sim_cpu *proc, uint8 val)
+{
+  uint16 addr = proc->cpu_regs.sp;
+
+  memory_write8 (proc, addr, val);
+  proc->cpu_regs.sp = addr - 1;
+  proc->cpu_need_update_frame |= CPU_PUSH;
+}
+
+inline void
+cpu_push_uint16 (sim_cpu *proc, uint16 val)
+{
+  uint16 addr = proc->cpu_regs.sp - 1;
+
+  memory_write16 (proc, addr, val);
+  proc->cpu_regs.sp = addr - 1;
+  proc->cpu_need_update_frame |= CPU_PUSH;
+}
+
+inline uint8
+cpu_pop_uint8 (sim_cpu *proc)
+{
+  uint16 addr = proc->cpu_regs.sp;
+  uint8 val;
+  
+  val = memory_read8 (proc, addr + 1);
+  proc->cpu_regs.sp = addr + 1;
+  proc->cpu_need_update_frame |= CPU_POP;
+  return val;
+}
+
+inline uint16
+cpu_pop_uint16 (sim_cpu *proc)
+{
+  uint16 addr = proc->cpu_regs.sp;
+  uint16 val;
+  
+  val = memory_read16 (proc, addr + 1);
+  proc->cpu_regs.sp = addr + 2;
+  proc->cpu_need_update_frame |= CPU_POP;
+  return val;
+}
+
+inline uint8
+cpu_fetch8 (sim_cpu *proc)
+{
+  uint16 addr = proc->cpu_regs.pc;
+  uint8 val;
+  
+  val = memory_read8 (proc, addr);
+  proc->cpu_regs.pc = addr + 1;
+  return val;
+}
+
+inline uint16
+cpu_fetch16 (sim_cpu *proc)
+{
+  uint16 addr = proc->cpu_regs.pc;
+  uint16 val;
+  
+  val = memory_read16 (proc, addr);
+  proc->cpu_regs.pc = addr + 2;
+  return val;
+}
+
+extern void cpu_call (sim_cpu* proc, uint16 addr);
+extern void cpu_special (sim_cpu *proc, enum M6811_Special special);
+
+extern uint16 cpu_fetch_relbranch (sim_cpu *proc);
+extern void cpu_push_all (sim_cpu *proc);
+extern void cpu_single_step (sim_cpu *proc);
+
+extern void cpu_info (SIM_DESC sd, sim_cpu *proc);
+
+extern int cpu_initialize (SIM_DESC sd, sim_cpu *cpu);
+
+extern void cpu_print_frame (SIM_DESC sd, sim_cpu *cpu);
+extern void cpu_set_sp (sim_cpu *cpu, uint16 val);
+extern uint16 cpu_frame_reg (sim_cpu *cpu, uint16 rn);
+extern int cpu_reset (sim_cpu *cpu);
+extern int cpu_restart (sim_cpu *cpu);
+extern void sim_memory_error (sim_cpu *cpu, SIM_SIGNAL excep,
+                              uint16 addr, const char *message, ...);
+extern void emul_os (int op, sim_cpu *cpu);
+extern void cpu_interp (sim_cpu *cpu);
+
+/* The current state of the processor; registers, memory, etc.  */
+
+#define CIA_GET(CPU)      (cpu_get_pc (CPU))
+#define CIA_SET(CPU,VAL)  (cpu_set_pc ((CPU), (VAL)))
+
+#if (WITH_SMP)
+#define STATE_CPU(sd,n) (&(sd)->cpu[n])
+#else
+#define STATE_CPU(sd,n) (&(sd)->cpu[0])
+#endif
+
+struct sim_state {
+  sim_cpu        cpu[MAX_NR_PROCESSORS];
+  device         *devices;
+  sim_state_base base;
+};
+
+extern void sim_set_profile (int n);
+extern void sim_set_profile_size (int n);
+extern void sim_board_reset (SIM_DESC sd);
+
+#endif
+
+