* Makefile.in: Add support for AVR target.
authorTheodore A. Roth <troth@openavr.org>
Thu, 25 Apr 2002 20:34:56 +0000 (20:34 +0000)
committerTheodore A. Roth <troth@openavr.org>
Thu, 25 Apr 2002 20:34:56 +0000 (20:34 +0000)
* configure.tgt: Add support for AVR target.
* avr-tdep.c: New file
* config/avr/avr.mt: New file.

gdb/ChangeLog
gdb/Makefile.in
gdb/avr-tdep.c [new file with mode: 0644]
gdb/config/avr/avr.mt [new file with mode: 0644]
gdb/configure.tgt

index e8f07f9..c2cfae4 100644 (file)
@@ -1,5 +1,12 @@
 2002-04-25  Theodore A. Roth  <troth@verinet.com>
 
+       * Makefile.in: Add support for AVR target.
+       * configure.tgt: Add support for AVR target.
+       * avr-tdep.c: New file
+       * config/avr/avr.mt: New file.
+
+2002-04-25  Theodore A. Roth  <troth@verinet.com>
+
        * MAINTAINERS: Add myself to write-after-approval.
 
 2002-04-24  Pierre Muller  <ics.u-strasbg.fr>
index 2151c32..c87eb17 100644 (file)
@@ -1183,6 +1183,7 @@ ALLDEPFILES = 29k-share/udi/udip2soc.c 29k-share/udi/udr.c \
        alphafbsd-tdep.c \
        arm-linux-nat.c arm-linux-tdep.c arm-tdep.c \
        armnbsd-nat.c armnbsd-tdep.c \
+       avr-tdep.c \
        coff-solib.c \
        core-sol2.c core-regset.c core-aout.c corelow.c \
        dcache.c delta68-nat.c dpx2-nat.c dstread.c exec.c fork-child.c \
@@ -1285,6 +1286,9 @@ armnbsd-nat.o: armnbsd-nat.c $(defs_h) arm-tdep.h $(inferior_h) $(regcache_h) \
 
 armnbsd-tdep.o: armnbsd-tdep.c $(defs_h) arm-tdep.h
 
+avr-tdep.o: avr-tdep.c $(defs_h) $(gdbcmd_h) $(gdbcore_h) $(inferior_h) \
+       $(symfile_h) $(regcache_h) $(arch_utils_h)
+
 bcache.o: bcache.c $(bcache_h) $(defs_h)
 
 blockframe.o: blockframe.c $(defs_h) $(gdbcore_h) $(inferior_h) \
