aboutsummaryrefslogtreecommitdiff
path: root/gdb/z80-tdep.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/z80-tdep.c')
-rw-r--r--gdb/z80-tdep.c1461
1 files changed, 1461 insertions, 0 deletions
diff --git a/gdb/z80-tdep.c b/gdb/z80-tdep.c
new file mode 100644
index 0000000..7b9a7e2
--- /dev/null
+++ b/gdb/z80-tdep.c
@@ -0,0 +1,1461 @@
+/* Target-dependent code for the Z80.
+
+ Copyright (C) 1986-2021 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 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 "defs.h"
+#include "arch-utils.h"
+#include "dis-asm.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "trad-frame.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "gdbtypes.h"
+#include "inferior.h"
+#include "objfiles.h"
+#include "symfile.h"
+
+#include "z80-tdep.h"
+#include "features/z80.c"
+
+/* You need to define __gdb_break_handler symbol pointing to the breakpoint
+ handler. The value of the symbol will be used to determine the instruction
+ for software breakpoint. If __gdb_break_handler points to one of standard
+ RST addresses (0x00, 0x08, 0x10,... 0x38) then RST __gdb_break_handler
+ instruction will be used, else CALL __gdb_break_handler
+
+;breakpoint handler
+ .globl __gdb_break_handler
+ .org 8
+__gdb_break_handler:
+ jp _debug_swbreak
+
+*/
+
+/* Meaning of terms "previous" and "next":
+ previous frame - frame of callee, which is called by current function
+ current frame - frame of current function which has called callee
+ next frame - frame of caller, which has called current function
+*/
+
+struct gdbarch_tdep
+{
+ /* Number of bytes used for address:
+ 2 bytes for all Z80 family
+ 3 bytes for eZ80 CPUs operating in ADL mode */
+ int addr_length;
+
+ /* Type for void. */
+ struct type *void_type;
+ /* Type for a function returning void. */
+ struct type *func_void_type;
+ /* Type for a pointer to a function. Used for the type of PC. */
+ struct type *pc_type;
+};
+
+/* At any time stack frame contains following parts:
+ [<current PC>]
+ [<temporaries, y bytes>]
+ [<local variables, x bytes>
+ <next frame FP>]
+ [<saved state (critical or interrupt functions), 2 or 10 bytes>]
+ In simplest case <next PC> is pointer to the call instruction
+ (or call __call_hl). There are more difficult cases: interrupt handler or
+ push/ret and jp; but they are untrackable.
+*/
+
+struct z80_unwind_cache
+{
+ /* The previous frame's inner most stack address (SP after call executed),
+ it is current frame's frame_id. */
+ CORE_ADDR prev_sp;
+
+ /* Size of the frame, prev_sp + size = next_frame.prev_sp */
+ ULONGEST size;
+
+ /* size of saved state (including frame pointer and return address),
+ assume: prev_sp + size = IX + state_size */
+ ULONGEST state_size;
+
+ struct
+ {
+ int called:1; /* there is return address on stack */
+ int load_args:1; /* prologues loads args using POPs */
+ int fp_sdcc:1; /* prologue saves and adjusts frame pointer IX */
+ int interrupt:1; /* __interrupt handler */
+ int critical:1; /* __critical function */
+ } prologue_type;
+
+ /* Table indicating the location of each and every register. */
+ struct trad_frame_saved_reg *saved_regs;
+};
+
+enum instruction_type
+{
+ insn_default,
+ insn_z80,
+ insn_adl,
+ insn_z80_ed,
+ insn_adl_ed,
+ insn_z80_ddfd,
+ insn_adl_ddfd,
+ insn_djnz_d,
+ insn_jr_d,
+ insn_jr_cc_d,
+ insn_jp_nn,
+ insn_jp_rr,
+ insn_jp_cc_nn,
+ insn_call_nn,
+ insn_call_cc_nn,
+ insn_rst_n,
+ insn_ret,
+ insn_ret_cc,
+ insn_push_rr,
+ insn_pop_rr,
+ insn_dec_sp,
+ insn_inc_sp,
+ insn_ld_sp_nn,
+ insn_ld_sp_6nn9, /* ld sp, (nn) */
+ insn_ld_sp_rr,
+ insn_force_nop /* invalid opcode prefix */
+};
+
+struct insn_info
+{
+ gdb_byte code;
+ gdb_byte mask;
+ gdb_byte size; /* without prefix(es) */
+ enum instruction_type type;
+};
+
+/* Constants */
+
+static const struct insn_info *
+z80_get_insn_info (struct gdbarch *gdbarch, const gdb_byte *buf, int *size);
+
+static const char *z80_reg_names[] =
+{
+ /* 24 bit on eZ80, else 16 bit */
+ "af", "bc", "de", "hl",
+ "sp", "pc", "ix", "iy",
+ "af'", "bc'", "de'", "hl'",
+ "ir",
+ /* eZ80 only */
+ "sps"
+};
+
+/* Return the name of register REGNUM. */
+static const char *
+z80_register_name (struct gdbarch *gdbarch, int regnum)
+{
+ if (regnum >= 0 && regnum < ARRAY_SIZE (z80_reg_names))
+ return z80_reg_names[regnum];
+
+ return NULL;
+}
+
+/* Return the type of a register specified by the architecture. Only
+ the register cache should call this function directly; others should
+ use "register_type". */
+static struct type *
+z80_register_type (struct gdbarch *gdbarch, int reg_nr)
+{
+ return builtin_type (gdbarch)->builtin_data_ptr;
+}
+
+/* The next 2 functions check BUF for instruction. If it is pop/push rr, then
+ it returns register number OR'ed with 0x100 */
+static int
+z80_is_pop_rr (const gdb_byte buf[], int *size)
+{
+ switch (buf[0])
+ {
+ case 0xc1:
+ *size = 1;
+ return Z80_BC_REGNUM | 0x100;
+ case 0xd1:
+ *size = 1;
+ return Z80_DE_REGNUM | 0x100;
+ case 0xe1:
+ *size = 1;
+ return Z80_HL_REGNUM | 0x100;
+ case 0xf1:
+ *size = 1;
+ return Z80_AF_REGNUM | 0x100;
+ case 0xdd:
+ *size = 2;
+ return (buf[1] == 0xe1) ? (Z80_IX_REGNUM | 0x100) : 0;
+ case 0xfd:
+ *size = 2;
+ return (buf[1] == 0xe1) ? (Z80_IY_REGNUM | 0x100) : 0;
+ }
+ *size = 0;
+ return 0;
+}
+
+static int
+z80_is_push_rr (const gdb_byte buf[], int *size)
+{
+ switch (buf[0])
+ {
+ case 0xc5:
+ *size = 1;
+ return Z80_BC_REGNUM | 0x100;
+ case 0xd5:
+ *size = 1;
+ return Z80_DE_REGNUM | 0x100;
+ case 0xe5:
+ *size = 1;
+ return Z80_HL_REGNUM | 0x100;
+ case 0xf5:
+ *size = 1;
+ return Z80_AF_REGNUM | 0x100;
+ case 0xdd:
+ *size = 2;
+ return (buf[1] == 0xe5) ? (Z80_IX_REGNUM | 0x100) : 0;
+ case 0xfd:
+ *size = 2;
+ return (buf[1] == 0xe5) ? (Z80_IY_REGNUM | 0x100) : 0;
+ }
+ *size = 0;
+ return 0;
+}
+
+/* Function: z80_scan_prologue
+
+ This function decodes a 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 z80_unwind_cache structure.
+ Small SDCC functions may just load args using POP instructions in prologue:
+ pop af
+ pop de
+ pop hl
+ pop bc
+ push bc
+ push hl
+ push de
+ push af
+ SDCC function prologue may have up to 3 sections (all are optional):
+ 1) save state
+ a) __critical functions:
+ ld a,i
+ di
+ push af
+ b) __interrupt (both int and nmi) functions:
+ push af
+ push bc
+ push de
+ push hl
+ push iy
+ 2) save and adjust frame pointer
+ a) call to special function (size optimization)
+ call ___sdcc_enter_ix
+ b) inline (speed optimization)
+ push ix
+ ld ix, #0
+ add ix, sp
+ c) without FP, but saving it (IX is optimized out)
+ push ix
+ 3) allocate local variables
+ a) via series of PUSH AF and optional DEC SP (size optimization)
+ push af
+ ...
+ push af
+ dec sp ;optional, if allocated odd numbers of bytes
+ b) via SP decrements
+ dec sp
+ ...
+ dec sp
+ c) via addition (for large frames: 5+ for speed and 9+ for size opt.)
+ ld hl, #xxxx ;size of stack frame
+ add hl, sp
+ ld sp, hl
+ d) same, but using register IY (arrays or for __z88dk_fastcall functions)
+ ld iy, #xxxx ;size of stack frame
+ add iy, sp
+ ld sp, iy
+ e) same as c, but for eZ80
+ lea hl, ix - #nn
+ ld sp, hl
+ f) same as d, but for eZ80
+ lea iy, ix - #nn
+ ld sp, iy
+*/
+
+static int
+z80_scan_prologue (struct gdbarch *gdbarch, CORE_ADDR pc_beg, CORE_ADDR pc_end,
+ struct z80_unwind_cache *info)
+{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ int addr_len = gdbarch_tdep (gdbarch)->addr_length;
+ gdb_byte prologue[32]; /* max prologue is 24 bytes: __interrupt with local array */
+ int pos = 0;
+ int len;
+ int reg;
+ CORE_ADDR value;
+
+ len = pc_end - pc_beg;
+ if (len > (int)sizeof (prologue))
+ len = sizeof (prologue);
+
+ read_memory (pc_beg, prologue, len);
+
+ /* stage0: check for series of POPs and then PUSHs */
+ if ((reg = z80_is_pop_rr(prologue, &pos)))
+ {
+ int i;
+ int size = pos;
+ gdb_byte regs[8]; /* Z80 have only 6 register pairs */
+ regs[0] = reg & 0xff;
+ for (i = 1; i < 8 && (regs[i] = z80_is_pop_rr (&prologue[pos], &size));
+ ++i, pos += size);
+ /* now we expect series of PUSHs in reverse order */
+ for (--i; i >= 0 && regs[i] == z80_is_push_rr (&prologue[pos], &size);
+ --i, pos += size);
+ if (i == -1 && pos > 0)
+ info->prologue_type.load_args = 1;
+ else
+ pos = 0;
+ }
+ /* stage1: check for __interrupt handlers and __critical functions */
+ else if (!memcmp (&prologue[pos], "\355\127\363\365", 4))
+ { /* ld a, i; di; push af */
+ info->prologue_type.critical = 1;
+ pos += 4;
+ info->state_size += addr_len;
+ }
+ else if (!memcmp (&prologue[pos], "\365\305\325\345\375\345", 6))
+ { /* push af; push bc; push de; push hl; push iy */
+ info->prologue_type.interrupt = 1;
+ pos += 6;
+ info->state_size += addr_len * 5;
+ }
+
+ /* stage2: check for FP saving scheme */
+ if (prologue[pos] == 0xcd) /* call nn */
+ {
+ struct bound_minimal_symbol msymbol;
+ msymbol = lookup_minimal_symbol ("__sdcc_enter_ix", NULL, NULL);
+ if (msymbol.minsym)
+ {
+ value = BMSYMBOL_VALUE_ADDRESS (msymbol);
+ if (value == extract_unsigned_integer (&prologue[pos+1], addr_len, byte_order))
+ {
+ pos += 1 + addr_len;
+ info->prologue_type.fp_sdcc = 1;
+ }
+ }
+ }
+ else if (!memcmp (&prologue[pos], "\335\345\335\041\000\000", 4+addr_len) &&
+ !memcmp (&prologue[pos+4+addr_len], "\335\071\335\371", 4))
+ { /* push ix; ld ix, #0; add ix, sp; ld sp, ix */
+ pos += 4 + addr_len + 4;
+ info->prologue_type.fp_sdcc = 1;
+ }
+ else if (!memcmp (&prologue[pos], "\335\345", 2))
+ { /* push ix */
+ pos += 2;
+ info->prologue_type.fp_sdcc = 1;
+ }
+
+ /* stage3: check for local variables allocation */
+ switch (prologue[pos])
+ {
+ case 0xf5: /* push af */
+ info->size = 0;
+ while (prologue[pos] == 0xf5)
+ {
+ info->size += addr_len;
+ pos++;
+ }
+ if (prologue[pos] == 0x3b) /* dec sp */
+ {
+ info->size++;
+ pos++;
+ }
+ break;
+ case 0x3b: /* dec sp */
+ info->size = 0;
+ while (prologue[pos] == 0x3b)
+ {
+ info->size++;
+ pos++;
+ }
+ break;
+ case 0x21: /*ld hl, -nn */
+ if (prologue[pos+addr_len] == 0x39 && prologue[pos+addr_len] >= 0x80 &&
+ prologue[pos+addr_len+1] == 0xf9)
+ { /* add hl, sp; ld sp, hl */
+ info->size = -extract_signed_integer(&prologue[pos+1], addr_len, byte_order);
+ pos += 1 + addr_len + 2;
+ }
+ break;
+ case 0xfd: /* ld iy, -nn */
+ if (prologue[pos+1] == 0x21 && prologue[pos+1+addr_len] >= 0x80 &&
+ !memcmp (&prologue[pos+2+addr_len], "\375\071\375\371", 4))
+ {
+ info->size = -extract_signed_integer(&prologue[pos+2], addr_len, byte_order);
+ pos += 2 + addr_len + 4;
+ }
+ break;
+ case 0xed: /* check for lea xx, ix - n */
+ switch (prologue[pos+1])
+ {
+ case 0x22: /* lea hl, ix - n */
+ if (prologue[pos+2] >= 0x80 && prologue[pos+3] == 0xf9)
+ { /* ld sp, hl */
+ info->size = -extract_signed_integer(&prologue[pos+2], 1, byte_order);
+ pos += 4;
+ }
+ break;
+ case 0x55: /* lea iy, ix - n */
+ if (prologue[pos+2] >= 0x80 && prologue[pos+3] == 0xfd &&
+ prologue[pos+4] == 0xf9)
+ { /* ld sp, iy */
+ info->size = -extract_signed_integer(&prologue[pos+2], 1, byte_order);
+ pos += 5;
+ }
+ break;
+ }
+ break;
+ }
+ len = 0;
+
+ if (info->prologue_type.interrupt)
+ {
+ info->saved_regs[Z80_AF_REGNUM].set_addr (len++);
+ info->saved_regs[Z80_BC_REGNUM].set_addr (len++);
+ info->saved_regs[Z80_DE_REGNUM].set_addr (len++);
+ info->saved_regs[Z80_HL_REGNUM].set_addr (len++);
+ info->saved_regs[Z80_IY_REGNUM].set_addr (len++);
+ }
+
+ if (info->prologue_type.critical)
+ len++; /* just skip IFF2 saved state */
+
+ if (info->prologue_type.fp_sdcc)
+ info->saved_regs[Z80_IX_REGNUM].set_addr (len++);
+
+ info->state_size += len * addr_len;
+
+ return pc_beg + pos;
+}
+
+static CORE_ADDR
+z80_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ CORE_ADDR func_addr, func_end;
+ CORE_ADDR prologue_end;
+
+ if (!find_pc_partial_function (pc, NULL, &func_addr, &func_end))
+ return pc;
+
+ prologue_end = skip_prologue_using_sal (gdbarch, func_addr);
+ if (prologue_end != 0)
+ return std::max (pc, prologue_end);
+
+ {
+ struct z80_unwind_cache info = {0};
+ struct trad_frame_saved_reg saved_regs[Z80_NUM_REGS];
+
+ info.saved_regs = saved_regs;
+
+ /* Need to run the prologue scanner to figure out if the function has a
+ prologue. */
+
+ prologue_end = z80_scan_prologue (gdbarch, func_addr, func_end, &info);
+
+ if (info.prologue_type.fp_sdcc || info.prologue_type.interrupt ||
+ info.prologue_type.critical)
+ return std::max (pc, prologue_end);
+ }
+
+ if (prologue_end != 0)
+ {
+ struct symtab_and_line prologue_sal = find_pc_line (func_addr, 0);
+ struct compunit_symtab *compunit = SYMTAB_COMPUNIT (prologue_sal.symtab);
+ const char *debug_format = COMPUNIT_DEBUGFORMAT (compunit);
+
+ if (debug_format != NULL &&
+ !strncasecmp ("dwarf", debug_format, strlen("dwarf")))
+ return std::max (pc, prologue_end);
+ }
+
+ return pc;
+}
+
+/* Return the return-value convention that will be used by FUNCTION
+ to return a value of type VALTYPE. FUNCTION may be NULL in which
+ case the return convention is computed based only on VALTYPE.
+
+ If READBUF is not NULL, extract the return value and save it in this buffer.
+
+ If WRITEBUF is not NULL, it contains a return value which will be
+ stored into the appropriate register. This can be used when we want
+ to force the value returned by a function (see the "return" command
+ for instance). */
+static enum return_value_convention
+z80_return_value (struct gdbarch *gdbarch, struct value *function,
+ struct type *valtype, struct regcache *regcache,
+ gdb_byte *readbuf, const gdb_byte *writebuf)
+{
+ /* Byte are returned in L, word in HL, dword in DEHL. */
+ int len = TYPE_LENGTH (valtype);
+
+ if ((valtype->code () == TYPE_CODE_STRUCT
+ || valtype->code () == TYPE_CODE_UNION
+ || valtype->code () == TYPE_CODE_ARRAY)
+ && len > 4)
+ return RETURN_VALUE_STRUCT_CONVENTION;
+
+ if (writebuf != NULL)
+ {
+ if (len > 2)
+ {
+ regcache->cooked_write_part (Z80_DE_REGNUM, 0, len - 2, writebuf+2);
+ len = 2;
+ }
+ regcache->cooked_write_part (Z80_HL_REGNUM, 0, len, writebuf);
+ }
+
+ if (readbuf != NULL)
+ {
+ if (len > 2)
+ {
+ regcache->cooked_read_part (Z80_DE_REGNUM, 0, len - 2, readbuf+2);
+ len = 2;
+ }
+ regcache->cooked_read_part (Z80_HL_REGNUM, 0, len, readbuf);
+ }
+
+ return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+/* function unwinds current stack frame and returns next one */
+static struct z80_unwind_cache *
+z80_frame_unwind_cache (struct frame_info *this_frame,
+ void **this_prologue_cache)
+{
+ CORE_ADDR start_pc, current_pc;
+ ULONGEST this_base;
+ int i;
+ gdb_byte buf[sizeof(void*)];
+ struct z80_unwind_cache *info;
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ int addr_len = gdbarch_tdep (gdbarch)->addr_length;
+
+ if (*this_prologue_cache)
+ return (struct z80_unwind_cache *) *this_prologue_cache;
+
+ info = FRAME_OBSTACK_ZALLOC (struct z80_unwind_cache);
+ memset (info, 0, sizeof (*info));
+ info->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+ *this_prologue_cache = info;
+
+ start_pc = get_frame_func (this_frame);
+ current_pc = get_frame_pc (this_frame);
+ if ((start_pc > 0) && (start_pc <= current_pc))
+ z80_scan_prologue (get_frame_arch (this_frame),
+ start_pc, current_pc, info);
+
+ if (info->prologue_type.fp_sdcc)
+ {
+ /* With SDCC standard prologue, IX points to the end of current frame
+ (where previous frame pointer and state are saved). */
+ this_base = get_frame_register_unsigned (this_frame, Z80_IX_REGNUM);
+ info->prev_sp = this_base + info->size;
+ }
+ else
+ {
+ CORE_ADDR addr;
+ CORE_ADDR sp;
+ CORE_ADDR sp_mask = (1 << gdbarch_ptr_bit(gdbarch)) - 1;
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ /* Assume that the FP is this frame's SP but with that pushed
+ stack space added back. */
+ this_base = get_frame_register_unsigned (this_frame, Z80_SP_REGNUM);
+ sp = this_base + info->size;
+ for (;; ++sp)
+ {
+ sp &= sp_mask;
+ if (sp < this_base)
+ { /* overflow, looks like end of stack */
+ sp = this_base + info->size;
+ break;
+ }
+ /* find return address */
+ read_memory (sp, buf, addr_len);
+ addr = extract_unsigned_integer(buf, addr_len, byte_order);
+ read_memory (addr-addr_len-1, buf, addr_len+1);
+ if (buf[0] == 0xcd || (buf[0] & 0307) == 0304) /* Is it CALL */
+ { /* CALL nn or CALL cc,nn */
+ static const char *names[] =
+ {
+ "__sdcc_call_ix", "__sdcc_call_iy", "__sdcc_call_hl"
+ };
+ addr = extract_unsigned_integer(buf+1, addr_len, byte_order);
+ if (addr == start_pc)
+ break; /* found */
+ for (i = sizeof(names)/sizeof(*names)-1; i >= 0; --i)
+ {
+ struct bound_minimal_symbol msymbol;
+ msymbol = lookup_minimal_symbol (names[i], NULL, NULL);
+ if (!msymbol.minsym)
+ continue;
+ if (addr == BMSYMBOL_VALUE_ADDRESS (msymbol))
+ break;
+ }
+ if (i >= 0)
+ break;
+ continue;
+ }
+ else
+ continue; /* it is not call_nn, call_cc_nn */
+ }
+ info->prev_sp = sp;
+ }
+
+ /* Adjust all the saved registers so that they contain addresses and not
+ offsets. */
+ for (i = 0; i < gdbarch_num_regs (gdbarch) - 1; i++)
+ if (info->saved_regs[i].addr () > 0)
+ info->saved_regs[i].set_addr
+ (info->prev_sp - info->saved_regs[i].addr () * addr_len);
+
+ /* Except for the startup code, the return PC is always saved on
+ the stack and is at the base of the frame. */
+ info->saved_regs[Z80_PC_REGNUM].set_addr (info->prev_sp);
+
+ /* The previous frame's SP needed to be computed. Save the computed
+ value. */
+ info->saved_regs[Z80_SP_REGNUM].set_value (info->prev_sp + addr_len);
+ return info;
+}
+
+/* Given a GDB frame, determine the address of the calling function's
+ frame. This will be used to create a new GDB frame struct. */
+static void
+z80_frame_this_id (struct frame_info *this_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ struct frame_id id;
+ struct z80_unwind_cache *info;
+ CORE_ADDR base;
+ CORE_ADDR func;
+
+ /* The FUNC is easy. */
+ func = get_frame_func (this_frame);
+
+ info = z80_frame_unwind_cache (this_frame, this_cache);
+ /* Hopefully the prologue analysis either correctly determined the
+ frame's base (which is the SP from the previous frame), or set
+ that base to "NULL". */
+ base = info->prev_sp;
+ if (base == 0)
+ return;
+
+ id = frame_id_build (base, func);
+ *this_id = id;
+}
+
+static struct value *
+z80_frame_prev_register (struct frame_info *this_frame,
+ void **this_prologue_cache, int regnum)
+{
+ struct z80_unwind_cache *info
+ = z80_frame_unwind_cache (this_frame, this_prologue_cache);
+
+ if (regnum == Z80_PC_REGNUM)
+ {
+ if (info->saved_regs[Z80_PC_REGNUM].is_addr ())
+ {
+ /* Reading the return PC from the PC register is slightly
+ abnormal. */
+ ULONGEST pc;
+ gdb_byte buf[3];
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
+ read_memory (info->saved_regs[Z80_PC_REGNUM].addr (),
+ buf, tdep->addr_length);
+ pc = extract_unsigned_integer (buf, tdep->addr_length, byte_order);
+ return frame_unwind_got_constant (this_frame, regnum, pc);
+ }
+
+ return frame_unwind_got_optimized (this_frame, regnum);
+ }
+
+ return trad_frame_get_prev_register (this_frame, info->saved_regs, regnum);
+}
+
+/* Return the breakpoint kind for this target based on *PCPTR. */
+static int
+z80_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr)
+{
+ static int addr = -1;
+ if (addr == -1)
+ {
+ struct bound_minimal_symbol bh;
+ bh = lookup_minimal_symbol ("_break_handler", NULL, NULL);
+ if (bh.minsym)
+ addr = BMSYMBOL_VALUE_ADDRESS (bh);
+ else
+ {
+ warning(_("Unable to determine inferior's software breakpoint type: "
+ "couldn't find `_break_handler' function in inferior. Will "
+ "be used default software breakpoint instruction RST 0x08."));
+ addr = 0x0008;
+ }
+ }
+ return addr;
+}
+
+/* Return the software breakpoint from KIND. KIND is just address of breakpoint
+ handler. If address is on of standard RSTs, then RST n instruction is used
+ as breakpoint.
+ SIZE is set to the software breakpoint's length in memory. */
+static const gdb_byte *
+z80_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size)
+{
+ static gdb_byte break_insn[8];
+
+ if ((kind & 070) == kind)
+ {
+ break_insn[0] = kind | 0307;
+ *size = 1;
+ }
+ else /* kind is non-RST address, use CALL instead, but it is dungerous */
+ {
+ gdb_byte *p = break_insn;
+ *p++ = 0xcd;
+ *p++ = (kind >> 0) & 0xff;
+ *p++ = (kind >> 8) & 0xff;
+ if (gdbarch_tdep (gdbarch)->addr_length > 2)
+ *p++ = (kind >> 16) & 0xff;
+ *size = p - break_insn;
+ }
+ return break_insn;
+}
+
+/* Return a vector of addresses on which the software single step
+ breakpoints should be inserted. NULL means software single step is
+ not used.
+ Only one breakpoint address will be returned: conditional branches
+ will be always evaluated. */
+static std::vector<CORE_ADDR>
+z80_software_single_step (struct regcache *regcache)
+{
+ static const int flag_mask[] = {1 << 6, 1 << 0, 1 << 2, 1 << 7};
+ gdb_byte buf[8];
+ ULONGEST t;
+ ULONGEST addr;
+ int opcode;
+ int size;
+ const struct insn_info *info;
+ std::vector<CORE_ADDR> ret (1);
+ struct gdbarch *gdbarch = target_gdbarch ();
+
+ regcache->cooked_read (Z80_PC_REGNUM, &addr);
+ read_memory (addr, buf, sizeof(buf));
+ info = z80_get_insn_info (gdbarch, buf, &size);
+ ret[0] = addr + size;
+ if (info == NULL) /* possible in case of double prefix */
+ { /* forced NOP, TODO: replace by NOP */
+ return ret;
+ }
+ opcode = buf[size - info->size]; /* take opcode instead of prefix */
+ /* stage 1: check for conditions */
+ switch (info->type)
+ {
+ case insn_djnz_d:
+ regcache->cooked_read (Z80_BC_REGNUM, &t);
+ if ((t & 0xff00) != 0x100)
+ return ret;
+ break;
+ case insn_jr_cc_d:
+ opcode &= 030; /* JR NZ,d has cc equal to 040, but others 000 */
+ /* fall through */
+ case insn_jp_cc_nn:
+ case insn_call_cc_nn:
+ case insn_ret_cc:
+ regcache->cooked_read (Z80_AF_REGNUM, &t);
+ /* lower bit of condition inverts match, so invert flags if set */
+ if ((opcode & 010) != 0)
+ t = ~t;
+ /* two higher bits of condition field defines flag, so use them only
+ to check condition of "not execute" */
+ if (t & flag_mask[(opcode >> 4) & 3])
+ return ret;
+ break;
+ }
+ /* stage 2: compute address */
+ /* TODO: implement eZ80 MADL support */
+ switch (info->type)
+ {
+ default:
+ return ret;
+ case insn_djnz_d:
+ case insn_jr_d:
+ case insn_jr_cc_d:
+ addr += size;
+ addr += (signed char)buf[size-1];
+ break;
+ case insn_jp_rr:
+ if (size == 1)
+ opcode = Z80_HL_REGNUM;
+ else
+ opcode = (buf[size-2] & 0x20) ? Z80_IY_REGNUM : Z80_IX_REGNUM;
+ regcache->cooked_read (opcode, &addr);
+ break;
+ case insn_jp_nn:
+ case insn_jp_cc_nn:
+ case insn_call_nn:
+ case insn_call_cc_nn:
+ addr = buf[size-1] * 0x100 + buf[size-2];
+ if (info->size > 3) /* long instruction mode */
+ addr = addr * 0x100 + buf[size-3];
+ break;
+ case insn_rst_n:
+ addr = opcode & 070;
+ break;
+ case insn_ret:
+ case insn_ret_cc:
+ regcache->cooked_read (Z80_SP_REGNUM, &addr);
+ read_memory (addr, buf, 3);
+ addr = buf[1] * 0x100 + buf[0];
+ if (gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_ez80_adl)
+ addr = addr * 0x100 + buf[2];
+ break;
+ }
+ ret[0] = addr;
+ return ret;
+}
+
+/* Cached, dynamically allocated copies of the target data structures: */
+static unsigned (*cache_ovly_region_table)[3] = 0;
+static unsigned cache_novly_regions;
+static CORE_ADDR cache_ovly_region_table_base = 0;
+enum ovly_index
+ {
+ VMA, OSIZE, MAPPED_TO_LMA
+ };
+
+static void
+z80_free_overlay_region_table (void)
+{
+ if (cache_ovly_region_table)
+ xfree (cache_ovly_region_table);
+ cache_novly_regions = 0;
+ cache_ovly_region_table = NULL;
+ cache_ovly_region_table_base = 0;
+}
+
+/* Read an array of ints of size SIZE from the target into a local buffer.
+ Convert to host order. LEN is number of ints. */
+
+static void
+read_target_long_array (CORE_ADDR memaddr, unsigned int *myaddr,
+ int len, int size, enum bfd_endian byte_order)
+{
+ /* alloca is safe here, because regions array is very small. */
+ gdb_byte *buf = (gdb_byte *) alloca (len * size);
+ int i;
+
+ read_memory (memaddr, buf, len * size);
+ for (i = 0; i < len; i++)
+ myaddr[i] = extract_unsigned_integer (size * i + buf, size, byte_order);
+}
+
+static int
+z80_read_overlay_region_table ()
+{
+ struct bound_minimal_symbol novly_regions_msym;
+ struct bound_minimal_symbol ovly_region_table_msym;
+ struct gdbarch *gdbarch;
+ int word_size;
+ enum bfd_endian byte_order;
+
+ z80_free_overlay_region_table ();
+ novly_regions_msym = lookup_minimal_symbol ("_novly_regions", NULL, NULL);
+ if (! novly_regions_msym.minsym)
+ {
+ error (_("Error reading inferior's overlay table: "
+ "couldn't find `_novly_regions'\n"
+ "variable in inferior. Use `overlay manual' mode."));
+ return 0;
+ }
+
+ ovly_region_table_msym = lookup_bound_minimal_symbol ("_ovly_region_table");
+ if (! ovly_region_table_msym.minsym)
+ {
+ error (_("Error reading inferior's overlay table: couldn't find "
+ "`_ovly_region_table'\n"
+ "array in inferior. Use `overlay manual' mode."));
+ return 0;
+ }
+
+ const enum overlay_debugging_state save_ovly_dbg = overlay_debugging;
+ /* prevent infinite recurse */
+ overlay_debugging = ovly_off;
+
+ gdbarch = ovly_region_table_msym.objfile->arch ();
+ word_size = gdbarch_long_bit (gdbarch) / TARGET_CHAR_BIT;
+ byte_order = gdbarch_byte_order (gdbarch);
+
+ cache_novly_regions = read_memory_integer (
+ BMSYMBOL_VALUE_ADDRESS (novly_regions_msym),
+ 4, byte_order);
+ cache_ovly_region_table
+ = (unsigned int (*)[3]) xmalloc (cache_novly_regions *
+ sizeof (*cache_ovly_region_table));
+ cache_ovly_region_table_base
+ = BMSYMBOL_VALUE_ADDRESS (ovly_region_table_msym);
+ read_target_long_array (cache_ovly_region_table_base,
+ (unsigned int *) cache_ovly_region_table,
+ cache_novly_regions * 3, word_size, byte_order);
+
+ overlay_debugging = save_ovly_dbg;
+ return 1; /* SUCCESS */
+}
+
+static int
+z80_overlay_update_1 (struct obj_section *osect)
+{
+ int i;
+ asection *bsect = osect->the_bfd_section;
+ unsigned lma;
+ unsigned vma = bfd_section_vma (bsect);
+
+ /* find region corresponding to the section VMA */
+ for (i = 0; i < cache_novly_regions; i++)
+ if (cache_ovly_region_table[i][VMA] == vma)
+ break;
+ if (i == cache_novly_regions)
+ return 0; /* no such region */
+
+ lma = cache_ovly_region_table[i][MAPPED_TO_LMA];
+ i = 0;
+
+ /* we have interest for sections with same VMA */
+ for (objfile *objfile : current_program_space->objfiles ())
+ ALL_OBJFILE_OSECTIONS (objfile, osect)
+ if (section_is_overlay (osect))
+ {
+ osect->ovly_mapped = (lma == bfd_section_lma (osect->the_bfd_section));
+ i |= osect->ovly_mapped; /* true, if at least one section is mapped */
+ }
+ return i;
+}
+
+/* Refresh overlay mapped state for section OSECT. */
+static void
+z80_overlay_update (struct obj_section *osect)
+{
+ /* Always need to read the entire table anew. */
+ if (!z80_read_overlay_region_table ())
+ return;
+
+ /* Were we given an osect to look up? NULL means do all of them. */
+ if (osect != nullptr && z80_overlay_update_1 (osect))
+ return;
+
+ /* Update all sections, even if only one was requested. */
+ for (objfile *objfile : current_program_space->objfiles ())
+ ALL_OBJFILE_OSECTIONS (objfile, osect)
+ {
+ if (!section_is_overlay (osect))
+ continue;
+
+ asection *bsect = osect->the_bfd_section;
+ bfd_vma lma = bfd_section_lma (bsect);
+ bfd_vma vma = bfd_section_vma (bsect);
+
+ for (int i = 0; i < cache_novly_regions; ++i)
+ if (cache_ovly_region_table[i][VMA] == vma)
+ osect->ovly_mapped =
+ (cache_ovly_region_table[i][MAPPED_TO_LMA] == lma);
+ }
+}
+
+/* Return non-zero if the instruction at ADDR is a call; zero otherwise. */
+static int
+z80_insn_is_call (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ gdb_byte buf[8];
+ int size;
+ const struct insn_info *info;
+ read_memory (addr, buf, sizeof(buf));
+ info = z80_get_insn_info (gdbarch, buf, &size);
+ if (info)
+ switch (info->type)
+ {
+ case insn_call_nn:
+ case insn_call_cc_nn:
+ case insn_rst_n:
+ return 1;
+ }
+ return 0;
+}
+
+/* Return non-zero if the instruction at ADDR is a return; zero otherwise. */
+static int
+z80_insn_is_ret (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ gdb_byte buf[8];
+ int size;
+ const struct insn_info *info;
+ read_memory (addr, buf, sizeof(buf));
+ info = z80_get_insn_info (gdbarch, buf, &size);
+ if (info)
+ switch (info->type)
+ {
+ case insn_ret:
+ case insn_ret_cc:
+ return 1;
+ }
+ return 0;
+}
+
+/* Return non-zero if the instruction at ADDR is a jump; zero otherwise. */
+static int
+z80_insn_is_jump (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ gdb_byte buf[8];
+ int size;
+ const struct insn_info *info;
+ read_memory (addr, buf, sizeof(buf));
+ info = z80_get_insn_info (gdbarch, buf, &size);
+ if (info)
+ switch (info->type)
+ {
+ case insn_jp_nn:
+ case insn_jp_cc_nn:
+ case insn_jp_rr:
+ case insn_jr_d:
+ case insn_jr_cc_d:
+ case insn_djnz_d:
+ return 1;
+ }
+ return 0;
+}
+
+static const struct frame_unwind
+z80_frame_unwind =
+{
+ "z80",
+ NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
+ z80_frame_this_id,
+ z80_frame_prev_register,
+ NULL, /*unwind_data*/
+ default_frame_sniffer
+ /*dealloc_cache*/
+ /*prev_arch*/
+};
+
+/* Initialize the gdbarch struct for the Z80 arch */
+static struct gdbarch *
+z80_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+ struct gdbarch *gdbarch;
+ struct gdbarch_tdep *tdep;
+ struct gdbarch_list *best_arch;
+ tdesc_arch_data_up tdesc_data;
+ unsigned long mach = info.bfd_arch_info->mach;
+ const struct target_desc *tdesc = info.target_desc;
+
+ if (!tdesc_has_registers (tdesc))
+ /* Pick a default target description. */
+ tdesc = tdesc_z80;
+
+ /* Check any target description for validity. */
+ if (tdesc_has_registers (tdesc))
+ {
+ const struct tdesc_feature *feature;
+ int valid_p;
+
+ feature = tdesc_find_feature (tdesc, "org.gnu.gdb.z80.cpu");
+ if (feature == NULL)
+ return NULL;
+
+ tdesc_data = tdesc_data_alloc ();
+
+ valid_p = 1;
+
+ for (unsigned i = 0; i < Z80_NUM_REGS; i++)
+ valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), i,
+ z80_reg_names[i]);
+
+ if (!valid_p)
+ return NULL;
+ }
+
+ /* If there is already a candidate, use it. */
+ for (best_arch = gdbarch_list_lookup_by_info (arches, &info);
+ best_arch != NULL;
+ best_arch = gdbarch_list_lookup_by_info (best_arch->next, &info))
+ {
+ if (mach == gdbarch_bfd_arch_info (best_arch->gdbarch)->mach)
+ return best_arch->gdbarch;
+ }
+
+ /* None found, create a new architecture from the information provided. */
+ tdep = XCNEW (struct gdbarch_tdep);
+ gdbarch = gdbarch_alloc (&info, tdep);
+
+ if (mach == bfd_mach_ez80_adl)
+ {
+ tdep->addr_length = 3;
+ set_gdbarch_max_insn_length (gdbarch, 6);
+ }
+ else
+ {
+ tdep->addr_length = 2;
+ set_gdbarch_max_insn_length (gdbarch, 4);
+ }
+
+ /* Create a type for PC. We can't use builtin types here, as they may not
+ be defined. */
+ tdep->void_type = arch_type (gdbarch, TYPE_CODE_VOID, TARGET_CHAR_BIT,
+ "void");
+ tdep->func_void_type = make_function_type (tdep->void_type, NULL);
+ tdep->pc_type = arch_pointer_type (gdbarch,
+ tdep->addr_length * TARGET_CHAR_BIT,
+ NULL, tdep->func_void_type);
+
+ set_gdbarch_short_bit (gdbarch, TARGET_CHAR_BIT);
+ set_gdbarch_int_bit (gdbarch, 2 * TARGET_CHAR_BIT);
+ set_gdbarch_long_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ set_gdbarch_ptr_bit (gdbarch, tdep->addr_length * TARGET_CHAR_BIT);
+ set_gdbarch_addr_bit (gdbarch, tdep->addr_length * TARGET_CHAR_BIT);
+
+ set_gdbarch_num_regs (gdbarch, (mach == bfd_mach_ez80_adl) ? EZ80_NUM_REGS
+ : Z80_NUM_REGS);
+ set_gdbarch_sp_regnum (gdbarch, Z80_SP_REGNUM);
+ set_gdbarch_pc_regnum (gdbarch, Z80_PC_REGNUM);
+
+ set_gdbarch_register_name (gdbarch, z80_register_name);
+ set_gdbarch_register_type (gdbarch, z80_register_type);
+
+ /* TODO: get FP type from binary (extra flags required) */
+ 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, floatformats_ieee_single);
+ set_gdbarch_double_format (gdbarch, floatformats_ieee_single);
+ set_gdbarch_long_double_format (gdbarch, floatformats_ieee_single);
+
+ set_gdbarch_return_value (gdbarch, z80_return_value);
+
+ set_gdbarch_skip_prologue (gdbarch, z80_skip_prologue);
+ set_gdbarch_inner_than (gdbarch, core_addr_lessthan); // falling stack
+
+ set_gdbarch_software_single_step (gdbarch, z80_software_single_step);
+ set_gdbarch_breakpoint_kind_from_pc (gdbarch, z80_breakpoint_kind_from_pc);
+ set_gdbarch_sw_breakpoint_from_kind (gdbarch, z80_sw_breakpoint_from_kind);
+ set_gdbarch_insn_is_call (gdbarch, z80_insn_is_call);
+ set_gdbarch_insn_is_jump (gdbarch, z80_insn_is_jump);
+ set_gdbarch_insn_is_ret (gdbarch, z80_insn_is_ret);
+
+ set_gdbarch_overlay_update (gdbarch, z80_overlay_update);
+
+ frame_unwind_append_unwinder (gdbarch, &z80_frame_unwind);
+ if (tdesc_data)
+ tdesc_use_registers (gdbarch, tdesc, std::move (tdesc_data));
+
+ return gdbarch;
+}
+
+/* Table to disassemble machine codes without prefix. */
+static const struct insn_info
+ez80_main_insn_table[] =
+{ /* table with double prefix check */
+ { 0100, 0377, 0, insn_force_nop}, //double prefix
+ { 0111, 0377, 0, insn_force_nop}, //double prefix
+ { 0122, 0377, 0, insn_force_nop}, //double prefix
+ { 0133, 0377, 0, insn_force_nop}, //double prefix
+ /* initial table for eZ80_z80 */
+ { 0100, 0377, 1, insn_z80 }, //eZ80 mode prefix
+ { 0111, 0377, 1, insn_z80 }, //eZ80 mode prefix
+ { 0122, 0377, 1, insn_adl }, //eZ80 mode prefix
+ { 0133, 0377, 1, insn_adl }, //eZ80 mode prefix
+ /* here common Z80/Z180/eZ80 opcodes */
+ { 0000, 0367, 1, insn_default }, //"nop", "ex af,af'"
+ { 0061, 0377, 3, insn_ld_sp_nn }, //"ld sp,nn"
+ { 0001, 0317, 3, insn_default }, //"ld rr,nn"
+ { 0002, 0347, 1, insn_default }, //"ld (rr),a", "ld a,(rr)"
+ { 0042, 0347, 3, insn_default }, //"ld (nn),hl/a", "ld hl/a,(nn)"
+ { 0063, 0377, 1, insn_inc_sp }, //"inc sp"
+ { 0073, 0377, 1, insn_dec_sp }, //"dec sp"
+ { 0003, 0303, 1, insn_default }, //"inc rr", "dec rr", ...
+ { 0004, 0307, 1, insn_default }, //"inc/dec r/(hl)"
+ { 0006, 0307, 2, insn_default }, //"ld r,n", "ld (hl),n"
+ { 0020, 0377, 2, insn_djnz_d }, //"djnz dis"
+ { 0030, 0377, 2, insn_jr_d }, //"jr dis"
+ { 0040, 0347, 2, insn_jr_cc_d }, //"jr cc,dis"
+ { 0100, 0300, 1, insn_default }, //"ld r,r", "halt"
+ { 0200, 0300, 1, insn_default }, //"alu_op a,r"
+ { 0300, 0307, 1, insn_ret_cc }, //"ret cc"
+ { 0301, 0317, 1, insn_pop_rr }, //"pop rr"
+ { 0302, 0307, 3, insn_jp_cc_nn }, //"jp cc,nn"
+ { 0303, 0377, 3, insn_jp_nn }, //"jp nn"
+ { 0304, 0307, 3, insn_call_cc_nn}, //"call cc,nn"
+ { 0305, 0317, 1, insn_push_rr }, //"push rr"
+ { 0306, 0307, 2, insn_default }, //"alu_op a,n"
+ { 0307, 0307, 1, insn_rst_n }, //"rst n"
+ { 0311, 0377, 1, insn_ret }, //"ret"
+ { 0313, 0377, 2, insn_default }, //CB prefix
+ { 0315, 0377, 3, insn_call_nn }, //"call nn"
+ { 0323, 0367, 2, insn_default }, //"out (n),a", "in a,(n)"
+ { 0335, 0337, 1, insn_z80_ddfd }, //DD/FD prefix
+ { 0351, 0377, 1, insn_jp_rr }, //"jp (hl)"
+ { 0355, 0377, 1, insn_z80_ed }, //ED prefix
+ { 0371, 0377, 1, insn_ld_sp_rr }, //"ld sp,hl"
+ { 0000, 0000, 1, insn_default } //others
+} ;
+
+static const struct insn_info
+ez80_adl_main_insn_table[] =
+{ /* table with double prefix check */
+ { 0100, 0377, 0, insn_force_nop}, //double prefix
+ { 0111, 0377, 0, insn_force_nop}, //double prefix
+ { 0122, 0377, 0, insn_force_nop}, //double prefix
+ { 0133, 0377, 0, insn_force_nop}, //double prefix
+ /* initial table for eZ80_adl */
+ { 0000, 0367, 1, insn_default }, //"nop", "ex af,af'"
+ { 0061, 0377, 4, insn_ld_sp_nn }, //"ld sp,Mmn"
+ { 0001, 0317, 4, insn_default }, //"ld rr,Mmn"
+ { 0002, 0347, 1, insn_default }, //"ld (rr),a", "ld a,(rr)"
+ { 0042, 0347, 4, insn_default }, //"ld (Mmn),hl/a", "ld hl/a,(Mmn)"
+ { 0063, 0377, 1, insn_inc_sp }, //"inc sp"
+ { 0073, 0377, 1, insn_dec_sp }, //"dec sp"
+ { 0003, 0303, 1, insn_default }, //"inc rr", "dec rr", ...
+ { 0004, 0307, 1, insn_default }, //"inc/dec r/(hl)"
+ { 0006, 0307, 2, insn_default }, //"ld r,n", "ld (hl),n"
+ { 0020, 0377, 2, insn_djnz_d }, //"djnz dis"
+ { 0030, 0377, 2, insn_jr_d }, //"jr dis"
+ { 0040, 0347, 2, insn_jr_cc_d }, //"jr cc,dis"
+ { 0100, 0377, 1, insn_z80 }, //eZ80 mode prefix (short instruction)
+ { 0111, 0377, 1, insn_z80 }, //eZ80 mode prefix (short instruction)
+ { 0122, 0377, 1, insn_adl }, //eZ80 mode prefix (long instruction)
+ { 0133, 0377, 1, insn_adl }, //eZ80 mode prefix (long instruction)
+ { 0100, 0300, 1, insn_default }, //"ld r,r", "halt"
+ { 0200, 0300, 1, insn_default }, //"alu_op a,r"
+ { 0300, 0307, 1, insn_ret_cc }, //"ret cc"
+ { 0301, 0317, 1, insn_pop_rr }, //"pop rr"
+ { 0302, 0307, 4, insn_jp_cc_nn }, //"jp cc,nn"
+ { 0303, 0377, 4, insn_jp_nn }, //"jp nn"
+ { 0304, 0307, 4, insn_call_cc_nn}, //"call cc,Mmn"
+ { 0305, 0317, 1, insn_push_rr }, //"push rr"
+ { 0306, 0307, 2, insn_default }, //"alu_op a,n"
+ { 0307, 0307, 1, insn_rst_n }, //"rst n"
+ { 0311, 0377, 1, insn_ret }, //"ret"
+ { 0313, 0377, 2, insn_default }, //CB prefix
+ { 0315, 0377, 4, insn_call_nn }, //"call Mmn"
+ { 0323, 0367, 2, insn_default }, //"out (n),a", "in a,(n)"
+ { 0335, 0337, 1, insn_adl_ddfd }, //DD/FD prefix
+ { 0351, 0377, 1, insn_jp_rr }, //"jp (hl)"
+ { 0355, 0377, 1, insn_adl_ed }, //ED prefix
+ { 0371, 0377, 1, insn_ld_sp_rr }, //"ld sp,hl"
+ { 0000, 0000, 1, insn_default } //others
+};
+
+/* ED prefix opcodes table.
+ Note the instruction length does include the ED prefix (+ 1 byte)
+*/
+static const struct insn_info
+ez80_ed_insn_table[] =
+{
+ /* eZ80 only instructions */
+ { 0002, 0366, 2, insn_default }, //"lea rr,ii+d"
+ { 0124, 0376, 2, insn_default }, //"lea ix,iy+d", "lea iy,ix+d"
+ { 0145, 0377, 2, insn_default }, //"pea ix+d"
+ { 0146, 0377, 2, insn_default }, //"pea iy+d"
+ { 0164, 0377, 2, insn_default }, //"tstio n"
+ /* Z180/eZ80 only instructions */
+ { 0060, 0376, 1, insn_default }, //not an instruction
+ { 0000, 0306, 2, insn_default }, //"in0 r,(n)", "out0 (n),r"
+ { 0144, 0377, 2, insn_default }, //"tst a, n"
+ /* common instructions */
+ { 0173, 0377, 3, insn_ld_sp_6nn9 }, //"ld sp,(nn)"
+ { 0103, 0307, 3, insn_default }, //"ld (nn),rr", "ld rr,(nn)"
+ { 0105, 0317, 1, insn_ret }, //"retn", "reti"
+ { 0000, 0000, 1, insn_default }
+};
+
+static const struct insn_info
+ez80_adl_ed_insn_table[] =
+{
+ { 0002, 0366, 2, insn_default }, //"lea rr,ii+d"
+ { 0124, 0376, 2, insn_default }, //"lea ix,iy+d", "lea iy,ix+d"
+ { 0145, 0377, 2, insn_default }, //"pea ix+d"
+ { 0146, 0377, 2, insn_default }, //"pea iy+d"
+ { 0164, 0377, 2, insn_default }, //"tstio n"
+ { 0060, 0376, 1, insn_default }, //not an instruction
+ { 0000, 0306, 2, insn_default }, //"in0 r,(n)", "out0 (n),r"
+ { 0144, 0377, 2, insn_default }, //"tst a, n"
+ { 0173, 0377, 4, insn_ld_sp_6nn9 }, //"ld sp,(nn)"
+ { 0103, 0307, 4, insn_default }, //"ld (nn),rr", "ld rr,(nn)"
+ { 0105, 0317, 1, insn_ret }, //"retn", "reti"
+ { 0000, 0000, 1, insn_default }
+};
+
+/* table for FD and DD prefixed instructions */
+static const struct insn_info
+ez80_ddfd_insn_table[] =
+{
+ /* ez80 only instructions */
+ { 0007, 0307, 2, insn_default }, //"ld rr,(ii+d)"
+ { 0061, 0377, 2, insn_default }, //"ld ii,(ii+d)"
+ /* common instructions */
+ { 0011, 0367, 2, insn_default }, //"add ii,rr"
+ { 0041, 0377, 3, insn_default }, //"ld ii,nn"
+ { 0042, 0367, 3, insn_default }, //"ld (nn),ii", "ld ii,(nn)"
+ { 0043, 0367, 1, insn_default }, //"inc ii", "dec ii"
+ { 0044, 0366, 1, insn_default }, //"inc/dec iih/iil"
+ { 0046, 0367, 2, insn_default }, //"ld iih,n", "ld iil,n"
+ { 0064, 0376, 2, insn_default }, //"inc (ii+d)", "dec (ii+d)"
+ { 0066, 0377, 2, insn_default }, //"ld (ii+d),n"
+ { 0166, 0377, 0, insn_default }, //not an instruction
+ { 0160, 0370, 2, insn_default }, //"ld (ii+d),r"
+ { 0104, 0306, 1, insn_default }, //"ld r,iih", "ld r,iil"
+ { 0106, 0307, 2, insn_default }, //"ld r,(ii+d)"
+ { 0140, 0360, 1, insn_default }, //"ld iih,r", "ld iil,r"
+ { 0204, 0306, 1, insn_default }, //"alu_op a,iih", "alu_op a,iil"
+ { 0206, 0307, 2, insn_default }, //"alu_op a,(ii+d)"
+ { 0313, 0377, 3, insn_default }, //DD/FD CB dd oo instructions
+ { 0335, 0337, 0, insn_force_nop}, //double DD/FD prefix, exec DD/FD as NOP
+ { 0341, 0373, 1, insn_default }, //"pop ii", "push ii"
+ { 0343, 0377, 1, insn_default }, //"ex (sp),ii"
+ { 0351, 0377, 1, insn_jp_rr }, //"jp (ii)"
+ { 0371, 0377, 1, insn_ld_sp_rr}, //"ld sp,ii"
+ { 0000, 0000, 0, insn_default } //not an instruction, exec DD/FD as NOP
+};
+
+static const struct insn_info
+ez80_adl_ddfd_insn_table[] =
+{
+ { 0007, 0307, 2, insn_default }, //"ld rr,(ii+d)"
+ { 0061, 0377, 2, insn_default }, //"ld ii,(ii+d)"
+ { 0011, 0367, 1, insn_default }, //"add ii,rr"
+ { 0041, 0377, 4, insn_default }, //"ld ii,nn"
+ { 0042, 0367, 4, insn_default }, //"ld (nn),ii", "ld ii,(nn)"
+ { 0043, 0367, 1, insn_default }, //"inc ii", "dec ii"
+ { 0044, 0366, 1, insn_default }, //"inc/dec iih/iil"
+ { 0046, 0367, 2, insn_default }, //"ld iih,n", "ld iil,n"
+ { 0064, 0376, 2, insn_default }, //"inc (ii+d)", "dec (ii+d)"
+ { 0066, 0377, 3, insn_default }, //"ld (ii+d),n"
+ { 0166, 0377, 0, insn_default }, //not an instruction
+ { 0160, 0370, 2, insn_default }, //"ld (ii+d),r"
+ { 0104, 0306, 1, insn_default }, //"ld r,iih", "ld r,iil"
+ { 0106, 0307, 2, insn_default }, //"ld r,(ii+d)"
+ { 0140, 0360, 1, insn_default }, //"ld iih,r", "ld iil,r"
+ { 0204, 0306, 1, insn_default }, //"alu_op a,iih", "alu_op a,iil"
+ { 0206, 0307, 2, insn_default }, //"alu_op a,(ii+d)"
+ { 0313, 0377, 3, insn_default }, //DD/FD CB dd oo instructions
+ { 0335, 0337, 0, insn_force_nop}, //double DD/FD prefix, exec DD/FD as NOP
+ { 0341, 0373, 1, insn_default }, //"pop ii", "push ii"
+ { 0343, 0377, 1, insn_default }, //"ex (sp),ii"
+ { 0351, 0377, 1, insn_jp_rr }, //"jp (ii)"
+ { 0371, 0377, 1, insn_ld_sp_rr}, //"ld sp,ii"
+ { 0000, 0000, 0, insn_default } //not an instruction, exec DD/FD as NOP
+};
+
+/* Return pointer to instruction information structure corresponded to opcode
+ in buf. */
+static const struct insn_info *
+z80_get_insn_info (struct gdbarch *gdbarch, const gdb_byte *buf, int *size)
+{
+ int code;
+ const struct insn_info *info;
+ unsigned long mach = gdbarch_bfd_arch_info (gdbarch)->mach;
+ *size = 0;
+ switch (mach)
+ {
+ case bfd_mach_ez80_z80:
+ info = &ez80_main_insn_table[4]; /* skip force_nops */
+ break;
+ case bfd_mach_ez80_adl:
+ info = &ez80_adl_main_insn_table[4]; /* skip force_nops */
+ break;
+ default:
+ info = &ez80_main_insn_table[8]; /* skip eZ80 prefices and force_nops */
+ break;
+ }
+ do
+ {
+ for (; ((code = buf[*size]) & info->mask) != info->code; ++info)
+ ;
+ *size += info->size;
+ /* process instruction type */
+ switch (info->type)
+ {
+ case insn_z80:
+ if (mach == bfd_mach_ez80_z80 || mach == bfd_mach_ez80_adl)
+ info = &ez80_main_insn_table[0];
+ else
+ info = &ez80_main_insn_table[8];
+ break;
+ case insn_adl:
+ info = &ez80_adl_main_insn_table[0];
+ break;
+ /* These two (for GameBoy Z80 & Z80 Next CPUs) haven't been tested.
+
+ case bfd_mach_gbz80:
+ info = &gbz80_main_insn_table[0];
+ break;
+ case bfd_mach_z80n:
+ info = &z80n_main_insn_table[0];
+ break;
+ */
+ case insn_z80_ddfd:
+ if (mach == bfd_mach_ez80_z80 || mach == bfd_mach_ez80_adl)
+ info = &ez80_ddfd_insn_table[0];
+ else
+ info = &ez80_ddfd_insn_table[2];
+ break;
+ case insn_adl_ddfd:
+ info = &ez80_adl_ddfd_insn_table[0];
+ break;
+ case insn_z80_ed:
+ info = &ez80_ed_insn_table[0];
+ break;
+ case insn_adl_ed:
+ info = &ez80_adl_ed_insn_table[0];
+ break;
+ case insn_force_nop:
+ return NULL;
+ default:
+ return info;
+ }
+ }
+ while (1);
+}
+
+extern initialize_file_ftype _initialize_z80_tdep;
+
+void
+_initialize_z80_tdep ()
+{
+ register_gdbarch_init (bfd_arch_z80, z80_gdbarch_init);
+ initialize_tdesc_z80 ();
+}