This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFA] AVR simulator


Hi,

we have an AVR core simulator in our tree and I think it's time to contribute
it.
AVR (from Atmel) is a 8 bit microcontroller with separate I&D spaces
(Hardvard architecture).

As there are many many implementations of the AVR, only the instructions are
simulated but not the devices registers.  There are 3 pseudo registers used to
do I/O (using the same convention as avrtest).

Integration with gdb will come soon - currently it can be used as a standalone
simulator.

Tristan.

2009-04-10  Tristan Gingold  <gingold@adacore.com>

        * avr: New directory.
	* avr/interp.c, avr/Makefile.in, avr/configure.ac: New files.
	* avr/config.in: New file, generated by autoheader.
	* avr/configure: New file generated by autoconf.
	* configure.ac: Add avr.
	* configure: Regenerated.

--- configure.ac	8 Apr 2008 09:15:56 -0000	1.14
+++ configure.ac	10 Apr 2009 10:22:18 -0000
@@ -51,6 +51,9 @@
            AC_CONFIG_SUBDIRS(arm)
 	   testsuite=yes
 	   ;;
+       avr*-*-*)
+           AC_CONFIG_SUBDIRS(avr)
+	   ;;
        cr16*-*-*)
 	   AC_CONFIG_SUBDIRS(cr16)
 	   testsuite=yes