diff --git a/gdb/avr-tdep.c b/gdb/avr-tdep.c
new file mode 100644 (file)
index 0000000..32e8f3e
--- /dev/null
@@ -0,0 +1,1369 @@
+/* Target-dependent code for Atmel AVR, for GDB.
+   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002
+   Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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.  */
+
+/* Contributed by Theodore A. Roth, troth@verinet.com */
+
+/* Portions of this file were taken from the original gdb-4.18 patch developed
+   by Denis Chertykov, denisc@overta.ru */
+
+#include "defs.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "inferior.h"
+#include "symfile.h"
+#include "arch-utils.h"
+#include "regcache.h"
+
+/* AVR Background:
+
+   (AVR micros are pure Harvard Architecture processors.)
+
+   The AVR family of microcontrollers have three distinctly different memory
+   spaces: flash, sram and eeprom. The flash is 16 bits wide and is used for
+   the most part to store program instructions. The sram is 8 bits wide and is
+   used for the stack and the heap. Some devices lack sram and some can have
+   an additional external sram added on as a peripheral.
+
+   The eeprom is 8 bits wide and is used to store data when the device is
+   powered down. Eeprom is not directly accessible, it can only be accessed
+   via io-registers using a special algorithm. Accessing eeprom via gdb's
+   remote serial protocol ('m' or 'M' packets) looks difficult to do and is
+   not included at this time.
+
+   [The eeprom could be read manually via ``x/b <eaddr + AVR_EMEM_START>'' or
+   written using ``set {unsigned char}<eaddr + AVR_EMEM_START>''.  For this to
+   work, the remote target must be able to handle eeprom accesses and perform
+   the address translation.]
+
+   All three memory spaces have physical addresses beginning at 0x0. In
+   addition, the flash is addressed by gcc/binutils/gdb with respect to 8 bit
+   bytes instead of the 16 bit wide words used by the real device for the
+   Program Counter.
+
+   In order for remote targets to work correctly, extra bits must be added to
+   addresses before they are send to the target or received from the target
+   via the remote serial protocol. The extra bits are the MSBs and are used to
+   decode which memory space the address is referring to. */
+
+#undef XMALLOC
+#define XMALLOC(TYPE) ((TYPE*) xmalloc (sizeof (TYPE)))
+
+#undef EXTRACT_INSN
+#define EXTRACT_INSN(addr) extract_unsigned_integer(addr,2)
+
+/* Constants: prefixed with AVR_ to avoid name space clashes */
+
+enum
+  {
+    AVR_REG_W         = 24,
+    AVR_REG_X         = 26,
+    AVR_REG_Y         = 28,
+    AVR_FP_REGNUM     = 28,
+    AVR_REG_Z         = 30,
+                    
+    AVR_SREG_REGNUM   = 32,
+    AVR_SP_REGNUM     = 33,
+    AVR_PC_REGNUM     = 34,
+
+    AVR_NUM_REGS      = 32 + 1 /*SREG*/ + 1 /*SP*/ + 1 /*PC*/,
+    AVR_NUM_REG_BYTES = 32 + 1 /*SREG*/ + 2 /*SP*/ + 4 /*PC*/,
+
+    AVR_PC_REG_INDEX  = 35,       /* index into array of registers */
+
+    AVR_MAX_PROLOGUE_SIZE = 56,   /* bytes */
+
+    /* Count of pushed registers. From r2 to r17 (inclusively), r28, r29 */
+    AVR_MAX_PUSHES    = 18,
+
+    /* Number of the last pushed register. r17 for current avr-gcc */
+    AVR_LAST_PUSHED_REGNUM = 17,
+
+    /* FIXME: TRoth/2002-01-??: Can we shift all these memory masks left 8
+       bits? Do these have to match the bfd vma values?. It sure would make
+       things easier in the future if they didn't need to match.
+
+       Note: I chose these values so as to be consistent with bfd vma
+       addresses.
+
+       TRoth/2002-04-08: There is already a conflict with very large programs
+       in the mega128. The mega128 has 128K instruction bytes (64K words),
+       thus the Most Significant Bit is 0x10000 which gets masked off my
+       AVR_MEM_MASK.
+
+       The problem manifests itself when trying to set a breakpoint in a
+       function which resides in the upper half of the instruction space and
+       thus requires a 17-bit address.
+
+       For now, I've just removed the EEPROM mask and changed AVR_MEM_MASK
+       from 0x00ff0000 to 0x00f00000. Eeprom is not accessible from gdb yet,
+       but could be for some remote targets by just adding the correct offset
+       to the address and letting the remote target handle the low-level
+       details of actually accessing the eeprom. */
+
+    AVR_IMEM_START    = 0x00000000, /* INSN memory */
+    AVR_SMEM_START    = 0x00800000, /* SRAM memory */
+#if 1
+    /* No eeprom mask defined */
+    AVR_MEM_MASK      = 0x00f00000, /* mask to determine memory space */
+#else
+    AVR_EMEM_START    = 0x00810000, /* EEPROM memory */
+    AVR_MEM_MASK      = 0x00ff0000, /* mask to determine memory space */
+#endif
+  };
+
+/* Any function with a frame looks like this
+   .......    <-SP POINTS HERE
+   LOCALS1    <-FP POINTS HERE
+   LOCALS0
+   SAVED FP
+   SAVED R3
+   SAVED R2
+   RET PC
+   FIRST ARG
+   SECOND ARG */
+
+struct frame_extra_info
+  {
+    CORE_ADDR return_pc;
+    CORE_ADDR args_pointer;
+    int locals_size;
+    int framereg;
+    int framesize;
+    int is_main;
+  };
+
+struct gdbarch_tdep
+  {
+    /* FIXME: TRoth: is there anything to put here? */
+    int foo;
+  };
+
+/* Lookup the name of a register given it's number. */
+
+static char *
+avr_register_name (int regnum)
+{
+  static char *register_names[] =
+  {
+    "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
+    "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
+    "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+    "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
+    "SREG", "SP", "PC"
+  };
+  if (regnum < 0)
+    return NULL;
+  if (regnum >= (sizeof (register_names) / sizeof (*register_names)))
+    return NULL;
+  return register_names[regnum];
+}
+
+/* Index within `registers' of the first byte of the space for
+   register REGNUM.  */
+
+static int
+avr_register_byte (int regnum)
+{
+  if (regnum < AVR_PC_REGNUM)
+    return regnum;
+  else
+    return AVR_PC_REG_INDEX;
+}
+
+/* Number of bytes of storage in the actual machine representation for
+   register REGNUM.  */
+
+static int
+avr_register_raw_size (int regnum)
+{
+  switch (regnum)
+    {
+    case AVR_PC_REGNUM:
+      return 4;
+    case AVR_SP_REGNUM:
+    case AVR_FP_REGNUM:
+      return 2;
+    default:
+      return 1;
+    }
+}
+
+/* Number of bytes of storage in the program's representation
+   for register N.  */
+
+static int
+avr_register_virtual_size (int regnum)
+{
+  return TYPE_LENGTH (REGISTER_VIRTUAL_TYPE (regnum));
+}
+
+/* Return the GDB type object for the "standard" data type
+   of data in register N.  */
+
+static struct type *
+avr_register_virtual_type (int regnum)
+{
+  switch (regnum)
+    {
+    case AVR_PC_REGNUM:
+      return builtin_type_unsigned_long;
+    case AVR_SP_REGNUM:
+      return builtin_type_unsigned_short;
+    default:
+      return builtin_type_unsigned_char;
+    }
+}
+
+/* Instruction address checks and convertions. */
+
+static CORE_ADDR
+avr_make_iaddr (CORE_ADDR x)
+{
+  return ((x) | AVR_IMEM_START);
+}
+
+static int
+avr_iaddr_p (CORE_ADDR x)
+{
+  return (((x) & AVR_MEM_MASK) == AVR_IMEM_START);
+}
+
+/* FIXME: TRoth: Really need to use a larger mask for instructions. Some
+   devices are already up to 128KBytes of flash space.
+
+   TRoth/2002-04-8: See comment above where AVR_IMEM_START is defined. */
+
+static CORE_ADDR
+avr_convert_iaddr_to_raw (CORE_ADDR x)
+{
+  return ((x) & 0xffffffff);
+}
+
+/* SRAM address checks and convertions. */
+
+static CORE_ADDR
+avr_make_saddr (CORE_ADDR x)
+{
+  return ((x) | AVR_SMEM_START);
+}
+
+static int
+avr_saddr_p (CORE_ADDR x)
+{
+  return (((x) & AVR_MEM_MASK) == AVR_SMEM_START);
+}
+
+static CORE_ADDR
+avr_convert_saddr_to_raw (CORE_ADDR x)
+{
+  return ((x) & 0xffffffff);
+}
+
+/* EEPROM address checks and convertions. I don't know if these will ever
+   actually be used, but I've added them just the same. TRoth */
+
+/* TRoth/2002-04-08: Commented out for now to allow fix for problem with large
+   programs in the mega128. */
+
+/*  static CORE_ADDR */
+/*  avr_make_eaddr (CORE_ADDR x) */
+/*  { */
+/*    return ((x) | AVR_EMEM_START); */
+/*  } */
+
+/*  static int */
+/*  avr_eaddr_p (CORE_ADDR x) */
+/*  { */
+/*    return (((x) & AVR_MEM_MASK) == AVR_EMEM_START); */
+/*  } */
+
+/*  static CORE_ADDR */
+/*  avr_convert_eaddr_to_raw (CORE_ADDR x) */
+/*  { */
+/*    return ((x) & 0xffffffff); */
+/*  } */
+
+/* Convert from address to pointer and vice-versa. */
+
+static void
+avr_address_to_pointer (struct type *type, void *buf, CORE_ADDR addr)
+{
+  /* Is it a code address?  */
+  if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_FUNC
+      || TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_METHOD)
+    {
+      store_unsigned_integer (buf, TYPE_LENGTH (type), 
+                              avr_convert_iaddr_to_raw (addr));
+    }
+  else
+    {
+      /* Strip off any upper segment bits.  */
+      store_unsigned_integer (buf, TYPE_LENGTH (type), 
+                              avr_convert_saddr_to_raw (addr));
+    }
+}
+
+static CORE_ADDR
+avr_pointer_to_address (struct type *type, void *buf)
+{
+  CORE_ADDR addr = extract_address (buf, TYPE_LENGTH (type));
+
+  if ( TYPE_CODE_SPACE (TYPE_TARGET_TYPE (type)) )
+    {
+      fprintf_unfiltered (gdb_stderr, "CODE_SPACE ---->> ptr->addr: 0x%lx\n", addr);
+      fprintf_unfiltered (gdb_stderr, "+++ If you see this, please send me an email <troth@verinet.com>\n");
+    }
+
+  /* Is it a code address?  */
+  if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_FUNC
+      || TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_METHOD
+      || TYPE_CODE_SPACE (TYPE_TARGET_TYPE (type))
+      )
+    return avr_make_iaddr (addr);
+  else
+    return avr_make_saddr (addr);
+}
+
+static CORE_ADDR
+avr_read_pc (ptid_t ptid)
+{
+  ptid_t save_ptid;
+  CORE_ADDR pc;
+  CORE_ADDR retval;
+
+  save_ptid = inferior_ptid;
+  inferior_ptid = ptid;
+  pc = (int) read_register (AVR_PC_REGNUM);
+  inferior_ptid = save_ptid;
+  retval = avr_make_iaddr (pc);
+  return retval;
+}
+
+static void
+avr_write_pc (CORE_ADDR val, ptid_t ptid)
+{
+  ptid_t save_ptid;
+
+  save_ptid = inferior_ptid;
+  inferior_ptid = ptid;
+  write_register (AVR_PC_REGNUM, avr_convert_iaddr_to_raw (val));
+  inferior_ptid = save_ptid;
+}
+
+static CORE_ADDR
+avr_read_sp (void)
+{
+  return (avr_make_saddr (read_register (AVR_SP_REGNUM)));
+}
+
+static void
+avr_write_sp (CORE_ADDR val)
+{
+  write_register (AVR_SP_REGNUM, avr_convert_saddr_to_raw (val));
+}
+
+static CORE_ADDR
+avr_read_fp (void)
+{
+  return (avr_make_saddr (read_register (AVR_FP_REGNUM)));
+}
+
+/* Translate a GDB virtual ADDR/LEN into a format the remote target
+   understands.  Returns number of bytes that can be transfered
+   starting at TARG_ADDR.  Return ZERO if no bytes can be transfered
+   (segmentation fault).
+
+   TRoth/2002-04-08: Could this be used to check for dereferencing an invalid
+   pointer? */
+
+static void
+avr_remote_translate_xfer_address (CORE_ADDR memaddr, int nr_bytes,
+                                   CORE_ADDR *targ_addr, int *targ_len)
+{
+  long out_addr;
+  long out_len;
+
+  /* FIXME: TRoth: Do nothing for now. Will need to examine memaddr at this
+     point and see if the high bit are set with the masks that we want. */
+
+  *targ_addr = memaddr;
+  *targ_len = nr_bytes;
+}
+
+/* Function pointers obtained from the target are half of what gdb expects so
+   multiply by 2. */
+
+static CORE_ADDR
+avr_convert_from_func_ptr_addr (CORE_ADDR addr)
+{
+  return addr * 2;
+}
+
+/* avr_scan_prologue is also used as the frame_init_saved_regs().
+
+   Put here the code to store, into fi->saved_regs, the addresses of
+   the saved registers of frame described by FRAME_INFO.  This
+   includes special registers such as pc and fp saved in special ways
+   in the stack frame.  sp is even more special: the address we return
+   for it IS the sp for the next frame. */
+
+/* Function: avr_scan_prologue (helper function for avr_init_extra_frame_info)
+   This function decodes a AVR function prologue to determine:
+     1) the size of the stack frame
+     2) which registers are saved on it
+     3) the offsets of saved regs
+   This information is stored in the "extra_info" field of the frame_info.
+
+   A typical AVR function prologue might look like this:
+        push rXX
+        push r28
+        push r29
+        in r28,__SP_L__
+        in r29,__SP_H__
+        sbiw r28,<LOCALS_SIZE>
+        in __tmp_reg__,__SREG__
+        cli
+        out __SP_L__,r28
+        out __SREG__,__tmp_reg__
+        out __SP_H__,r29
+
+  A `-mcall-prologues' prologue look like this:
+        ldi r26,<LOCALS_SIZE>
+        ldi r27,<LOCALS_SIZE>/265
+        ldi r30,pm_lo8(.L_foo_body)
+        ldi r31,pm_hi8(.L_foo_body)
+        rjmp __prologue_saves__+RRR
+  .L_foo_body:  */
+
+static void
+avr_scan_prologue (struct frame_info *fi)
+{
+  CORE_ADDR prologue_start;
+  CORE_ADDR prologue_end;
+  int       i;
+  unsigned  short insn;
+  int       regno;
+  int       scan_stage=0;
+  char      *name;
+  struct minimal_symbol *msymbol;
+  int       prologue_len;
+  unsigned char prologue[AVR_MAX_PROLOGUE_SIZE];
+  int vpc = 0;
+
+  fi->extra_info->framereg = AVR_SP_REGNUM;
+  
+  if (find_pc_partial_function (fi->pc, &name, &prologue_start, &prologue_end))
+    {
+      struct symtab_and_line sal = find_pc_line (prologue_start, 0);
+
+      if (sal.line == 0)                /* no line info, use current PC */
+        prologue_end = fi->pc;
+      else if (sal.end < prologue_end)  /* next line begins after fn end */
+        prologue_end = sal.end;         /* (probably means no prologue)  */
+    }
+  else
+    /* We're in the boondocks: allow for */
+    /* 19 pushes, an add, and "mv fp,sp" */
+    prologue_end = prologue_start + AVR_MAX_PROLOGUE_SIZE; 
+
+  prologue_end = min (prologue_end, fi->pc);
+
+  /* Search the prologue looking for instructions that set up the
+     frame pointer, adjust the stack pointer, and save registers.  */
+
+  fi->extra_info->framesize = 0;
+  prologue_len = prologue_end - prologue_start;
+  read_memory (prologue_start, prologue, prologue_len);
+
+  /* Scanning main()'s prologue
+     ldi r28,lo8(<RAM_ADDR> - <LOCALS_SIZE>)
+     ldi r29,hi8(<RAM_ADDR> - <LOCALS_SIZE>)
+     out __SP_H__,r29
+     out __SP_L__,r28 */
+
+  if (name && strcmp ("main", name) == 0 && prologue_len == 8)
+    {
+      CORE_ADDR locals;
+      unsigned char img[] =
+      {
+        0xde,0xbf,              /* out __SP_H__,r29 */
+        0xcd,0xbf               /* out __SP_L__,r28 */
+      };
+
+      fi->extra_info->framereg = AVR_FP_REGNUM;
+      insn = EXTRACT_INSN (&prologue[vpc]);
+      /* ldi r28,lo8(<RAM_ADDR> - <LOCALS_SIZE>) */
+      if ((insn & 0xf0f0) == 0xe0c0) 
+        {
+          locals = (insn & 0xf) | ((insn & 0x0f00) >> 4);
+          insn = EXTRACT_INSN (&prologue[vpc+2]);
+          /* ldi r29,hi8(<RAM_ADDR> - <LOCALS_SIZE>) */
+          if ((insn & 0xf0f0) == 0xe0d0)  
+            {
+              locals |= ((insn & 0xf) | ((insn & 0x0f00) >> 4)) << 8;
+              if (memcmp (prologue + vpc + 4, img, sizeof (img)) == 0)
+                {
+                  fi->frame = locals;
+
+                  /* TRoth: Does -1 mean we're in main? */
+                  fi->extra_info->is_main = 1;
+                  return;
+                }
+            }
+        }
+    }
+      
+  /* Scanning `-mcall-prologues' prologue
+     FIXME: mega prologue have a 12 bytes long */
+
+  while (prologue_len <= 12)    /* I'm use while to avoit many goto's */
+    {
+      int loc_size;
+      int body_addr;
+      unsigned num_pushes;
+      
+      insn = EXTRACT_INSN (&prologue[vpc]);
+      /* ldi r26,<LOCALS_SIZE> */
+      if ((insn & 0xf0f0) != 0xe0a0) 
+        break;
+      loc_size = (insn & 0xf) | ((insn & 0x0f00) >> 4);
+      
+      insn = EXTRACT_INSN (&prologue[vpc + 2]);
+      /* ldi r27,<LOCALS_SIZE> / 256 */
+      if ((insn & 0xf0f0) != 0xe0b0)
+        break;
+      loc_size |= ((insn & 0xf) | ((insn & 0x0f00) >> 4)) << 8;
+      
+      insn = EXTRACT_INSN (&prologue[vpc + 4]);
+      /* ldi r30,pm_lo8(.L_foo_body) */
+      if ((insn & 0xf0f0) != 0xe0e0)
+        break;
+      body_addr = (insn & 0xf) | ((insn & 0x0f00) >> 4);
+
+      insn = EXTRACT_INSN (&prologue[vpc + 6]);
+      /* ldi r31,pm_hi8(.L_foo_body) */
+      if ((insn & 0xf0f0) != 0xe0f0)
+        break;
+      body_addr |= ((insn & 0xf) | ((insn & 0x0f00) >> 4)) << 8;
+
+      if (body_addr != (prologue_start + 10) / 2)
+        break;
+
+      msymbol = lookup_minimal_symbol ("__prologue_saves__", NULL, NULL);
+      if (!msymbol)
+        break;
+
+      /* FIXME: prologue for mega have a JMP instead of RJMP */
+      insn = EXTRACT_INSN (&prologue[vpc + 8]);
+      /* rjmp __prologue_saves__+RRR */
+      if ((insn & 0xf000) != 0xc000)
+        break;
+      
+      /* Extract PC relative offset from RJMP */
+      i = (insn & 0xfff) | (insn & 0x800 ? (-1 ^ 0xfff) : 0);
+      /* Convert offset to byte addressable mode */
+      i *= 2;
+      /* Destination address */
+      i += vpc + prologue_start + 10;
+      /* Resovle offset (in words) from __prologue_saves__ symbol.
+         Which is a pushes count in `-mcall-prologues' mode */
+      num_pushes = AVR_MAX_PUSHES - (i - SYMBOL_VALUE_ADDRESS (msymbol)) / 2;
+
+      if (num_pushes > AVR_MAX_PUSHES)
+        num_pushes = 0;
+        
+      if (num_pushes)
+        {
+          int from;
+          fi->saved_regs[AVR_FP_REGNUM+1] = num_pushes;
+          if (num_pushes >= 2)
+            fi->saved_regs[AVR_FP_REGNUM] = num_pushes - 1;
+          i = 0;
+          for (from = AVR_LAST_PUSHED_REGNUM + 1 - (num_pushes - 2);
+               from <= AVR_LAST_PUSHED_REGNUM; ++from)
+            fi->saved_regs[from] = ++i;
+        }
+      fi->extra_info->locals_size = loc_size;
+      fi->extra_info->framesize = loc_size + num_pushes;
+      fi->extra_info->framereg = AVR_FP_REGNUM;
+      return;
+    }
+
+  /* Scan interrupt or signal function */
+
+  if (prologue_len >= 12)
+    {
+      unsigned char img[] =
+      {
+        0x78,0x94,              /* sei */
+        0x1f,0x92,              /* push r1 */
+        0x0f,0x92,              /* push r0 */
+        0x0f,0xb6,              /* in r0,0x3f SREG */
+        0x0f,0x92,              /* push r0 */
+        0x11,0x24               /* clr r1 */
+      };
+      if (memcmp (prologue, img, sizeof (img)) == 0)
+        {
+          vpc += sizeof (img);
+          fi->saved_regs[0] = 2;
+          fi->saved_regs[1] = 1;
+          fi->extra_info->framesize += 3;
+        }
+      else if (memcmp (img + 1, prologue, sizeof (img) - 1) == 0)
+        {
+          vpc += sizeof (img) - 1;
+          fi->saved_regs[0] = 2;
+          fi->saved_regs[1] = 1;
+          fi->extra_info->framesize += 3;
+        }
+    }
+
+  /* First stage of the prologue scanning.
+     Scan pushes */
+
+  for (; vpc <= prologue_len; vpc += 2)
+    {
+      insn = EXTRACT_INSN (&prologue[vpc]);
+      if ((insn & 0xfe0f) == 0x920f)            /* push rXX */
+        {
+          /* Bits 4-9 contain a mask for registers R0-R32. */
+          regno = (insn & 0x1f0) >> 4;
+          ++fi->extra_info->framesize;
+          fi->saved_regs[regno] = fi->extra_info->framesize;
+          scan_stage = 1;
+        }
+      else
+        break;
+    }
+
+  /* Second stage of the prologue scanning.
+     Scan:
+     in r28,__SP_L__
+     in r29,__SP_H__ */
+
+  if (scan_stage == 1 && vpc + 4 <= prologue_len)
+    {
+      unsigned char img[] =
+      {
+        0xcd,0xb7,              /* in r28,__SP_L__ */
+        0xde,0xb7               /* in r29,__SP_H__ */
+      };
+      unsigned short insn1;
+      
+      if (memcmp (prologue + vpc, img, sizeof (img)) == 0)
+        {
+          vpc += 4;
+          fi->extra_info->framereg = AVR_FP_REGNUM;
+          scan_stage = 2;
+        }
+    }
+
+  /* Third stage of the prologue scanning. (Really two stages)
+     Scan for:
+     sbiw r28,XX or subi r28,lo8(XX)
+     sbci r29,hi8(XX)
+     in __tmp_reg__,__SREG__
+     cli
+     out __SP_L__,r28
+     out __SREG__,__tmp_reg__
+     out __SP_H__,r29 */
+
+  if (scan_stage == 2 && vpc + 12 <= prologue_len)
+    {
+      int locals_size = 0;
+      unsigned char img[] =
+      {
+        0x0f,0xb6,              /* in r0,0x3f */
+        0xf8,0x94,              /* cli */
+        0xcd,0xbf,              /* out 0x3d,r28 ; SPL */
+        0x0f,0xbe,              /* out 0x3f,r0  ; SREG*/
+        0xde,0xbf               /* out 0x3e,r29 ; SPH */
+      };
+      unsigned char img_sig[] =
+      {
+        0xcd,0xbf,              /* out 0x3d,r28 ; SPL */
+        0xde,0xbf               /* out 0x3e,r29 ; SPH */
+      };
+      unsigned char img_int[] =
+      {
+        0xf8,0x94,              /* cli */
+        0xcd,0xbf,              /* out 0x3d,r28 ; SPL */
+        0x78,0x94,              /* sei */
+        0xde,0xbf               /* out 0x3e,r29 ; SPH */
+      };
+        
+      insn = EXTRACT_INSN (&prologue[vpc]);
+      vpc += 2;
+      if ((insn & 0xff30) == 0x9720) /* sbiw r28,XXX */
+        locals_size = (insn & 0xf) | ((insn & 0xc0) >> 2);
+      else if ((insn & 0xf0f0) == 0x50c0) /* subi r28,lo8(XX) */
+        {
+          locals_size = (insn & 0xf) | ((insn & 0xf00) >> 4);
+          insn = EXTRACT_INSN (&prologue[vpc]);
+          vpc += 2;
+          locals_size += ((insn & 0xf) | ((insn & 0xf00) >> 4) << 8);
+        }
+      else
+        return;
+      fi->extra_info->locals_size = locals_size;
+      fi->extra_info->framesize += locals_size;
+    }
+}
+
+/* This function actually figures out the frame address for a given pc and
+   sp.  This is tricky  because we sometimes don't use an explicit
+   frame pointer, and the previous stack pointer isn't necessarily recorded
+   on the stack.  The only reliable way to get this info is to
+   examine the prologue.  */
+
+static void
+avr_init_extra_frame_info (int fromleaf, struct frame_info *fi)
+{
+  int reg;
+
+  if (fi->next)
+    fi->pc = FRAME_SAVED_PC (fi->next);
+
+  fi->extra_info = (struct frame_extra_info *)
+    frame_obstack_alloc (sizeof (struct frame_extra_info));
+  frame_saved_regs_zalloc (fi);
+
+  fi->extra_info->return_pc = 0;
+  fi->extra_info->args_pointer = 0;
+  fi->extra_info->locals_size = 0;
+  fi->extra_info->framereg = 0;
+  fi->extra_info->framesize = 0;
+  fi->extra_info->is_main = 0;
+  
+  avr_scan_prologue (fi);
+
+  if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
+    {
+      /* We need to setup fi->frame here because run_stack_dummy gets it wrong
+         by assuming it's always FP.  */
+      fi->frame = generic_read_register_dummy (fi->pc, fi->frame,
+                                               fi->frame);
+    }
+  else if (!fi->next)                   /* this is the innermost frame? */
+    fi->frame = read_register (fi->extra_info->framereg);
+  else if (fi->extra_info->is_main != 1) /* not the innermost frame, not `main' */
+    /* If we have an next frame,  the callee saved it. */
+    {
+      struct frame_info * next_fi = fi->next;
+      if (fi->extra_info->framereg == AVR_SP_REGNUM)
+        fi->frame = next_fi->frame + 2 /* ret addr */ + next_fi->extra_info->framesize;
+      /* FIXME: I don't analyse va_args functions  */
+      else
+        {
+          CORE_ADDR fp = 0;
+          CORE_ADDR fp1 = 0;
+          unsigned int fp_low, fp_high;
+
+          /* Scan all frames */
+          for (; next_fi; next_fi = next_fi->next)
+            {
+              /* look for saved AVR_FP_REGNUM */
+              if (next_fi->saved_regs[AVR_FP_REGNUM] && !fp)
+                fp = next_fi->saved_regs[AVR_FP_REGNUM];
+              /* look for saved AVR_FP_REGNUM + 1 */
+              if (next_fi->saved_regs[AVR_FP_REGNUM + 1] && !fp1)
+                fp1 = next_fi->saved_regs[AVR_FP_REGNUM + 1];
+            }
+          fp_low = (fp ? read_memory_unsigned_integer (avr_make_saddr (fp), 1)
+                    : read_register (AVR_FP_REGNUM)) & 0xff;
+          fp_high = (fp1 ? read_memory_unsigned_integer (avr_make_saddr (fp1), 1)
+                    : read_register (AVR_FP_REGNUM + 1)) & 0xff;
+          fi->frame = fp_low | (fp_high << 8);
+        }
+    }
+
+  /* TRoth: Do we want to do this if we are in main? I don't think we should
+     since return_pc makes no sense when we are in main. */
+
+  if ((fi->pc) && (fi->extra_info->is_main == 0)) /* We are not in CALL_DUMMY */
+    {
+      CORE_ADDR addr;
+      int i;
+    
+      addr = fi->frame + fi->extra_info->framesize + 1;
+      
+      /* Return address in stack in different endianness */
+
+      fi->extra_info->return_pc =
+          read_memory_unsigned_integer (avr_make_saddr (addr), 1) << 8;
+      fi->extra_info->return_pc |=
+          read_memory_unsigned_integer (avr_make_saddr (addr + 1), 1);
+    
+      /* This return address in words,
+         must be converted to the bytes address */
+      fi->extra_info->return_pc *= 2;
+
+      /* Resolve a pushed registers addresses */
+      for (i = 0; i < NUM_REGS; i++)
+        {
+          if (fi->saved_regs[i])
+            fi->saved_regs[i] = addr - fi->saved_regs[i];
+        }
+    }
+}
+
+/* Restore the machine to the state it had before the current frame was
+   created.  Usually used either by the "RETURN" command, or by
+   call_function_by_hand after the dummy_frame is finished. */
+
+static void
+avr_pop_frame (void)
+{
+  unsigned regnum;
+  CORE_ADDR saddr;
+  struct frame_info *frame = get_current_frame ();
+
+  if (PC_IN_CALL_DUMMY(frame->pc, frame->frame, frame->frame))
+    {
+      generic_pop_dummy_frame();
+    }
+  else
+    {
+      /* TRoth: Why only loop over 8 registers? */
+
+      for (regnum = 0; regnum < 8; regnum++)
+        {
+          /* Don't forget AVR_SP_REGNUM in a frame_saved_regs struct is the
+             actual value we want, not the address of the value we want.  */
+          if (frame->saved_regs[regnum] && regnum != AVR_SP_REGNUM)
+            {
+              saddr = avr_make_saddr (frame->saved_regs[regnum]);
+              write_register (regnum, read_memory_unsigned_integer (saddr, 1));
+            }
+          else if (frame->saved_regs[regnum] && regnum == AVR_SP_REGNUM)
+            write_register (regnum, frame->frame + 2);
+        }
+
+      /* Don't forget the update the PC too!  */
+      write_pc (frame->extra_info->return_pc);
+    }
+  flush_cached_frames ();
+}
+
+/* Return the saved PC from this frame. */
+
+static CORE_ADDR
+avr_frame_saved_pc (struct frame_info *frame)
+{
+  if (PC_IN_CALL_DUMMY(frame->pc, frame->frame, frame->frame))
+    return generic_read_register_dummy (frame->pc, frame->frame, AVR_PC_REGNUM);
+  else
+    return frame->extra_info->return_pc;
+}
+
+static CORE_ADDR
+avr_saved_pc_after_call (struct frame_info *frame)
+{
+  unsigned char m1, m2;
+  unsigned int sp = read_register (AVR_SP_REGNUM);
+  m1 = read_memory_unsigned_integer (avr_make_saddr (sp + 1), 1);
+  m2 = read_memory_unsigned_integer (avr_make_saddr (sp + 2), 1);
+  return (m2 | (m1 << 8)) * 2;
+}
+
+/* Figure out where in REGBUF the called function has left its return value.
+   Copy that into VALBUF. */
+
+static void
+avr_extract_return_value (struct type *type, char *regbuf, char *valbuf)
+{
+  int wordsize, len;
+
+  wordsize = 2;
+
+  len = TYPE_LENGTH(type);
+
+  switch (len) {
+  case 1:       /* (char) */
+  case 2:       /* (short), (int) */
+    memcpy (valbuf,   regbuf + REGISTER_BYTE(24), 2);
+    break;
+  case 4:       /* (long), (float) */
+    memcpy (valbuf,   regbuf + REGISTER_BYTE(22), 4);
+    break;
+  case 8:       /* (double) (doesn't seem to happen, which is good,
+                   because this almost certainly isn't right.  */
+    error ("I don't know how a double is returned.");
+    break;
+  }
+}
+
+/* Returns the return address for a dummy. */
+
+static CORE_ADDR
+avr_call_dummy_address (void)
+{
+  return entry_point_address ();
+}
+
+/* Place the appropriate value in the appropriate registers.
+   Primarily used by the RETURN command.  */
+
+static void
+avr_store_return_value (struct type *type, char *valbuf)
+{
+  int wordsize, len, regval;
+  
+  wordsize = 2;
+
+  len = TYPE_LENGTH(type);
+  switch (len) {
+  case 1:       /* char */
+  case 2:       /* short, int */
+    regval = extract_address(valbuf, len);
+    write_register (0, regval);
+    break;
+  case 4:       /* long, float */
+    regval = extract_address(valbuf, len);
+    write_register (0, regval >> 16);
+    write_register (1, regval & 0xffff);
+    break;
+  case 8:       /* presumeably double, but doesn't seem to happen */
+    error ("I don't know how to return a double.");
+    break;
+  }
+}
+
+/* Setup the return address for a dummy frame, as called by
+   call_function_by_hand.  Only necessary when you are using an empty
+   CALL_DUMMY. */
+
+static CORE_ADDR
+avr_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
+{
+  unsigned char buf[2];
+  int wordsize = 2;
+  struct minimal_symbol *msymbol;
+  CORE_ADDR mon_brk;
+
+  fprintf_unfiltered (gdb_stderr, "avr_push_return_address() was called\n");
+
+  buf[0] = 0;
+  buf[1] = 0;
+  sp -= wordsize;
+  write_memory (sp + 1, buf, 2);
+
+#if 0
+  /* FIXME: TRoth/2002-02-18: This should probably be removed since it's a
+     left-over from Denis' original patch which used avr-mon for the target
+     instead of the generic remote target. */
+  if ((strcmp (target_shortname, "avr-mon") == 0)
+      && (msymbol = lookup_minimal_symbol ("gdb_break", NULL, NULL)))
+    {
+      mon_brk = SYMBOL_VALUE_ADDRESS (msymbol);
+      store_unsigned_integer (buf, wordsize, mon_brk / 2);
+      sp -= wordsize;
+      write_memory (sp + 1, buf + 1, 1);
+      write_memory (sp + 2, buf, 1);
+    }
+#endif
+  return sp;
+}
+
+static CORE_ADDR
+avr_skip_prologue (CORE_ADDR pc)
+{
+  CORE_ADDR func_addr, func_end;
+  struct symtab_and_line sal;
+
+  /* See what the symbol table says */
+
+  if (find_pc_partial_function (pc, NULL, &func_addr, &func_end))
+    {
+      sal = find_pc_line (func_addr, 0);
+
+      if (sal.line != 0 && sal.end < func_end) 
+        return sal.end;
+    }
+
+/* Either we didn't find the start of this function (nothing we can do),
+   or there's no line info, or the line after the prologue is after
+   the end of the function (there probably isn't a prologue). */
+
+  return pc;
+}
+
+static CORE_ADDR
+avr_frame_address (struct frame_info *fi)
+{
+  return avr_make_saddr (fi->frame);
+}
+
+/* Given a GDB frame, determine the address of the calling function's frame.
+   This will be used to create a new GDB frame struct, and then
+   INIT_EXTRA_FRAME_INFO and INIT_FRAME_PC will be called for the new frame.
+
+   For us, the frame address is its stack pointer value, so we look up
+   the function prologue to determine the caller's sp value, and return it.  */
+
+static CORE_ADDR
+avr_frame_chain (struct frame_info *frame)
+{
+  if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame))
+    {
+      /* initialize the return_pc now */
+      frame->extra_info->return_pc = generic_read_register_dummy (frame->pc,
+                                                                  frame->frame, 
+                                                                  AVR_PC_REGNUM);
+      return frame->frame;
+    }
+  return (frame->extra_info->is_main ? 0
+          : frame->frame + frame->extra_info->framesize + 2 /* ret addr */);
+}
+
+/* Store the address of the place in which to copy the structure the
+   subroutine will return.  This is called from call_function. 
+
+   We store structs through a pointer passed in the first Argument
+   register. */
+
+static void
+avr_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
+{
+  write_register (0, addr);
+}
+
+/* Extract from an array REGBUF containing the (raw) register state
+   the address in which a function should return its structure value,
+   as a CORE_ADDR (or an expression that can be used as one). */
+
+static CORE_ADDR
+avr_extract_struct_value_address (char *regbuf)
+{
+  return (extract_address ((regbuf) + REGISTER_BYTE (0),
+                           REGISTER_RAW_SIZE (0))
+          | AVR_SMEM_START);
+}
+
+/* Setup the function arguments for calling a function in the inferior.
+
+   On the AVR architecture, there are 18 registers (R25 to R8) which are
+   dedicated for passing function arguments.  Up to the first 18 arguments
+   (depending on size) may go into these registers.  The rest go on the stack.
+
+   Arguments that are larger than WORDSIZE bytes will be split between two or
+   more registers as available, but will NOT be split between a register and
+   the stack.
+
+   An exceptional case exists for struct arguments (and possibly other
+   aggregates such as arrays) -- if the size is larger than WORDSIZE bytes but
+   not a multiple of WORDSIZE bytes.  In this case the argument is never split
+   between the registers and the stack, but instead is copied in its entirety
+   onto the stack, AND also copied into as many registers as there is room
+   for.  In other words, space in registers permitting, two copies of the same
+   argument are passed in.  As far as I can tell, only the one on the stack is
+   used, although that may be a function of the level of compiler
+   optimization.  I suspect this is a compiler bug.  Arguments of these odd
+   sizes are left-justified within the word (as opposed to arguments smaller
+   than WORDSIZE bytes, which are right-justified).
+   If the function is to return an aggregate type such as a struct, the caller
+   must allocate space into which the callee will copy the return value.  In
+   this case, a pointer to the return value location is passed into the callee
+   in register R0, which displaces one of the other arguments passed in via
+   registers R0 to R2. */
+
+static CORE_ADDR
+avr_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
+                    int struct_return, CORE_ADDR struct_addr)
+{
+  int stack_alloc, stack_offset;
+  int wordsize;
+  int argreg;
+  int argnum;
+  struct type *type;
+  CORE_ADDR regval;
+  char *val;
+  char valbuf[4];
+  int len;
+
+  wordsize    = 1;
+#if 0
+  /* Now make sure there's space on the stack */
+  for (argnum = 0, stack_alloc = 0; 
+       argnum < nargs; argnum++)
+    stack_alloc += TYPE_LENGTH(VALUE_TYPE(args[argnum]));
+  sp -= stack_alloc;    /* make room on stack for args */
+  /* we may over-allocate a little here, but that won't hurt anything */
+#endif
+  argreg = 25;
+  if (struct_return)    /* "struct return" pointer takes up one argreg */
+    {
+      write_register (--argreg, struct_addr);
+    }
+
+  /* Now load as many as possible of the first arguments into registers, and
+     push the rest onto the stack.  There are 3N bytes in three registers
+     available.  Loop thru args from first to last.  */
+
+  for (argnum = 0, stack_offset = 0; argnum < nargs; argnum++)
+    {
+      type = VALUE_TYPE (args[argnum]);
+      len = TYPE_LENGTH (type);
+      val = (char *) VALUE_CONTENTS (args[argnum]);
+
+      /* NOTE WELL!!!!!  This is not an "else if" clause!!!  That's because
+         some *&^%$ things get passed on the stack AND in the registers!  */
+      while (len > 0)
+        { /* there's room in registers */
+          len -= wordsize;
+          regval = extract_address (val + len, wordsize);
+          write_register (argreg--, regval);
+        }
+    }
+  return sp;
+}
+
+/* Initialize the gdbarch structure for the AVR's. */
+
+static struct gdbarch *
+avr_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches){
+  /* FIXME: TRoth/2002-02-18: I have no idea if avr_call_dummy_words[] should
+     be bigger or not. Initial testing seems to show that `call my_func()`
+     works and backtrace from a breakpoint within the call looks correct.
+     Admittedly, I haven't tested with more than a very simple program. */
+  static LONGEST avr_call_dummy_words[] = {0};
+
+  struct gdbarch                   *gdbarch;
+  struct gdbarch_tdep              *tdep;
+
+  /* Find a candidate among the list of pre-declared architectures. */
+  arches = gdbarch_list_lookup_by_info (arches, &info);
+  if (arches != NULL)
+    return arches->gdbarch;
+
+  /* None found, create a new architecture from the information provided. */
+  tdep = XMALLOC (struct gdbarch_tdep);
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  /* If we ever need to differentiate the device types, do it here. */
+  switch (info.bfd_arch_info->mach)
+    {
+    case bfd_mach_avr1:
+    case bfd_mach_avr2:
+    case bfd_mach_avr3:
+    case bfd_mach_avr4:
+    case bfd_mach_avr5:
+      break;
+    }
+
+  set_gdbarch_short_bit (gdbarch, 2 * TARGET_CHAR_BIT);
+  set_gdbarch_int_bit (gdbarch, 2 * TARGET_CHAR_BIT);
+  set_gdbarch_long_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+  set_gdbarch_long_long_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+  set_gdbarch_ptr_bit (gdbarch, 2 * TARGET_CHAR_BIT);
+  set_gdbarch_addr_bit (gdbarch, 32);
+  set_gdbarch_bfd_vma_bit (gdbarch, 32); /* FIXME: TRoth/2002-02-18: Is this needed? */
+
+  set_gdbarch_float_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+  set_gdbarch_double_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+  set_gdbarch_long_double_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+
+  set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_little);
+  set_gdbarch_double_format (gdbarch, &floatformat_ieee_single_little);
+  set_gdbarch_long_double_format (gdbarch, &floatformat_ieee_single_little);
+
+  set_gdbarch_read_pc (gdbarch, avr_read_pc);
+  set_gdbarch_write_pc (gdbarch, avr_write_pc);
+  set_gdbarch_read_fp (gdbarch, avr_read_fp);
+  set_gdbarch_read_sp (gdbarch, avr_read_sp);
+  set_gdbarch_write_sp (gdbarch, avr_write_sp);
+
+  set_gdbarch_num_regs (gdbarch, AVR_NUM_REGS);
+
+  set_gdbarch_sp_regnum (gdbarch, AVR_SP_REGNUM);
+  set_gdbarch_fp_regnum (gdbarch, AVR_FP_REGNUM);
+  set_gdbarch_pc_regnum (gdbarch, AVR_PC_REGNUM);
+
+  set_gdbarch_register_name (gdbarch, avr_register_name);
+  set_gdbarch_register_size (gdbarch, 1);
+  set_gdbarch_register_bytes (gdbarch, AVR_NUM_REG_BYTES);
+  set_gdbarch_register_byte (gdbarch, avr_register_byte);
+  set_gdbarch_register_raw_size (gdbarch, avr_register_raw_size);
+  set_gdbarch_max_register_raw_size (gdbarch, 4);
+  set_gdbarch_register_virtual_size (gdbarch, avr_register_virtual_size);
+  set_gdbarch_max_register_virtual_size (gdbarch, 4);
+  set_gdbarch_register_virtual_type (gdbarch, avr_register_virtual_type);
+
+  /* We might need to define our own here or define FRAME_INIT_SAVED_REGS */
+  set_gdbarch_get_saved_register (gdbarch, generic_get_saved_register);
+
+  set_gdbarch_print_insn (gdbarch, print_insn_avr);
+
+  set_gdbarch_use_generic_dummy_frames (gdbarch, 1);
+  set_gdbarch_call_dummy_location (gdbarch, AT_ENTRY_POINT);
+  set_gdbarch_call_dummy_address (gdbarch, avr_call_dummy_address);
+  set_gdbarch_call_dummy_start_offset (gdbarch, 0);
+  set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1);
+  set_gdbarch_call_dummy_breakpoint_offset (gdbarch, 0);
+  set_gdbarch_call_dummy_length (gdbarch, 0);
+  set_gdbarch_pc_in_call_dummy (gdbarch, generic_pc_in_call_dummy);
+  set_gdbarch_call_dummy_p (gdbarch, 1);
+  set_gdbarch_call_dummy_words (gdbarch, avr_call_dummy_words);
+  set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0);
+  set_gdbarch_fix_call_dummy (gdbarch, generic_fix_call_dummy);
+
+/*    set_gdbarch_believe_pcc_promotion (gdbarch, 1); // TRoth: should this be set? */
+
+  set_gdbarch_address_to_pointer (gdbarch, avr_address_to_pointer);
+  set_gdbarch_pointer_to_address (gdbarch, avr_pointer_to_address);
+  set_gdbarch_extract_return_value (gdbarch, avr_extract_return_value);
+  set_gdbarch_push_arguments (gdbarch, avr_push_arguments);
+  set_gdbarch_push_dummy_frame (gdbarch, generic_push_dummy_frame);
+/*    set_gdbarch_push_return_address (gdbarch, avr_push_return_address); */
+  set_gdbarch_pop_frame (gdbarch, avr_pop_frame);
+
+  set_gdbarch_store_return_value (gdbarch, avr_store_return_value);
+
+  set_gdbarch_use_struct_convention (gdbarch, generic_use_struct_convention);
+  set_gdbarch_store_struct_return (gdbarch, avr_store_struct_return);
+  set_gdbarch_extract_struct_value_address (gdbarch, avr_extract_struct_value_address);
+
+  set_gdbarch_frame_init_saved_regs (gdbarch, avr_scan_prologue);
+  set_gdbarch_init_extra_frame_info (gdbarch, avr_init_extra_frame_info);
+  set_gdbarch_skip_prologue (gdbarch, avr_skip_prologue);
+/*    set_gdbarch_prologue_frameless_p (gdbarch, avr_prologue_frameless_p); */
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+
+  set_gdbarch_decr_pc_after_break (gdbarch, 0);
+
+  set_gdbarch_function_start_offset (gdbarch, 0);
+  set_gdbarch_remote_translate_xfer_address (gdbarch, avr_remote_translate_xfer_address);
+  set_gdbarch_frame_args_skip (gdbarch, 0);
+  set_gdbarch_frameless_function_invocation (gdbarch, frameless_look_for_prologue); /* ??? */
+  set_gdbarch_frame_chain (gdbarch, avr_frame_chain);
+  set_gdbarch_frame_chain_valid (gdbarch, generic_func_frame_chain_valid);
+  set_gdbarch_frame_saved_pc (gdbarch, avr_frame_saved_pc);
+  set_gdbarch_frame_args_address (gdbarch, avr_frame_address);
+  set_gdbarch_frame_locals_address (gdbarch, avr_frame_address);
+  set_gdbarch_saved_pc_after_call (gdbarch, avr_saved_pc_after_call);
+  set_gdbarch_frame_num_args (gdbarch, frame_num_args_unknown);
+
+  set_gdbarch_convert_from_func_ptr_addr (gdbarch, avr_convert_from_func_ptr_addr);
+
+  return gdbarch;
+}
+
+/* Send a query request to the avr remote target asking for values of the io
+   registers. If args parameter is not NULL, then the user has requested info
+   on a specific io register [This still needs implemented and is ignored for
+   now]. The query string should be one of these forms:
+
+   "Ravr.io_reg" -> reply is "NN" number of io registers
+
+   "Ravr.io_reg:addr,len" where addr is first register and len is number of
+   registers to be read. The reply should be "<NAME>,VV;" for each io register
+   where, <NAME> is a string, and VV is the hex value of the register.
+
+   All io registers are 8-bit. */
+
+static void
+avr_io_reg_read_command (char *args, int from_tty)
+{
+  int           bufsiz = 0;
+  char          buf[400];
+  char          query[400];
+  char         *p;
+  unsigned int  nreg = 0;
+  unsigned int  val;
+  int           i, j, k, step;
+
+/*    fprintf_unfiltered (gdb_stderr, "DEBUG: avr_io_reg_read_command (\"%s\", %d)\n", */
+/*             args, from_tty); */
+
+  if (! current_target.to_query)
+    {
+      fprintf_unfiltered (gdb_stderr, "ERR: info io_registers NOT supported by current target\n");
+      return;
+    }
+
+  /* Just get the maximum buffer size. */
+  target_query ((int) 'R', 0, 0, &bufsiz);
+  if (bufsiz > sizeof(buf))
+    bufsiz = sizeof(buf);
+
+  /* Find out how many io registers the target has. */
+  strcpy (query, "avr.io_reg");
+  target_query( (int) 'R', query, buf, &bufsiz );
+
+  if (strncmp (buf, "", bufsiz) == 0)
+    {
+      fprintf_unfiltered (gdb_stderr, "info io_registers NOT supported by target\n");
+      return;
+    }
+
+  if ( sscanf (buf, "%x", &nreg) != 1 )
+    {
+      fprintf_unfiltered (gdb_stderr, "Error fetching number of io registers\n");
+      return;
+    }
+
+  reinitialize_more_filter();
+
+  printf_unfiltered ("Target has %u io registers:\n\n", nreg);
+
+  /* only fetch up to 8 registers at a time to keep the buffer small */
+  step = 8;
+
+  for (i=0; i<nreg; i+=step)
+    {
+      j = step - (nreg % step);     /* how many registers this round? */
+
+      snprintf (query, sizeof(query)-1, "avr.io_reg:%x,%x", i, j);
+      target_query ((int) 'R', query, buf, &bufsiz);
+
+      p = buf;
+      for (k=i; k<(i+j); k++)
+        {
+          if (sscanf (p, "%[^,],%x;", query, &val) == 2)
+            {
+              printf_filtered ("[%02x] %-15s : %02x\n", k, query, val);
+              while ((*p != ';') && (*p != '\0'))
+                p++;
+              p++; /* skip over ';' */
+              if (*p == '\0')
+                break;
+            }
+        }
+    }
+}
+
+void
+_initialize_avr_tdep (void)
+{
+  register_gdbarch_init (bfd_arch_avr, avr_gdbarch_init);
+
+  /* Add a new command to allow the user to query the avr remote target for
+     the values of the io space registers in a saner way than just using
+     `x/NNNb ADDR`. */
+
+  /* FIXME: TRoth/2002-02-18: This should probably be changed to 'info avr
+     io_registers' to signify it is not available on other platforms. */
+
+  add_cmd ("io_registers", class_info, avr_io_reg_read_command,
+           "query remote avr target for io space register values",
+           &infolist);
+}
diff --git a/gdb/config/avr/avr.mt b/gdb/config/avr/avr.mt
new file mode 100644 (file)
index 0000000..0354a42
--- /dev/null
@@ -0,0 +1,12 @@
+# Target: AVR
+TDEPFILES= avr-tdep.o
+
+#
+# There is no simulator provided with gdb (yet).
+#
+# See <http://savannah.gnu.org/projects/simulavr/> for the simulator
+# used during development of avr support for gdb.
+#
+# Simulator: AVR
+#SIM_OBS = remote-sim.o
+#SIM = ../sim/avr/libsim.a
index 64fdb4a..07c8465 100644 (file)
@@ -14,6 +14,7 @@ case "${target_cpu}" in
 
 alpha*)                        gdb_target_cpu=alpha ;;
 arm*)                  gdb_target_cpu=arm ;;
+avr*)                  gdb_target_cpu=avr ;;
 hppa*)                 gdb_target_cpu=pa ;;
 i[3456]86*)            gdb_target_cpu=i386 ;;
 m68hc11*|m6811*)       gdb_target_cpu=m68hc11 ;;
@@ -66,6 +67,10 @@ xscale-*-*)          gdb_target=embed
                         configdirs="$configdirs rdi-share"
                         ;;
 
+avr-*-*)               gdb_target=avr
+                       gdb_multi_arch=yes
+                       ;;
+
 cris*)                  gdb_target=cris ;;
 
 d10v-*-*)              gdb_target=d10v ;;