diff -ruN null/Makefile.in avr/Makefile.in
--- null/Makefile.in	1970-01-01 01:00:00.000000000 +0100
+++ avr/Makefile.in	2009-04-10 12:06:07.000000000 +0200
@@ -0,0 +1,25 @@
+#    Makefile template for Configure for the AVR sim library.
+#    Copyright (C) 2009
+#    Free Software Foundation, Inc.
+# 
+# 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 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+## COMMON_PRE_CONFIG_FRAG
+
+SIM_OBJS = interp.o sim-load.o
+SIM_EXTRA_LIBS = -lm
+
+## COMMON_POST_CONFIG_FRAG
+
+interp.o: interp.c
diff -ruN null/config.in avr/config.in
--- null/config.in	1970-01-01 01:00:00.000000000 +0100
+++ avr/config.in	2008-11-25 15:58:54.000000000 +0100
@@ -0,0 +1,101 @@
+/* config.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if translation of program messages to the user's native
+   language is requested. */
+#undef ENABLE_NLS
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <errno.h> header file. */
+#undef HAVE_ERRNO_H
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if you have the <fpu_control.h> header file. */
+#undef HAVE_FPU_CONTROL_H
+
+/* Define to 1 if you have the `getrusage' function. */
+#undef HAVE_GETRUSAGE
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#undef HAVE_LIBNSL
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+#undef HAVE_LIBSOCKET
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `sigaction' function. */
+#undef HAVE_SIGACTION
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#undef HAVE_SYS_RESOURCE_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the `time' function. */
+#undef HAVE_TIME
+
+/* Define to 1 if you have the <time.h> header file. */
+#undef HAVE_TIME_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the <zlib.h> header file. */
+#undef HAVE_ZLIB_H
+
+/* Define to 1 if you have the `__setfpucw' function. */
+#undef HAVE___SETFPUCW
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Additional package description */
+#undef PKGVERSION
+
+/* Bug reporting address */
+#undef REPORT_BUGS_TO
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#undef RETSIGTYPE
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
diff -ruN null/configure.ac avr/configure.ac
--- null/configure.ac	1970-01-01 01:00:00.000000000 +0100
+++ avr/configure.ac	2009-04-10 11:45:44.000000000 +0200
@@ -0,0 +1,12 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_PREREQ(2.59)dnl
+AC_INIT(Makefile.in)
+AC_CONFIG_HEADER(config.h:config.in)
+
+sinclude(../common/aclocal.m4)
+
+# Bugs in autoconf 2.59 break the call to SIM_AC_COMMON, hack around
+# it by inlining the macro's contents.
+sinclude(../common/common.m4)
+
+SIM_AC_OUTPUT
diff -ruN null/interp.c avr/interp.c
--- null/interp.c	1970-01-01 01:00:00.000000000 +0100
+++ avr/interp.c	2009-04-10 11:52:23.000000000 +0200
@@ -0,0 +1,1848 @@
+/* Simulator for Atmel's AVR core.
+   Copyright (C) 2009 Free Software Foundation, Inc.
+   Written by Tristan Gingold, AdaCore.
+
+   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 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include "bfd.h"
+#include "gdb/callback.h"
+#include "gdb/signals.h"
+#include "libiberty.h"
+#include "gdb/remote-sim.h"
+#include "dis-asm.h"
+#include "sim-utils.h"
+
+/* As AVR is a 8/16 bits processor, define handy types.  */
+typedef unsigned short int word;
+typedef signed short int sword;
+typedef unsigned char byte;
+typedef signed char sbyte;
+
+/* Debug flag to display instructions and registers.  */
+static int tracing = 0;
+static int lock_step = 0;
+static int verbose;
+
+/* The only real register.  */
+static unsigned int pc;
+
+/* We update a cycle counter.  */
+static unsigned int cycles = 0;
+
+/* If true, the pc needs more than 2 bytes.  */
+static int avr_pc22;
+
+static struct bfd *cur_bfd;
+
+static enum sim_stop cpu_exception;
+static int cpu_signal;
+
+static SIM_OPEN_KIND sim_kind;
+static char *myname;
+static host_callback *callback;
+
+/* Max size of I space (which is always flash on avr).  */
+#define MAX_AVR_FLASH (128 * 1024)
+#define PC_MASK (MAX_AVR_FLASH - 1)
+
+/* Mac size of D space.  */
+#define MAX_AVR_SRAM (64 * 1024)
+#define SRAM_MASK (MAX_AVR_SRAM - 1)
+
+/* D space offset in ELF file.  */
+#define SRAM_VADDR 0x800000
+
+/* Simulator specific ports.  */
+#define STDIO_PORT	0x52
+#define EXIT_PORT	0x4F
+#define ABORT_PORT	0x49
+
+/* GDB defined register numbers.  */
+#define AVR_SREG_REGNUM  32
+#define AVR_SP_REGNUM    33
+#define AVR_PC_REGNUM    34
+
+/* Memory mapped registers.  */
+#define SREG	0x5F
+#define REG_SP	0x5D
+#define EIND	0x5C
+#define RAMPZ	0x5B
+
+#define REGX 0x1a
+#define REGY 0x1c
+#define REGZ 0x1e
+#define REGZ_LO 0x1e
+#define REGZ_HI 0x1f
+
+/* Sreg (status) bits.  */
+#define SREG_I 0x80
+#define SREG_T 0x40
+#define SREG_H 0x20
+#define SREG_S 0x10
+#define SREG_V 0x08
+#define SREG_N 0x04
+#define SREG_Z 0x02
+#define SREG_C 0x01
+
+/* In order to speed up emulation we use a simple approach:
+   a code is associated with each instruction.  The pre-decoding occurs
+   usually once when the instruction is first seen.
+   This works well because I&D spaces are separated.
+
+   Missing opcodes: sleep, spm, wdr (as they are mmcu dependent).
+*/
+enum avr_opcode
+  {
+    /* Opcode not yet decoded.  */
+    OP_unknown,
+    OP_bad,
+
+    OP_nop,
+
+    OP_rjmp,
+    OP_rcall,
+    OP_ret,
+    OP_reti,
+
+    OP_break,
+
+    OP_brbs,
+    OP_brbc,
+
+    OP_bset,
+    OP_bclr,
+
+    OP_bld,
+    OP_bst,
+
+    OP_sbrc,
+    OP_sbrs,
+
+    OP_eor,
+    OP_and,
+    OP_andi,
+    OP_or,
+    OP_ori,
+    OP_com,
+    OP_swap,
+    OP_neg,
+
+    OP_out,
+    OP_in,
+    OP_cbi,
+    OP_sbi,
+
+    OP_sbic,
+    OP_sbis,
+
+    OP_ldi,
+    OP_cpse,
+    OP_cp,
+    OP_cpi,
+    OP_cpc,
+    OP_sub,
+    OP_sbc,
+    OP_sbiw,
+    OP_adiw,
+    OP_add,
+    OP_adc,
+    OP_subi,
+    OP_sbci,
+    OP_inc,
+    OP_dec,
+    OP_lsr,
+    OP_ror,
+    OP_asr,
+
+    OP_mul,
+    OP_muls,
+    OP_mulsu,
+    OP_fmul,
+    OP_fmuls,
+    OP_fmulsu,
+
+    OP_mov,
+    OP_movw,
+
+    OP_push,
+    OP_pop,
+
+    OP_st_X,
+    OP_st_dec_X,
+    OP_st_X_inc,
+    OP_st_Y_inc,
+    OP_st_dec_Y,
+    OP_st_Z_inc,
+    OP_st_dec_Z,
+    OP_std_Y,
+    OP_std_Z,
+    OP_ldd_Y,
+    OP_ldd_Z,
+    OP_ld_Z_inc,
+    OP_ld_dec_Z,
+    OP_ld_Y_inc,
+    OP_ld_dec_Y,
+    OP_ld_X,
+    OP_ld_X_inc,
+    OP_ld_dec_X,
+    
+    OP_lpm,
+    OP_lpm_Z,
+    OP_lpm_inc_Z,
+    OP_elpm,
+    OP_elpm_Z,
+    OP_elpm_inc_Z,
+
+    OP_ijmp,
+    OP_icall,
+
+    OP_eijmp,
+    OP_eicall,
+
+    /* 2 words opcodes.  */
+#define OP_2words OP_jmp
+    OP_jmp,
+    OP_call,
+    OP_sts,
+    OP_lds
+  };
+
+struct avr_insn_cell
+{
+  /* The insn (16 bits).  */
+  word op;
+
+  /* Pre-decoding code.  */
+  enum avr_opcode code : 8;
+  /* One byte of additional information.  */
+  byte r;
+};
+
+/* I&D memories.  */
+static struct avr_insn_cell flash[MAX_AVR_FLASH];
+static byte sram[MAX_AVR_SRAM];
+
+void
+sim_size (int s)
+{
+}
+
+/* Sign extend a value.  */
+static int sign_ext (word val, int nb_bits)
+{
+  if (val & (1 << (nb_bits - 1)))
+    return val | (-1 << nb_bits);
+  return val;
+}
+
+/* Insn field extractors.  */
+
+/* Extract xxxx_xxxRx_xxxx_RRRR.  */
+static inline byte get_r (word op)
+{
+  return (op & 0xf) | ((op >> 5) & 0x10);
+}
+
+/* Extract xxxx_xxxxx_xxxx_RRRR.  */
+static inline byte get_r16 (word op)
+{
+  return 16 + (op & 0xf);
+}
+
+/* Extract xxxx_xxxxx_xxxx_xRRR.  */
+static inline byte get_r16_23 (word op)
+{
+  return 16 + (op & 0x7);
+}
+
+/* Extract xxxx_xxxD_DDDD_xxxx.  */
+static inline byte get_d (word op)
+{
+  return (op >> 4) & 0x1f;
+}
+
+/* Extract xxxx_xxxx_DDDD_xxxx.  */
+static inline byte get_d16 (word op)
+{
+  return 16 + ((op >> 4) & 0x0f);
+}
+
+/* Extract xxxx_xxxx_xDDD_xxxx.  */
+static inline byte get_d16_23 (word op)
+{
+  return 16 + ((op >> 4) & 0x07);
+}
+
+/* Extract xxxx_xAAx_xxxx_AAAA.  */
+static inline byte get_A (word op)
+{
+  return (op & 0x0f) | ((op & 0x600) >> 5);
+}
+
+/* Extract xxxx_xxxx_AAAA_Axxx.  */
+static inline byte get_biA (word op)
+{
+  return (op >> 3) & 0x1f;
+}
+
+/* Extract xxxx_KKKK_xxxx_KKKK.  */
+static inline byte get_K (word op)
+{
+  return (op & 0xf) | ((op & 0xf00) >> 4);
+}
+
+/* Extract xxxx_xxKK_KKKK_Kxxx.  */
+static inline int get_k (word op)
+{
+  return sign_ext ((op & 0x3f8) >> 3, 7);
+}
+
+/* Extract xxxx_xxxx_xxDD_xxxx.  */
+static inline byte get_d24 (word op)
+{
+  return 24 + ((op >> 3) & 6);
+}
+
+/* Extract xxxx_xxxx_KKxx_KKKK.  */
+static inline byte get_k6 (word op)
+{
+  return (op & 0xf) | ((op >> 2) & 0x30);
+}
+ 
+/* Extract xxQx_QQxx_xxxx_xQQQ.  */
+static inline byte get_q (word op)
+{
+  return (op & 7) | ((op >> 7) & 0x18)| ((op >> 8) & 0x20);
+}
+
+/* Extract xxxx_xxxx_xxxx_xBBB.  */
+static inline byte get_b (word op)
+{
+  return (op & 7);
+}
+
+/* AVR is little endian.  */
+static inline word
+read_word (unsigned int addr)
+{
+  return sram[addr] | (sram[addr + 1] << 8);
+}
+
+static inline void
+write_word (unsigned int addr, word w)
+{
+  sram[addr] = w;
+  sram[addr + 1] = w >> 8;
+}
+
+static inline word
+read_word_post_inc (unsigned int addr)
+{
+  word v = read_word (addr);
+  write_word (addr, v + 1);
+  return v;
+}
+
+static inline word
+read_word_pre_dec (unsigned int addr)
+{
+  word v = read_word (addr) - 1;
+  write_word (addr, v);
+  return v;
+}
+
+static void
+update_flags_logic (byte res)
+{
+  sram[SREG] &= ~(SREG_S | SREG_V | SREG_N | SREG_Z);
+  if (res == 0)
+    sram[SREG] |= SREG_Z;
+  if (res & 0x80)
+    sram[SREG] |= SREG_N | SREG_S;
+}
+
+static void
+update_flags_add (byte r, byte a, byte b)
+{
+  byte carry;
+
+  sram[SREG] &= ~(SREG_H | SREG_S | SREG_V | SREG_N | SREG_Z | SREG_C);
+  if (r & 0x80)
+    sram[SREG] |= SREG_N;
+  carry = (a & b) | (a & ~r) | (b & ~r);
+  if (carry & 0x08)
+    sram[SREG] |= SREG_H;
+  if (carry & 0x80)
+    sram[SREG] |= SREG_C;
+  if (((a & b & ~r) | (~a & ~b & r)) & 0x80)
+    sram[SREG] |= SREG_V;
+  if (!(sram[SREG] & SREG_N) ^ !(sram[SREG] & SREG_V))
+    sram[SREG] |= SREG_S;
+  if (r == 0)
+    sram[SREG] |= SREG_Z;
+}
+
+static void update_flags_sub (byte r, byte a, byte b)
+{
+  byte carry;
+
+  sram[SREG] &= ~(SREG_H | SREG_S | SREG_V | SREG_N | SREG_Z | SREG_C);
+  if (r & 0x80)
+    sram[SREG] |= SREG_N;
+  carry = (~a & b) | (b & r) | (r & ~a);
+  if (carry & 0x08)
+    sram[SREG] |= SREG_H;
+  if (carry & 0x80)
+    sram[SREG] |= SREG_C;
+  if (((a & ~b & ~r) | (~a & b & r)) & 0x80)
+    sram[SREG] |= SREG_V;
+  if (!(sram[SREG] & SREG_N) ^ !(sram[SREG] & SREG_V))
+    sram[SREG] |= SREG_S;
+  /* Note: Z is not set.  */
+}
+
+static enum avr_opcode
+decode (unsigned int pc)
+{
+  word op1 = flash[pc].op;
+
+  switch ((op1 >> 12) & 0x0f)
+    {
+    case 0x0:
+      switch ((op1 >> 10) & 0x3)
+        {
+        case 0x0:
+          switch ((op1 >> 8) & 0x3)
+            {
+            case 0x0:
+              if (op1 == 0)
+                return OP_nop;
+              break;
+            case 0x1:
+              return OP_movw;
+            case 0x2:
+              return OP_muls;
+            case 0x3:
+              if (op1 & 0x80)
+                {
+                  if (op1 & 0x08)
+                    return OP_fmulsu;
+                  else
+                    return OP_fmuls;
+                }
+              else
+                {
+                  if (op1 & 0x08)
+                    return OP_fmul;
+                  else
+                    return OP_mulsu;
+                }
+            }
+          break;
+        case 0x1:
+          return OP_cpc;
+        case 0x2:
+          flash[pc].r = SREG_C;
+          return OP_sbc;
+        case 0x3:
+          flash[pc].r = 0;
+          return OP_add;
+        }
+      break;
+    case 0x1:
+      switch ((op1 >> 10) & 0x3)
+        {
+        case 0x0:
+          return OP_cpse;
+        case 0x1:
+          return OP_cp;
+        case 0x2:
+          flash[pc].r = 0;
+          return OP_sub;
+        case 0x3:
+          flash[pc].r = SREG_C;
+          return OP_adc;
+        }
+      break;
+    case 0x2:
+      switch ((op1 >> 10) & 0x3)
+        {
+        case 0x0:
+          return OP_and;
+        case 0x1:
+          return OP_eor;
+        case 0x2:
+          return OP_or;
+        case 0x3:
+          return OP_mov;
+        }
+      break;
+    case 0x3:
+      return OP_cpi;
+    case 0x4:
+      return OP_sbci;
+    case 0x5:
+      return OP_subi;
+    case 0x6:
+      return OP_ori;
+    case 0x7:
+      return OP_andi;
+    case 0x8:
+    case 0xa:
+      if (op1 & 0x0200)
+        {
+          if (op1 & 0x0008)
+            {
+              flash[pc].r = get_q (op1);
+              return OP_std_Y;
+            }
+          else
+            {
+              flash[pc].r = get_q (op1);
+              return OP_std_Z;
+            }
+        }
+      else
+        {
+          if (op1 & 0x0008)
+            {
+              flash[pc].r = get_q (op1);
+              return OP_ldd_Y;
+            }
+          else
+            {
+              flash[pc].r = get_q (op1);
+              return OP_ldd_Z;
+            }
+        }
+      return;
+    case 0x9: /* 9xxx */
+      switch ((op1 >> 8) & 0xf)
+        {
+        case 0x0:
+        case 0x1:
+          switch ((op1 >> 0) & 0xf)
+            {
+            case 0x0:
+              return OP_lds;
+            case 0x1:
+              return OP_ld_Z_inc;
+            case 0x2:
+              return OP_ld_dec_Z;
+            case 0x4:
+              return OP_lpm_Z;
+            case 0x5:
+              return OP_lpm_inc_Z;
+            case 0x6:
+              return OP_elpm_Z;
+            case 0x7:
+              return OP_elpm_inc_Z;
+            case 0x9:
+              return OP_ld_Y_inc;
+            case 0xa:
+              return OP_ld_dec_Y;
+            case 0xc:
+              return OP_ld_X;
+            case 0xd:
+              return OP_ld_X_inc;
+            case 0xe:
+              return OP_ld_dec_X;
+            case 0xf:
+              return OP_pop;
+            }
+          break;
+        case 0x2:
+        case 0x3:
+          switch ((op1 >> 0) & 0xf)
+            {
+            case 0x0:
+              return OP_sts;
+            case 0x1:
+              return OP_st_Z_inc;
+            case 0x2:
+              return OP_st_dec_Z;
+            case 0x9:
+              return OP_st_Y_inc;
+            case 0xa:
+              return OP_st_dec_Y;
+            case 0xc:
+              return OP_st_X;
+            case 0xd:
+              return OP_st_X_inc;
+            case 0xe:
+              return OP_st_dec_X;
+            case 0xf:
+              return OP_push;
+            }
+          break;
+        case 0x4:
+        case 0x5:
+          switch (op1 & 0xf)
+            {
+            case 0x0:
+              return OP_com;
+            case 0x1:
+              return OP_neg;
+            case 0x2:
+              return OP_swap;
+            case 0x3:
+              return OP_inc;
+            case 0x5:
+              flash[pc].r = 0x80;
+              return OP_asr;
+            case 0x6:
+              flash[pc].r = 0;
+              return OP_lsr;
+            case 0x7:
+              return OP_ror;
+            case 0x8: /* 9[45]x8 */
+              switch ((op1 >> 4) & 0x1f)
+                {
+                case 0x00:
+                case 0x01:
+                case 0x02:
+                case 0x03:
+                case 0x04:
+                case 0x05:
+                case 0x06:
+                case 0x07:
+                  return OP_bset;
+                case 0x08:
+                case 0x09:
+                case 0x0a:
+                case 0x0b:
+                case 0x0c:
+                case 0x0d:
+                case 0x0e:
+                case 0x0f:
+                  return OP_bclr;
+                case 0x10:
+                  return OP_ret;
+                case 0x11:
+                  return OP_reti;
+                case 0x19:
+                  return OP_break;
+                case 0x1c:
+                  return OP_lpm;
+                case 0x1d:
+                  return OP_elpm;
+                default:
+                  break;
+                }
+              break;
+            case 0x9: /* 9[45]x9 */
+              switch ((op1 >> 4) & 0x1f)
+                {
+                case 0x00:
+                  return OP_ijmp;
+                case 0x01:
+                  return OP_eijmp;
+                case 0x10:
+                  return OP_icall;
+                case 0x11:
+                  return OP_eicall;
+                default:
+                  break;
+                }
+              break;
+            case 0xa:
+              return OP_dec;
+            case 0xc:
+            case 0xd:
+              flash[pc].r = ((op1 & 0x1f0) >> 3) | (op1 & 1);
+              return OP_jmp;
+            case 0xe:
+            case 0xf:
+              flash[pc].r = ((op1 & 0x1f0) >> 3) | (op1 & 1);
+              return OP_call;
+            }
+          break;
+        case 0x6:
+          return OP_adiw;
+        case 0x7:
+          return OP_sbiw;
+        case 0x8:
+          return OP_cbi;
+        case 0x9:
+          return OP_sbic;
+        case 0xa:
+          return OP_sbi;
+        case 0xb:
+          return OP_sbis;
+        case 0xc:
+        case 0xd:
+        case 0xe:
+        case 0xf:
+          return OP_mul;
+        }
+      break;
+    case 0xb:
+      flash[pc].r = get_A (op1);
+      if (((op1 >> 11) & 1) == 0)
+        return OP_in;
+      else
+        return OP_out;
+    case 0xc:
+      return OP_rjmp;
+    case 0xd:
+      return OP_rcall;
+    case 0xe:
+      return OP_ldi;
+    case 0xf:
+      switch ((op1 >> 9) & 7)
+        {
+        case 0:
+        case 1:
+          flash[pc].r = 1 << (op1 & 7);
+          return OP_brbs;
+        case 2:
+        case 3:
+          flash[pc].r = 1 << (op1 & 7);
+          return OP_brbc;
+        case 4:
+          if ((op1 & 8) == 0)
+            {
+              flash[pc].r = 1 << (op1 & 7);
+              return OP_bld;
+            }
+          break;
+        case 5:
+          if ((op1 & 8) == 0)
+            {
+              flash[pc].r = 1 << (op1 & 7);
+              return OP_bst;
+            }
+          break;
+        case 6:
+          if ((op1 & 8) == 0)
+            {
+              flash[pc].r = 1 << (op1 & 7);
+              return OP_sbrc;
+            }
+          break;
+        case 7:
+          if ((op1 & 8) == 0)
+            {
+              flash[pc].r = 1 << (op1 & 7);
+              return OP_sbrs;
+            }
+          break;
+        }
+    }
+  sim_cb_eprintf (callback,
+                  "Unhandled instruction at pc=0x%x, op=%04x\n", pc * 2, op1);
+  return OP_bad;
+}
+
+/* Disassemble an instruction.  */
+
+static int
+disasm_read_memory (bfd_vma memaddr, bfd_byte *myaddr, unsigned int length,
+			struct disassemble_info *info)
+{
+  int res;
+
+  res = sim_read (NULL, memaddr, myaddr, length);
+  if (res != length)
+    return -1;
+  return 0;
+}
+
+/* Memory error support for an opcodes disassembler.  */
+
+static void
+disasm_perror_memory (int status, bfd_vma memaddr,
+			  struct disassemble_info *info)
+{
+  if (status != -1)
+    /* Can't happen.  */
+    info->fprintf_func (info->stream, "Unknown error %d.", status);
+  else
+    /* Actually, address between memaddr and memaddr + len was
+       out of bounds.  */
+    info->fprintf_func (info->stream,
+			"Address 0x%x is out of bounds.",
+			(int) memaddr);
+}
+
+static void
+disassemble_insn (SIM_DESC sd, SIM_ADDR pc)
+{
+  struct disassemble_info disasm_info;
+  int len;
+  int i;
+
+  INIT_DISASSEMBLE_INFO (disasm_info, callback, sim_cb_eprintf);
+
+  disasm_info.arch = bfd_get_arch (cur_bfd);
+  disasm_info.mach = bfd_get_mach (cur_bfd);
+  disasm_info.endian = BFD_ENDIAN_LITTLE;
+  disasm_info.read_memory_func = disasm_read_memory;
+  disasm_info.memory_error_func = disasm_perror_memory;
+
+  len = print_insn_avr (pc << 1, &disasm_info);
+  len = len / 2;
+  for (i = 0; i < len; i++)
+    sim_cb_eprintf (callback, " %04x", flash[pc + i].op);
+}
+
+static void
+do_call (unsigned int npc)
+{
+  unsigned int sp = read_word (REG_SP);
+
+  /* Big endian!  */
+  sram[sp--] = pc;
+  sram[sp--] = pc >> 8;
+  if (avr_pc22)
+    {
+      sram[sp--] = pc >> 16;
+      cycles++;
+    }
+  write_word (REG_SP, sp);
+  pc = npc & PC_MASK;
+  cycles += 3;
+}
+
+static int
+get_insn_length (unsigned int p)
+{
+  if (flash[p].code == OP_unknown)
+    flash[p].code = decode(p);
+  if (flash[p].code >= OP_2words)
+    return 2;
+  else
+    return 1;
+}
+
+static unsigned int
+get_z (void)
+{
+  return (sram[RAMPZ] << 16) | (sram[REGZ_HI] << 8) | sram[REGZ_LO];
+}
+
+static unsigned char
+get_lpm (unsigned int addr)
+{
+  word w;
+
+  w = flash[(addr >> 1) & PC_MASK].op;
+  if (addr & 1)
+    w >>= 8;
+  return w;
+}
+
+static void
+gen_mul (unsigned int res)
+{
+  write_word (0, res);
+  sram[SREG] &= ~(SREG_Z | SREG_C);
+  if (res == 0)
+    sram[SREG] |= SREG_Z;
+  if (res & 0x8000)
+    sram[SREG] |= SREG_C;
+  cycles++;
+}
+
+void
+sim_resume (SIM_DESC sd, int step, int signal)
+{
+  unsigned int ipc;
+
+  if (step)
+    {
+      cpu_exception = sim_stopped;
+      cpu_signal = TARGET_SIGNAL_TRAP;
+    }
+  else
+    cpu_exception = sim_running;
+
+  do
+    {
+      int code;
+      word op;
+      byte res;
+      byte r, d, vd;
+
+    again:
+      code = flash[pc].code;
+      op = flash[pc].op;
+
+
+      if ((tracing || lock_step) && code != OP_unknown)
+	{
+	  if (verbose > 0) {
+	    int flags;
+	    int i;
+	    
+	    sim_cb_eprintf (callback, "R00-07:");
+	    for (i = 0; i < 8; i++)
+	      sim_cb_eprintf (callback, " %02x", sram[i]);
+	    sim_cb_eprintf (callback, " -");
+	    for (i = 8; i < 16; i++)
+	      sim_cb_eprintf (callback, " %02x", sram[i]);
+	    sim_cb_eprintf (callback, "  SP: %02x %02x",
+                            sram[REG_SP + 1], sram[REG_SP]);
+	    sim_cb_eprintf (callback, "\n");
+	    sim_cb_eprintf (callback, "R16-31:");
+	    for (i = 16; i < 24; i++)
+	      sim_cb_eprintf (callback, " %02x", sram[i]);
+	    sim_cb_eprintf (callback, " -");
+	    for (i = 24; i < 32; i++)
+	      sim_cb_eprintf (callback, " %02x", sram[i]);
+	    sim_cb_eprintf (callback, "  ");
+	    flags = sram[SREG];
+	    for (i = 0; i < 8; i++)
+	      sim_cb_eprintf (callback, "%c",
+                              flags & (0x80 >> i) ? "ITHSVNZC"[i] : '-');
+	    sim_cb_eprintf (callback, "\n");
+	  }
+
+	  if (lock_step && !tracing)
+	    sim_cb_eprintf (callback, "%06x: %04x\n", 2 * pc, flash[pc].op);
+	  else
+	    {
+	      sim_cb_eprintf (callback, "pc=0x%06x insn=0x%04x code=%d r=%d\n",
+                              2 * pc, flash[pc].op, code, flash[pc].r);
+	      disassemble_insn (sd, pc);
+	      sim_cb_eprintf (callback, "\n");
+	    }
+	}
+
+      ipc = pc;
+      pc = (pc + 1) & PC_MASK;
+      cycles++;
+
+      switch (code)
+	{
+	case OP_unknown:
+          flash[ipc].code = decode(ipc);
+	  pc = ipc;
+	  cycles--;
+	  goto again;
+	  break;
+
+	case OP_nop:
+          break;
+
+	case OP_jmp:
+	  /* 2 words instruction, but we don't care about the pc.  */
+	  pc = ((flash[ipc].r << 16) | flash[ipc + 1].op) & PC_MASK;
+	  cycles += 2;
+	  break;
+
+	case OP_eijmp:
+	  pc = ((sram[EIND] << 16) | read_word (REGZ)) & PC_MASK;
+	  cycles += 2;
+	  break;
+
+	case OP_ijmp:
+	  pc = read_word (REGZ) & PC_MASK;
+	  cycles += 1;
+	  break;
+
+	case OP_call:
+	  /* 2 words instruction.  */
+	  pc++;
+	  do_call ((flash[ipc].r << 16) | flash[ipc + 1].op);
+	  break;
+
+	case OP_eicall:
+	  do_call ((sram[EIND] << 16) | read_word (REGZ));
+	  break;
+
+	case OP_icall:
+	  do_call (read_word (REGZ));
+	  break;
+
+	case OP_rcall:
+	  do_call (pc + sign_ext (op & 0xfff, 12));
+	  break;
+
+	case OP_reti:
+          sram[SREG] |= SREG_I;
+          /* Fall through */
+	case OP_ret:
+	  {
+	    unsigned int sp = read_word (REG_SP);
+	    if (avr_pc22)
+	      {
+		pc = sram[++sp] = pc << 16;
+		cycles++;
+	      }
+	    else
+	      pc = 0;
+	    pc |= sram[++sp] << 8;
+	    pc |= sram[++sp];
+	    write_word (REG_SP, sp);
+	  }
+	  cycles += 3;
+	  break;
+	  
+	case OP_break:
+	  /* Stop on this address.  */
+	  cpu_exception = sim_stopped;
+	  cpu_signal = TARGET_SIGNAL_TRAP;
+	  pc = ipc;
+	  break;
+
+	case OP_bld:
+	  d = get_d (op);
+	  r = flash[ipc].r;
+	  if (sram[SREG] & SREG_T)
+	    sram[d] |= r;
+	  else
+	    sram[d] &= ~r;
+	  break;
+
+	case OP_bst:
+	  if (sram[get_d (op)] & flash[ipc].r)
+	    sram[SREG] |= SREG_T;
+	  else
+	    sram[SREG] &= ~SREG_T;
+	  break;
+
+	case OP_sbrc:
+	case OP_sbrs:
+	  if (((sram[get_d (op)] & flash[ipc].r) == 0) ^ ((op & 0x0200) != 0))
+            {
+              int l = get_insn_length(pc);
+              pc += l;
+              cycles += l;
+            }
+	  break;
+
+	case OP_push:
+	  {
+	    unsigned int sp = read_word (REG_SP);
+	    sram[sp--] = sram[get_d (op)];
+	    write_word (REG_SP, sp);
+	  }
+	  cycles++;
+	  break;
+
+	case OP_pop:
+	  {
+	    unsigned int sp = read_word (REG_SP);
+	    sram[get_d (op)] = sram[++sp];
+	    write_word (REG_SP, sp);
+	  }
+	  cycles++;
+	  break;
+
+	case OP_bclr:
+	  sram[SREG] &= ~(1 << ((op >> 4) & 0x7));
+	  break;
+
+	case OP_bset:
+	  sram[SREG] |= 1 << ((op >> 4) & 0x7);
+	  break;
+
+	case OP_rjmp:
+	  pc = (pc + sign_ext (op & 0xfff, 12)) & PC_MASK;
+	  cycles++;
+	  break;
+
+	case OP_eor:
+	  d = get_d (op);
+	  res = sram[d] ^ sram[get_r (op)];
+	  sram[d] = res;
+	  update_flags_logic (res);
+	  break;
+
+	case OP_and:
+	  d = get_d (op);
+	  res = sram[d] & sram[get_r (op)];
+	  sram[d] = res;
+	  update_flags_logic (res);
+	  break;
+
+	case OP_andi:
+	  d = get_d16 (op);
+	  res = sram[d] & get_K (op);
+	  sram[d] = res;
+	  update_flags_logic (res);
+	  break;
+
+	case OP_or:
+	  d = get_d (op);
+	  res = sram[d] | sram[get_r (op)];
+	  sram[d] = res;
+	  update_flags_logic (res);
+	  break;
+
+	case OP_ori:
+	  d = get_d16 (op);
+	  res = sram[d] | get_K (op);
+	  sram[d] = res;
+	  update_flags_logic (res);
+	  break;
+
+	case OP_com:
+	  d = get_d (op);
+	  res = ~sram[d];
+	  sram[d] = res;
+	  update_flags_logic (res);
+	  sram[SREG] |= SREG_C;
+	  break;
+
+	case OP_swap:
+	  d = get_d (op);
+	  vd = sram[d];
+	  sram[d] = (vd >> 4) | (vd << 4);
+	  break;
+
+	case OP_neg:
+	  d = get_d (op);
+	  vd = sram[d];
+	  res = -vd;
+	  sram[d] = res;
+	  sram[SREG] &= ~(SREG_H | SREG_S | SREG_V | SREG_N | SREG_Z | SREG_C);
+	  if (res == 0)
+	    sram[SREG] |= SREG_Z;
+	  else
+	    sram[SREG] |= SREG_C;
+	  if (res == 0x80)
+	    sram[SREG] |= SREG_V | SREG_N;
+	  else if (res & 0x80)
+	    sram[SREG] |= SREG_N | SREG_S;
+	  if ((res | vd) & 0x08)
+	    sram[SREG] |= SREG_H;
+	  break;
+
+	case OP_inc:
+	  d = get_d (op);
+	  res = sram[d] + 1;
+	  sram[d] = res;
+	  sram[SREG] &= ~(SREG_S | SREG_V | SREG_N | SREG_Z);
+	  if (res == 0x80)
+	    sram[SREG] |= SREG_V | SREG_N;
+	  else if (res & 0x80)
+	    sram[SREG] |= SREG_N | SREG_S;
+	  else if (res == 0)
+	    sram[SREG] |= SREG_Z;
+	  break;
+
+	case OP_dec:
+	  d = get_d (op);
+	  res = sram[d] - 1;
+	  sram[d] = res;
+	  sram[SREG] &= ~(SREG_S | SREG_V | SREG_N | SREG_Z);
+	  if (res == 0x7f)
+	    sram[SREG] |= SREG_V | SREG_S;
+	  else if (res & 0x80)
+	    sram[SREG] |= SREG_N | SREG_S;
+	  else if (res == 0)
+	    sram[SREG] |= SREG_Z;
+	  break;
+
+	case OP_lsr:
+	case OP_asr:
+	  d = get_d (op);
+	  vd = sram[d];
+	  res = (vd >> 1) | (vd & flash[ipc].r);
+	  sram[d] = res;
+	  sram[SREG] &= ~(SREG_S | SREG_V | SREG_N | SREG_Z | SREG_C);
+	  if (vd & 1)
+	    sram[SREG] |= SREG_C | SREG_S;
+	  if (res & 0x80)
+	    sram[SREG] |= SREG_N;
+          if (!(sram[SREG] & SREG_N) ^ !(sram[SREG] & SREG_C))
+            sram[SREG] |= SREG_V;
+	  if (res == 0)
+	    sram[SREG] |= SREG_Z;
+	  break;
+
+	case OP_ror:
+	  d = get_d (op);
+	  vd = sram[d];
+	  res = vd >> 1 | (sram[SREG] << 7);
+	  sram[d] = res;
+	  sram[SREG] &= ~(SREG_S | SREG_V | SREG_N | SREG_Z | SREG_C);
+	  if (vd & 1)
+	    sram[SREG] |= SREG_C | SREG_S;
+	  if (res & 0x80)
+	    sram[SREG] |= SREG_N;
+          if (!(sram[SREG] & SREG_N) ^ !(sram[SREG] & SREG_C))
+            sram[SREG] |= SREG_V;
+	  if (res == 0)
+	    sram[SREG] |= SREG_Z;
+	  break;
+
+	case OP_mul:
+          gen_mul ((word)sram[get_r (op)] * (word)sram[get_d (op)]);
+	  break;
+
+	case OP_muls:
+	  gen_mul((sword)(sbyte)sram[get_r16 (op)] 
+                  * (sword)(sbyte)sram[get_d16 (op)]);
+	  break;
+
+	case OP_mulsu:
+	  gen_mul ((sword)(word)sram[get_r16_23 (op)] 
+                   * (sword)(sbyte)sram[get_d16_23 (op)]);
+	  break;
+
+	case OP_fmul:
+	  gen_mul(((word)sram[get_r16_23 (op)] 
+                   * (word)sram[get_d16_23 (op)]) << 1);
+	  break;
+
+	case OP_fmuls:
+	  gen_mul(((sword)(sbyte)sram[get_r16_23 (op)] 
+                   * (sword)(sbyte)sram[get_d16_23 (op)]) << 1);
+	  break;
+
+	case OP_fmulsu:
+	  gen_mul(((sword)(word)sram[get_r16_23 (op)] 
+                   * (sword)(sbyte)sram[get_d16_23 (op)]) << 1);
+	  break;
+
+	case OP_adc:
+	case OP_add:
+	  r = sram[get_r (op)];
+	  d = get_d (op);
+	  vd = sram[d];
+	  res = r + vd + (sram[SREG] & flash[ipc].r);
+	  sram[d] = res;
+	  update_flags_add (res, vd, r);
+	  break;
+
+	case OP_sub:
+	  d = get_d (op);
+	  vd = sram[d];
+	  r = sram[get_r (op)];
+	  res = vd - r;
+	  sram[d] = res;
+	  update_flags_sub (res, vd, r);
+	  if (res == 0)
+	    sram[SREG] |= SREG_Z;
+	  break;
+
+	case OP_sbc:
+	  {
+	    byte old = sram[SREG];
+	    d = get_d (op);
+	    vd = sram[d];
+	    r = sram[get_r (op)];
+	    res = vd - r - (old & SREG_C);
+	    sram[d] = res;
+	    update_flags_sub (res, vd, r);
+	    if (res == 0 && (old & SREG_Z))
+	      sram[SREG] |= SREG_Z;
+	  }
+	  break;
+
+	case OP_subi:
+	  d = get_d16 (op);
+	  vd = sram[d];
+	  r = get_K (op);
+	  res = vd - r;
+	  sram[d] = res;
+	  update_flags_sub (res, vd, r);
+	  if (res == 0)
+	    sram[SREG] |= SREG_Z;
+	  break;
+
+	case OP_sbci:
+	  {
+	    byte old = sram[SREG];
+
+	    d = get_d16 (op);
+	    vd = sram[d];
+	    r = get_K (op);
+	    res = vd - r - (old & SREG_C);
+	    sram[d] = res;
+	    update_flags_sub (res, vd, r);
+	    if (res == 0 && (old & SREG_Z))
+	      sram[SREG] |= SREG_Z;
+	  }
+	  break;
+
+	case OP_mov:
+	  sram[get_d (op)] = sram[get_r (op)];
+	  break;
+
+	case OP_movw:
+	  d = (op & 0xf0) >> 3;
+	  r = (op & 0x0f) << 1;
+	  sram[d] = sram[r];
+	  sram[d + 1] = sram[r + 1];
+	  break;
+
+	case OP_out:
+	  d = get_A (op) + 0x20;
+	  res = sram[get_d (op)];
+	  sram[d] = res;
+	  if (d == STDIO_PORT)
+	    putchar (res);
+	  else if (d == EXIT_PORT)
+	    {
+	      cpu_exception = sim_exited;
+	      cpu_signal = 0;
+	      return;
+	    }
+	  else if (d == ABORT_PORT)
+	    {
+	      cpu_exception = sim_exited;
+	      cpu_signal = 1;
+	      return;
+	    }
+	  break;
+
+	case OP_in:
+	  d = get_A (op) + 0x20;
+	  sram[get_d (op)] = sram[d];
+	  break;
+
+        case OP_cbi:
+	  d = get_biA (op) + 0x20;
+          sram[d] &= ~(1 << get_b(op));
+          break;
+
+        case OP_sbi:
+	  d = get_biA (op) + 0x20;
+          sram[d] |= 1 << get_b(op);
+          break;
+
+        case OP_sbic:
+          if (!(sram[get_biA (op) + 0x20] & 1 << get_b(op)))
+            {
+              int l = get_insn_length(pc);
+              pc += l;
+              cycles += l;
+            }
+          break;
+
+        case OP_sbis:
+          if (sram[get_biA (op) + 0x20] & 1 << get_b(op))
+            {
+              int l = get_insn_length(pc);
+              pc += l;
+              cycles += l;
+            }
+          break;
+
+	case OP_ldi:
+	  res = get_K (op);
+	  d = get_d16 (op);
+	  sram[d] = res;
+	  break;
+
+	case OP_lds:
+	  sram[get_d (op)] = sram[flash[pc].op];
+	  pc++;
+	  cycles++;
+	  break;
+
+	case OP_sts:
+	  sram[flash[pc].op] = sram[get_d (op)];
+	  pc++;
+	  cycles++;
+	  break;
+
+	case OP_cpse:
+	  if (sram[get_r (op)] == sram[get_d (op)])
+            {
+              int l = get_insn_length(pc);
+              pc += l;
+              cycles += l;
+            }
+	  break;
+
+	case OP_cp:
+	  r = sram[get_r (op)];
+	  d = sram[get_d (op)];
+	  res = d - r;
+	  update_flags_sub (res, d, r);
+	  if (res == 0)
+	    sram[SREG] |= SREG_Z;
+	  break;
+
+	case OP_cpi:
+	  r = get_K (op);
+	  d = sram[get_d16 (op)];
+	  res = d - r;
+	  update_flags_sub (res, d, r);
+	  if (res == 0)
+	    sram[SREG] |= SREG_Z;
+	  break;
+
+	case OP_cpc:
+	  {
+	    byte old = sram[SREG];
+	    d = sram[get_d (op)];
+	    r = sram[get_r (op)];
+	    res = d - r - (old & SREG_C);
+	    update_flags_sub (res, d, r);
+	    if (res == 0 && (old & SREG_Z))
+	      sram[SREG] |= SREG_Z;
+	  }
+	  break;
+
+	case OP_brbc:
+	  if (!(sram[SREG] & flash[ipc].r))
+	    {
+	      pc = (pc + get_k (op)) & PC_MASK;
+	      cycles++;
+	    }
+	  break;
+
+	case OP_brbs:
+	  if (sram[SREG] & flash[ipc].r)
+	    {
+	      pc = (pc + get_k (op)) & PC_MASK;
+	      cycles++;
+	    }
+	  break;
+
+	case OP_lpm:
+          sram[0] = get_lpm (read_word (REGZ));
+	  cycles += 2;
+	  break;
+
+	case OP_lpm_Z:
+          sram[get_d (op)] = get_lpm (read_word (REGZ));
+	  cycles += 2;
+	  break;
+
+	case OP_lpm_inc_Z:
+          sram[get_d (op)] = get_lpm (read_word_post_inc (REGZ));
+	  cycles += 2;
+	  break;
+
+	case OP_elpm:
+          sram[0] = get_lpm (get_z ());
+	  cycles += 2;
+	  break;
+
+	case OP_elpm_Z:
+          sram[get_d (op)] = get_lpm (get_z ());
+	  cycles += 2;
+	  break;
+
+	case OP_elpm_inc_Z:
+	  {
+	    unsigned int z = get_z ();
+
+	    sram[get_d (op)] = get_lpm (z);
+	    z++;
+	    sram[REGZ_LO] = z;
+	    sram[REGZ_HI] = z >> 8;
+	    sram[RAMPZ] = z >> 16;
+	  }
+	  cycles += 2;
+	  break;
+
+	case OP_ld_Z_inc:
+	  sram[get_d (op)] = sram[read_word_post_inc (REGZ) & SRAM_MASK];
+	  cycles++;
+	  break;
+
+	case OP_ld_dec_Z:
+	  sram[get_d (op)] = sram[read_word_pre_dec (REGZ) & SRAM_MASK];
+	  cycles++;
+	  break;
+
+	case OP_ld_X_inc:
+	  sram[get_d (op)] = sram[read_word_post_inc (REGX) & SRAM_MASK];
+	  cycles++;
+	  break;
+
+	case OP_ld_dec_X:
+	  sram[get_d (op)] = sram[read_word_pre_dec (REGX) & SRAM_MASK];
+	  cycles++;
+	  break;
+
+	case OP_ld_Y_inc:
+	  sram[get_d (op)] = sram[read_word_post_inc (REGY) & SRAM_MASK];
+	  cycles++;
+	  break;
+
+	case OP_ld_dec_Y:
+	  sram[get_d (op)] = sram[read_word_pre_dec (REGY) & SRAM_MASK];
+	  cycles++;
+	  break;
+
+	case OP_st_X:
+	  sram[read_word (REGX) & SRAM_MASK] = sram[get_d (op)];
+	  cycles++;
+	  break;
+
+	case OP_st_X_inc:
+	  sram[read_word_post_inc (REGX) & SRAM_MASK] = sram[get_d (op)];
+	  cycles++;
+	  break;
+
+	case OP_st_dec_X:
+	  sram[read_word_pre_dec (REGX) & SRAM_MASK] = sram[get_d (op)];
+	  cycles++;
+	  break;
+
+	case OP_st_Z_inc:
+	  sram[read_word_post_inc (REGZ) & SRAM_MASK] = sram[get_d (op)];
+	  cycles++;
+	  break;
+
+	case OP_st_dec_Z:
+	  sram[read_word_pre_dec (REGZ) & SRAM_MASK] = sram[get_d (op)];
+	  cycles++;
+	  break;
+
+	case OP_st_Y_inc:
+	  sram[read_word_post_inc (REGY) & SRAM_MASK] = sram[get_d (op)];
+	  cycles++;
+	  break;
+
+	case OP_st_dec_Y:
+	  sram[read_word_pre_dec (REGY) & SRAM_MASK] = sram[get_d (op)];
+	  cycles++;
+	  break;
+
+	case OP_std_Y:
+	  sram[read_word (REGY) + flash[ipc].r] = sram[get_d (op)];
+	  cycles++;
+	  break;
+
+	case OP_std_Z:
+	  sram[read_word (REGZ) + flash[ipc].r] = sram[get_d (op)];
+	  cycles++;
+	  break;
+
+	case OP_ldd_Z:
+	  sram[get_d (op)] = sram[read_word (REGZ) + flash[ipc].r];
+	  cycles++;
+	  break;
+
+	case OP_ldd_Y:
+	  sram[get_d (op)] = sram[read_word (REGY) + flash[ipc].r];
+	  cycles++;
+	  break;
+
+	case OP_ld_X:
+	  sram[get_d (op)] = sram[read_word (REGX) & SRAM_MASK];
+	  cycles++;
+	  break;
+
+	case OP_sbiw:
+	  {
+	    word wk = get_k6 (op);
+	    word wres;
+	    word wr;
+	    
+	    d = get_d24 (op);
+	    wr = read_word (d);
+	    wres = wr - wk;
+
+	    sram[SREG] &= ~(SREG_S | SREG_V | SREG_N | SREG_Z | SREG_C);
+	    if (wres == 0)
+	      sram[SREG] |= SREG_Z;
+	    if (wres & 0x8000)
+	      sram[SREG] |= SREG_N;
+	    if (wres & ~wr & 0x8000)
+	      sram[SREG] |= SREG_C;
+	    if (~wres & wr & 0x8000)
+	      sram[SREG] |= SREG_V;
+	    if (((~wres & wr) ^ wres) & 0x8000)
+	      sram[SREG] |= SREG_S;
+	    write_word (d, wres);
+	  }
+	  cycles++;
+	  break;
+
+	case OP_adiw:
+	  {
+	    word wk = get_k6 (op);
+	    word wres;
+	    word wr;
+	    
+	    d = get_d24 (op);
+	    wr = read_word (d);
+	    wres = wr + wk;
+
+	    sram[SREG] &= ~(SREG_S | SREG_V | SREG_N | SREG_Z | SREG_C);
+	    if (wres == 0)
+	      sram[SREG] |= SREG_Z;
+	    if (wres & 0x8000)
+	      sram[SREG] |= SREG_N;
+	    if (~wres & wr & 0x8000)
+	      sram[SREG] |= SREG_C;
+	    if (wres & ~wr & 0x8000)
+	      sram[SREG] |= SREG_V;
+	    if (((wres & ~wr) ^ wres) & 0x8000)
+	      sram[SREG] |= SREG_S;
+	    write_word (d, wres);
+	  }
+	  cycles++;
+	  break;
+
+	case OP_bad:
+	  sim_cb_eprintf (callback, "Bad instruction at pc=0x%x\n", ipc * 2);
+	  return;
+
+	default:
+	  sim_cb_eprintf (callback,
+                          "Unhandled instruction at pc=0x%x, code=%d\n",
+                          2 * ipc, code);
+	  return;
+	}
+    }
+  while (cpu_exception == sim_running);
+}
+
+
+int
+sim_trace (SIM_DESC sd)
+{
+  tracing = 1;
+  
+  sim_resume (sd, 0, 0);
+
+  tracing = 0;
+  
+  return 1;
+}
+
+int
+sim_write (SIM_DESC sd, SIM_ADDR addr, unsigned char *buffer, int size)
+{
+  int osize = size;
+
+  if (addr >= 0 && addr < SRAM_VADDR)
+    {
+      if (addr & 1)
+	return 0;
+      addr /= 2;
+      while (size > 1 && addr < MAX_AVR_FLASH)
+	{
+	  flash[addr].op = buffer[0] | (buffer[1] << 8);
+	  flash[addr].code = OP_unknown;
+	  addr++;
+	  buffer += 2;
+	  size -= 2;
+	}
+      return osize - size;
+    }
+  else if (addr >= SRAM_VADDR && addr < SRAM_VADDR + MAX_AVR_SRAM)
+    {
+      addr -= SRAM_VADDR;
+      if (addr + size > MAX_AVR_SRAM)
+	size = MAX_AVR_SRAM - addr;
+      memcpy (sram + addr, buffer, size);
+      return size;
+    }
+  else
+    return 0;
+}
+
+int
+sim_read (SIM_DESC sd, SIM_ADDR addr, unsigned char *buffer, int size)
+{
+  int i;
+  int osize = size;
+
+  if (addr >= 0 && addr < SRAM_VADDR)
+    {
+      if (addr & 1)
+	return 0;
+      addr /= 2;
+      while (size > 1 && addr < MAX_AVR_FLASH)
+	{
+	  buffer[0] = flash[addr].op;
+	  buffer[1] = flash[addr].op >> 8;
+	  addr++;
+	  buffer += 2;
+	  size -= 2;
+	}
+      return osize - size;
+    }
+  else if (addr >= SRAM_VADDR && addr < SRAM_VADDR + MAX_AVR_SRAM)
+    {
+      addr -= SRAM_VADDR;
+      if (addr + size > MAX_AVR_SRAM)
+	size = MAX_AVR_SRAM - addr;
+      memcpy (buffer, sram + addr, size);
+      return size;
+    }
+  else
+    {
+      /* Avoid errors.  */
+      memset (buffer, 0, size);
+      return size;
+    }
+}
+
+int
+sim_store_register (SIM_DESC sd, int rn, unsigned char *memory, int length)
+{
+  if (rn < 32 && length == 1)
+    {
+      sram[rn] = *memory;
+      return 1;
+    }
+  if (rn == AVR_SREG_REGNUM && length == 1)
+    {
+      sram[SREG] = *memory;
+      return 1;
+    }
+  if (rn == AVR_SP_REGNUM && length == 2)
+    {
+      sram[REG_SP] = memory[0];
+      sram[REG_SP + 1] = memory[1];
+      return 2;
+    }
+  if (rn == AVR_PC_REGNUM && length == 4)
+    {
+      pc = (memory[0] >> 1) | (memory[1] << 7) 
+	| (memory[2] << 15) | (memory[3] << 23);
+      pc &= PC_MASK;
+      return 4;
+    }
+  return 0;
+}
+
+int
+sim_fetch_register (SIM_DESC sd, int rn, unsigned char *memory, int length)
+{
+  if (rn < 32 && length == 1)
+    {
+      *memory = sram[rn];
+      return 1;
+    }
+  if (rn == AVR_SREG_REGNUM && length == 1)
+    {
+      *memory = sram[SREG];
+      return 1;
+    }
+  if (rn == AVR_SP_REGNUM && length == 2)
+    {
+      memory[0] = sram[REG_SP];
+      memory[1] = sram[REG_SP + 1];
+      return 2;
+    }
+  if (rn == AVR_PC_REGNUM && length == 4)
+    {
+      memory[0] = pc << 1;
+      memory[1] = pc >> 7;
+      memory[2] = pc >> 15;
+      memory[3] = pc >> 23;
+      return 4;
+    }
+  return 0;
+}
+
+void
+sim_stop_reason (SIM_DESC sd, enum sim_stop * reason,  int *sigrc)
+{
+  *reason = cpu_exception;
+  *sigrc = cpu_signal;
+}
+
+int
+sim_stop (SIM_DESC sd)
+{
+  cpu_exception = sim_stopped;
+  cpu_signal = TARGET_SIGNAL_INT;
+  return 0;
+}
+
+void
+sim_info (SIM_DESC sd, int verbose)
+{
+  callback->printf_filtered
+    (callback, "\n\n# cycles  %10u\n", cycles);
+}
+
+SIM_DESC
+sim_open (SIM_OPEN_KIND kind, host_callback *cb, struct bfd *abfd, char **argv)
+{
+  myname = argv[0];
+  callback = cb;
+  
+  cur_bfd = abfd;
+
+  /* Fudge our descriptor for now.  */
+  return (SIM_DESC) 1;
+}
+
+void
+sim_close (SIM_DESC sd, int quitting)
+{
+  /* nothing to do */
+}
+
+SIM_RC
+sim_load (SIM_DESC sd, char *prog, bfd *abfd, int from_tty)
+{
+  bfd *prog_bfd;
+
+  prog_bfd = sim_load_file (sd, myname, callback, prog, abfd,
+                            sim_kind == SIM_OPEN_DEBUG,
+                            0, sim_write);
+  if (prog_bfd == NULL)
+    return SIM_RC_FAIL;
+
+  avr_pc22 = (bfd_get_mach (prog_bfd) >= bfd_mach_avr6);
+
+  if (abfd != NULL)
+    cur_bfd = abfd;
+
+  return SIM_RC_OK;
+}
+
+SIM_RC
+sim_create_inferior (SIM_DESC sd, struct bfd *prog_bfd, char **argv, char **env)
+{
+  /* Set the initial register set.  */
+  pc = 0;
+  
+  return SIM_RC_OK;
+}
+
+void
+sim_kill (SIM_DESC sd)
+{
+  /* nothing to do */
+}
+
+void
+sim_do_command (SIM_DESC sd, char *cmd)
+{
+  /* Nothing there yet; it's all an error.  */
+  
+  if (cmd == NULL)
+    return;
+
+  if (strcmp (cmd, "verbose") == 0)
+    verbose = 2;
+  else if (strcmp (cmd, "trace") == 0)
+    tracing = 1;
+  else
+    sim_cb_eprintf (callback,
+                    "Error: \"%s\" is not a valid avr simulator command.\n",
+                    cmd);
+}
+
+void
+sim_set_callbacks (host_callback *ptr)
+{
+  callback = ptr; 
+}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]