[v5] Add basic Z80 CPU support

Message ID 9a541e64-a21e-67cf-3242-62c0f1992c25@polymtl.ca
State New
Headers show
Series
  • [v5] Add basic Z80 CPU support
Related show

Commit Message

Simon Marchi via Gdb-patches July 15, 2021, 2:29 a.m.
Hi Sergey (and others),

This is what I would push, let me know if that looks good to you.

Thanks,

Simon

From 320750644135ee83557e0252c3e18e1b51f6681b Mon Sep 17 00:00:00 2001
From: Sergey Belyashov <Sergey.Belyashov@gmail.com>

Date: Fri, 25 Sep 2020 14:40:42 +0300
Subject: [PATCH v5] Add basic Z80 CPU support

Supported ISAs:
- Z80 (all undocumented instructions)
- Z180
- eZ80 (Z80 mode only)

Datasheets:
Z80: https://www.zilog.com/manage_directlink.php?filepath=docs/z80/um0080&extn=.pdf
Z180: https://www.zilog.com/manage_directlink.php?filepath=docs/z180/ps0140&extn=.pdf
eZ80: http://www.zilog.com/force_download.php?filepath=YUhSMGNEb3ZMM2QzZHk1NmFXeHZaeTVqYjIwdlpHOWpjeTlWVFRBd056Y3VjR1Jt

To debug Z80 programs using GDB you must configure and embed
z80-stub.c to your program (SDCC compiler is required). Or
you may use some simulator with GDB support.

gdb/ChangeLog:

	* Makefile.in (ALL_TARGET_OBS): Add z80-tdep.c.
	* NEWS: Mention z80 support.
	* configure.tgt: Handle z80*.
	* features/Makefile (XMLTOC): Add z80.xml.
	* features/z80-cpu.xml: New.
	* features/z80.c: Generate.
	* features/z80.xml: New.
	* z80-tdep.c: New file.
	* z80-tdep.h: New file.

gdb/stubs/ChangeLog:

	* z80-stub.c: New file.

Change-Id: Id0b7a6e210c3f93c6853c5e3031b7bcee47d0db9
---
 gdb/Makefile.in          |    3 +-
 gdb/NEWS                 |    1 +
 gdb/configure.tgt        |    4 +
 gdb/features/Makefile    |    3 +-
 gdb/features/z80-cpu.xml |   33 +
 gdb/features/z80.c       |   44 ++
 gdb/features/z80.xml     |   12 +
 gdb/stubs/z80-stub.c     | 1355 +++++++++++++++++++++++++++++++++++
 gdb/z80-tdep.c           | 1461 ++++++++++++++++++++++++++++++++++++++
 gdb/z80-tdep.h           |   52 ++
 10 files changed, 2966 insertions(+), 2 deletions(-)
 create mode 100644 gdb/features/z80-cpu.xml
 create mode 100644 gdb/features/z80.c
 create mode 100644 gdb/features/z80.xml
 create mode 100644 gdb/stubs/z80-stub.c
 create mode 100644 gdb/z80-tdep.c
 create mode 100644 gdb/z80-tdep.h

-- 
2.32.0

Comments

Simon Marchi via Gdb-patches July 15, 2021, 7:19 a.m. | #1
Hi,
Looks good for me

чт, 15 июл. 2021 г., 05:29 Simon Marchi <simon.marchi@polymtl.ca>:

> Hi Sergey (and others),

>

> This is what I would push, let me know if that looks good to you.

>

> Thanks,

>

> Simon

>

> From 320750644135ee83557e0252c3e18e1b51f6681b Mon Sep 17 00:00:00 2001

> From: Sergey Belyashov <Sergey.Belyashov@gmail.com>

> Date: Fri, 25 Sep 2020 14:40:42 +0300

> Subject: [PATCH v5] Add basic Z80 CPU support

>

> Supported ISAs:

> - Z80 (all undocumented instructions)

> - Z180

> - eZ80 (Z80 mode only)

>

> Datasheets:

> Z80:

> https://www.zilog.com/manage_directlink.php?filepath=docs/z80/um0080&extn=.pdf

> Z180:

> https://www.zilog.com/manage_directlink.php?filepath=docs/z180/ps0140&extn=.pdf

> eZ80:

> http://www.zilog.com/force_download.php?filepath=YUhSMGNEb3ZMM2QzZHk1NmFXeHZaeTVqYjIwdlpHOWpjeTlWVFRBd056Y3VjR1Jt

>

> To debug Z80 programs using GDB you must configure and embed

> z80-stub.c to your program (SDCC compiler is required). Or

> you may use some simulator with GDB support.

>

> gdb/ChangeLog:

>

>         * Makefile.in (ALL_TARGET_OBS): Add z80-tdep.c.

>         * NEWS: Mention z80 support.

>         * configure.tgt: Handle z80*.

>         * features/Makefile (XMLTOC): Add z80.xml.

>         * features/z80-cpu.xml: New.

>         * features/z80.c: Generate.

>         * features/z80.xml: New.

>         * z80-tdep.c: New file.

>         * z80-tdep.h: New file.

>

> gdb/stubs/ChangeLog:

>

>         * z80-stub.c: New file.

>

> Change-Id: Id0b7a6e210c3f93c6853c5e3031b7bcee47d0db9

> ---

>  gdb/Makefile.in          |    3 +-

>  gdb/NEWS                 |    1 +

>  gdb/configure.tgt        |    4 +

>  gdb/features/Makefile    |    3 +-

>  gdb/features/z80-cpu.xml |   33 +

>  gdb/features/z80.c       |   44 ++

>  gdb/features/z80.xml     |   12 +

>  gdb/stubs/z80-stub.c     | 1355 +++++++++++++++++++++++++++++++++++

>  gdb/z80-tdep.c           | 1461 ++++++++++++++++++++++++++++++++++++++

>  gdb/z80-tdep.h           |   52 ++

>  10 files changed, 2966 insertions(+), 2 deletions(-)

>  create mode 100644 gdb/features/z80-cpu.xml

>  create mode 100644 gdb/features/z80.c

>  create mode 100644 gdb/features/z80.xml

>  create mode 100644 gdb/stubs/z80-stub.c

>  create mode 100644 gdb/z80-tdep.c

>  create mode 100644 gdb/z80-tdep.h

>

> diff --git a/gdb/Makefile.in b/gdb/Makefile.in

> index 2274b9b6a61a..73a1bf83c858 100644

> --- a/gdb/Makefile.in

> +++ b/gdb/Makefile.in

> @@ -853,7 +853,8 @@ ALL_TARGET_OBS = \

>         xstormy16-tdep.o \

>         xtensa-config.o \

>         xtensa-linux-tdep.o \

> -       xtensa-tdep.o

> +       xtensa-tdep.o \

> +       z80-tdep.o

>

>  # The following native-target dependent variables are defined on

>  # configure.nat.

> diff --git a/gdb/NEWS b/gdb/NEWS

> index 1fea2f56ff69..9560710dd4fe 100644

> --- a/gdb/NEWS

> +++ b/gdb/NEWS

> @@ -426,6 +426,7 @@ alias [-a] [--] ALIAS = COMMAND [DEFAULT-ARGS...]

>

>  GNU/Linux/RISC-V (gdbserver)   riscv*-*-linux*

>  BPF                            bpf-unknown-none

> +Z80                            z80-unknown-*

>

>  * Python API

>

> diff --git a/gdb/configure.tgt b/gdb/configure.tgt

> index 643973917fe0..97a5a57c3788 100644

> --- a/gdb/configure.tgt

> +++ b/gdb/configure.tgt

> @@ -761,6 +761,10 @@ xtensa*-*-*linux*)

>         # Target: GNU/Linux Xtensa

>         gdb_target_obs="xtensa-linux-tdep.o symfile-mem.o linux-tdep.o"

>         ;;

> +z80*)

> +       # Target: Z80

> +       gdb_target_obs="z80-tdep.o"

> +       ;;

>

>  esac

>

> diff --git a/gdb/features/Makefile b/gdb/features/Makefile

> index 522ad58aab0f..ded8c3bb9da4 100644

> --- a/gdb/features/Makefile

> +++ b/gdb/features/Makefile

> @@ -170,7 +170,8 @@ XMLTOC = \

>         s390x-tevx-linux64.xml \

>         s390x-vx-linux64.xml \

>         s390-gs-linux64.xml \

> -       s390x-gs-linux64.xml

> +       s390x-gs-linux64.xml \

> +       z80.xml

>

>  TDESC_CFILES = $(patsubst %.xml,%.c,$(XMLTOC))

>  GDB = false

> diff --git a/gdb/features/z80-cpu.xml b/gdb/features/z80-cpu.xml

> new file mode 100644

> index 000000000000..98498b1bcc13

> --- /dev/null

> +++ b/gdb/features/z80-cpu.xml

> @@ -0,0 +1,33 @@

> +<?xml version="1.0"?>

> +<!-- Copyright (C) 2020 Free Software Foundation, Inc.

> +

> +     Copying and distribution of this file, with or without modification,

> +     are permitted in any medium without royalty provided the copyright

> +     notice and this notice are preserved.  -->

> +

> +<!DOCTYPE feature SYSTEM "gdb-target.dtd">

> +<feature name="org.gnu.gdb.z80.cpu">

> +  <flags id="af_flags" size="2">

> +    <field name="C" start="0" end="0"/>

> +    <field name="N" start="1" end="1"/>

> +    <field name="P/V" start="2" end="2"/>

> +    <field name="F3" start="3" end="3"/>

> +    <field name="H" start="4" end="4"/>

> +    <field name="F5" start="5" end="5"/>

> +    <field name="Z" start="6" end="6"/>

> +    <field name="S" start="7" end="7"/>

> +  </flags>

> +  <reg name="af" bitsize="16" type="af_flags"/>

> +  <reg name="bc" bitsize="16" type="uint16"/>

> +  <reg name="de" bitsize="16" type="data_ptr"/>

> +  <reg name="hl" bitsize="16" type="data_ptr"/>

> +  <reg name="sp" bitsize="16" type="data_ptr" />

> +  <reg name="pc" bitsize="32" type="code_ptr" />

> +  <reg name="ix" bitsize="16" type="data_ptr"/>

> +  <reg name="iy" bitsize="16" type="data_ptr"/>

> +  <reg name="af'" bitsize="16" type="af_flags"/>

> +  <reg name="bc'" bitsize="16" type="uint16"/>

> +  <reg name="de'" bitsize="16" type="data_ptr"/>

> +  <reg name="hl'" bitsize="16" type="data_ptr"/>

> +  <reg name="ir" bitsize="16" type="uint16"/>

> +</feature>

> diff --git a/gdb/features/z80.c b/gdb/features/z80.c

> new file mode 100644

> index 000000000000..944b563aca47

> --- /dev/null

> +++ b/gdb/features/z80.c

> @@ -0,0 +1,44 @@

> +/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:

> +  Original: z80.xml */

> +

> +#include "defs.h"

> +#include "osabi.h"

> +#include "target-descriptions.h"

> +

> +struct target_desc *tdesc_z80;

> +static void

> +initialize_tdesc_z80 (void)

> +{

> +  target_desc_up result = allocate_target_description ();

> +  set_tdesc_architecture (result.get (), bfd_scan_arch ("z80"));

> +

> +  struct tdesc_feature *feature;

> +

> +  feature = tdesc_create_feature (result.get (), "org.gnu.gdb.z80.cpu");

> +  tdesc_type_with_fields *type_with_fields;

> +  type_with_fields = tdesc_create_flags (feature, "af_flags", 2);

> +  tdesc_add_flag (type_with_fields, 0, "C");

> +  tdesc_add_flag (type_with_fields, 1, "N");

> +  tdesc_add_flag (type_with_fields, 2, "P/V");

> +  tdesc_add_flag (type_with_fields, 3, "F3");

> +  tdesc_add_flag (type_with_fields, 4, "H");

> +  tdesc_add_flag (type_with_fields, 5, "F5");

> +  tdesc_add_flag (type_with_fields, 6, "Z");

> +  tdesc_add_flag (type_with_fields, 7, "S");

> +

> +  tdesc_create_reg (feature, "af", 0, 1, NULL, 16, "af_flags");

> +  tdesc_create_reg (feature, "bc", 1, 1, NULL, 16, "uint16");

> +  tdesc_create_reg (feature, "de", 2, 1, NULL, 16, "data_ptr");

> +  tdesc_create_reg (feature, "hl", 3, 1, NULL, 16, "data_ptr");

> +  tdesc_create_reg (feature, "sp", 4, 1, NULL, 16, "data_ptr");

> +  tdesc_create_reg (feature, "pc", 5, 1, NULL, 32, "code_ptr");

> +  tdesc_create_reg (feature, "ix", 6, 1, NULL, 16, "data_ptr");

> +  tdesc_create_reg (feature, "iy", 7, 1, NULL, 16, "data_ptr");

> +  tdesc_create_reg (feature, "af'", 8, 1, NULL, 16, "af_flags");

> +  tdesc_create_reg (feature, "bc'", 9, 1, NULL, 16, "uint16");

> +  tdesc_create_reg (feature, "de'", 10, 1, NULL, 16, "data_ptr");

> +  tdesc_create_reg (feature, "hl'", 11, 1, NULL, 16, "data_ptr");

> +  tdesc_create_reg (feature, "ir", 12, 1, NULL, 16, "uint16");

> +

> +  tdesc_z80 = result.release ();

> +}

> diff --git a/gdb/features/z80.xml b/gdb/features/z80.xml

> new file mode 100644

> index 000000000000..238687a127e2

> --- /dev/null

> +++ b/gdb/features/z80.xml

> @@ -0,0 +1,12 @@

> +<?xml version="1.0"?>

> +<!-- Copyright (C) 2020 Free Software Foundation, Inc.

> +

> +     Copying and distribution of this file, with or without modification,

> +     are permitted in any medium without royalty provided the copyright

> +     notice and this notice are preserved.  -->

> +

> +<!DOCTYPE target SYSTEM "gdb-target.dtd">

> +<target>

> +  <architecture>z80</architecture>

> +  <xi:include href="z80-cpu.xml"/>

> +</target>

> diff --git a/gdb/stubs/z80-stub.c b/gdb/stubs/z80-stub.c

> new file mode 100644

> index 000000000000..0ec128fbe6a6

> --- /dev/null

> +++ b/gdb/stubs/z80-stub.c

> @@ -0,0 +1,1355 @@

> +/* Debug stub for Z80.

> +

> +   Copyright (C) 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/>.

> */

> +

> +/* Usage:

> +  1. Copy this file to project directory

> +  2. Configure it commenting/uncommenting macros below or define

> DBG_CONFIGURED

> +     and all required macros and then include this file to one of your

> C-source

> +     files.

> +  3. Implement getDebugChar() and putDebugChar(), functions must not

> return

> +     until data received or sent.

> +  4. Implement all optional functions used to toggle

> breakpoints/watchpoints,

> +     if supported. Do not write fuctions to toggle software breakpoints if

> +     you unsure (GDB will do itself).

> +  5. Implement serial port initialization routine called at program start.

> +  6. Add necessary debugger entry points to your program, for example:

> +       .org 0x08       ;RST 8 handler

> +       jp _debug_swbreak

> +       ...

> +       .org    0x66    ;NMI handler

> +       jp      _debug_nmi

> +       ...

> +       main_loop:

> +       halt

> +       call    isDbgInterrupt

> +       jr      z,101$

> +       ld      hl, 2   ;EX_SIGINT

> +       push    hl

> +       call    _debug_exception

> +       101$:

> +       ...

> +  7. Compile file using SDCC (supported ports are: z80, z180, z80n, gbz80

> and

> +     ez80_z80), do not use --peep-asm option. For example:

> +       $ sdcc -mz80 --opt-code-size --max-allocs-per-node 50000 z80-stub.c

> +*/

>

> +/******************************************************************************\

> +                            Configuration

>

> +\******************************************************************************/

> +#ifndef DBG_CONFIGURED

> +/* Uncomment this line, if stub size is critical for you */

> +//#define DBG_MIN_SIZE

> +

> +/* Comment this line out if software breakpoints are unsupported.

> +   If you have special function to toggle software breakpoints, then

> provide

> +   here name of these function. Expected prototype:

> +       int toggle_swbreak(int set, void *addr);

> +   function must return 0 on success. */

> +//#define DBG_SWBREAK toggle_swbreak

> +#define DBG_SWBREAK

> +

> +/* Define if one of standard RST handlers is used as software

> +   breakpoint entry point */

> +//#define DBG_SWBREAK_RST 0x08

> +

> +/* if platform supports hardware breakpoints then define following macro

> +   by name of function. Fuction must have next prototype:

> +     int toggle_hwbreak(int set, void *addr);

> +   function must return 0 on success. */

> +//#define DBG_HWBREAK toggle_hwbreak

> +

> +/* if platform supports hardware watchpoints then define all or some of

> +   following macros by names of functions. Fuctions prototypes:

> +     int toggle_watch(int set, void *addr, size_t size);  // memory write

> watch

> +     int toggle_rwatch(int set, void *addr, size_t size); // memory read

> watch

> +     int toggle_awatch(int set, void *addr, size_t size); // memory

> access watch

> +   function must return 0 on success. */

> +//#define DBG_WWATCH toggle_watch

> +//#define DBG_RWATCH toggle_rwatch

> +//#define DBG_AWATCH toggle_awatch

> +

> +/* Size of hardware breakpoint. Required to correct PC. */

> +#define DBG_HWBREAK_SIZE 0

> +

> +/* Define following macro if you need custom memory read/write routine.

> +   Function should return non-zero on success, and zero on failure

> +   (for example, write to ROM area).

> +   Useful with overlays (bank switching).

> +   Do not forget to define:

> +   _ovly_table - overlay table

> +   _novlys - number of items in _ovly_table

> +   or

> +   _ovly_region_table - overlay regions table

> +   _novly_regions - number of items in _ovly_region_table

> +

> +   _ovly_debug_prepare - function is called before overlay mapping

> +   _ovly_debug_event - function is called after overlay mapping

> + */

> +//#define DBG_MEMCPY memcpy

> +

> +/* define dedicated stack size if required */

> +//#define DBG_STACK_SIZE 256

> +

> +/* max GDB packet size

> +   should be much less that DBG_STACK_SIZE because it will be allocated

> on stack

> +*/

> +#define DBG_PACKET_SIZE 150

> +

> +/* Uncomment if required to use trampoline when resuming operation.

> +   Useful with dedicated stack when stack pointer do not point to the

> stack or

> +   stack is not writable */

> +//#define DBG_USE_TRAMPOLINE

> +

> +/* Uncomment following macro to enable debug printing to debugger console

> */

> +//#define DBG_PRINT

> +

> +#define DBG_NMI_EX EX_HWBREAK

> +#define DBG_INT_EX EX_SIGINT

> +

> +/* Define following macro to statement, which will be exectuted after

> entering to

> +   stub_main function. Statement should include semicolon. */

> +//#define DBG_ENTER debug_enter();

> +

> +/* Define following macro to instruction(s), which will be execute before

> return

> +   control to the program. It is useful when gdb-stub is placed in one of

> overlays.

> +   This procedure must not change any register. On top of stack before

> invocation

> +   will be return address of the program. */

> +//#define DBG_RESUME jp _restore_bank

> +

> +/* Define following macro to the string containing memory map definition

> XML.

> +   GDB will use it to select proper breakpoint type (HW or SW). */

> +/*#define DBG_MEMORY_MAP "\

> +<memory-map>\

> +       <memory type=\"rom\" start=\"0x0000\" length=\"0x4000\"/>\

> +<!--   <memory type=\"flash\" start=\"0x4000\" length=\"0x4000\">\

> +               <property name=\"blocksize\">128</property>\

> +       </memory> -->\

> +       <memory type=\"ram\" start=\"0x8000\" length=\"0x8000\"/>\

> +</memory-map>\

> +"

> +*/

> +#endif /* DBG_CONFIGURED */

>

> +/******************************************************************************\

> +                            Public Interface

>

> +\******************************************************************************/

> +

> +/* Enter to debug mode from software or hardware breakpoint.

> +   Assume address of next instruction after breakpoint call is on top of

> stack.

> +   Do JP _debug_swbreak or JP _debug_hwbreak from RST handler, for

> example.

> + */

> +void debug_swbreak (void);

> +void debug_hwbreak (void);

> +

> +/* Jump to this function from NMI handler. Just replace RETN instruction

> by

> +   JP _debug_nmi

> +   Use if NMI detects request to enter to debug mode.

> + */

> +void debug_nmi (void);

> +

> +/* Jump to this function from INT handler. Just replace EI+RETI

> instructions by

> +   JP _debug_int

> +   Use if INT detects request to enter to debug mode.

> + */

> +void debug_int (void);

> +

> +#define EX_SWBREAK     0       /* sw breakpoint */

> +#define EX_HWBREAK     -1      /* hw breakpoint */

> +#define EX_WWATCH      -2      /* memory write watch */

> +#define EX_RWATCH      -3      /* memory read watch */

> +#define EX_AWATCH      -4      /* memory access watch */

> +#define EX_SIGINT      2

> +#define EX_SIGTRAP     5

> +#define EX_SIGABRT     6

> +#define EX_SIGBUS      10

> +#define EX_SIGSEGV     11

> +/* or any standard *nix signal value */

> +

> +/* Enter to debug mode (after receiving BREAK from GDB, for example)

> + * Assume:

> + *   program PC in (SP+0)

> + *   caught signal in (SP+2)

> + *   program SP is SP+4

> + */

> +void debug_exception (int ex);

> +

> +/* Prints to debugger console. */

> +void debug_print(const char *str);

>

> +/******************************************************************************\

> +                             Required functions

>

> +\******************************************************************************/

> +

> +extern int getDebugChar (void);

> +extern void putDebugChar (int ch);

> +

> +#ifdef DBG_SWBREAK

> +#define DO_EXPAND(VAL)  VAL ## 123456

> +#define EXPAND(VAL)     DO_EXPAND(VAL)

> +

> +#if EXPAND(DBG_SWBREAK) != 123456

> +#define DBG_SWBREAK_PROC DBG_SWBREAK

> +extern int DBG_SWBREAK(int set, void *addr);

> +#endif

> +

> +#undef EXPAND

> +#undef DO_EXPAND

> +#endif /* DBG_SWBREAK */

> +

> +#ifdef DBG_HWBREAK

> +extern int DBG_HWBREAK(int set, void *addr);

> +#endif

> +

> +#ifdef DBG_MEMCPY

> +extern void* DBG_MEMCPY (void *dest, const void *src, unsigned n);

> +#endif

> +

> +#ifdef DBG_WWATCH

> +extern int DBG_WWATCH(int set, void *addr, unsigned size);

> +#endif

> +

> +#ifdef DBG_RWATCH

> +extern int DBG_RWATCH(int set, void *addr, unsigned size);

> +#endif

> +

> +#ifdef DBG_AWATCH

> +extern int DBG_AWATCH(int set, void *addr, unsigned size);

> +#endif

> +

>

> +/******************************************************************************\

> +                              IMPLEMENTATION

>

> +\******************************************************************************/

> +

> +#include <string.h>

> +

> +#ifndef NULL

> +# define NULL (void*)0

> +#endif

> +

> +typedef unsigned char byte;

> +typedef unsigned short word;

> +

> +/* CPU state */

> +#ifdef __SDCC_ez80_adl

> +# define REG_SIZE 3

> +#else

> +# define REG_SIZE 2

> +#endif /* __SDCC_ez80_adl */

> +

> +#define R_AF    (0*REG_SIZE)

> +#define R_BC    (1*REG_SIZE)

> +#define R_DE    (2*REG_SIZE)

> +#define R_HL    (3*REG_SIZE)

> +#define R_SP    (4*REG_SIZE)

> +#define R_PC    (5*REG_SIZE)

> +

> +#ifndef __SDCC_gbz80

> +#define R_IX    (6*REG_SIZE)

> +#define R_IY    (7*REG_SIZE)

> +#define R_AF_   (8*REG_SIZE)

> +#define R_BC_   (9*REG_SIZE)

> +#define R_DE_   (10*REG_SIZE)

> +#define R_HL_   (11*REG_SIZE)

> +#define R_IR    (12*REG_SIZE)

> +

> +#ifdef __SDCC_ez80_adl

> +#define R_SPS   (13*REG_SIZE)

> +#define NUMREGBYTES (14*REG_SIZE)

> +#else

> +#define NUMREGBYTES (13*REG_SIZE)

> +#endif /* __SDCC_ez80_adl */

> +#else

> +#define NUMREGBYTES (6*REG_SIZE)

> +#define FASTCALL

> +#endif /*__SDCC_gbz80 */

> +static byte state[NUMREGBYTES];

> +

> +#if DBG_PACKET_SIZE < (NUMREGBYTES*2+5)

> +#error "Too small DBG_PACKET_SIZE"

> +#endif

> +

> +#ifndef FASTCALL

> +#define FASTCALL __z88dk_fastcall

> +#endif

> +

> +/* dedicated stack */

> +#ifdef DBG_STACK_SIZE

> +

> +#define LOAD_SP        ld      sp, #_stack + DBG_STACK_SIZE

> +

> +static char stack[DBG_STACK_SIZE];

> +

> +#else

> +

> +#undef DBG_USE_TRAMPOLINE

> +#define LOAD_SP

> +

> +#endif

> +

> +#ifndef DBG_ENTER

> +#define DBG_ENTER

> +#endif

> +

> +#ifndef DBG_RESUME

> +#define DBG_RESUME ret

> +#endif

> +

> +static signed char sigval;

> +

> +static void stub_main (int sigval, int pc_adj);

> +static char high_hex (byte v) FASTCALL;

> +static char low_hex (byte v) FASTCALL;

> +static char put_packet_info (const char *buffer) FASTCALL;

> +static void save_cpu_state (void);

> +static void rest_cpu_state (void);

> +

>

> +/******************************************************************************/

> +#ifdef DBG_SWBREAK

> +#ifdef DBG_SWBREAK_RST

> +#define DBG_SWBREAK_SIZE 1

> +#else

> +#define DBG_SWBREAK_SIZE 3

> +#endif

> +void

> +debug_swbreak (void) __naked

> +{

> +  __asm

> +       ld      (#_state + R_SP), sp

> +       LOAD_SP

> +       call    _save_cpu_state

> +       ld      hl, #-DBG_SWBREAK_SIZE

> +       push    hl

> +       ld      hl, #EX_SWBREAK

> +       push    hl

> +       call    _stub_main

> +       .globl  _break_handler

> +#ifdef DBG_SWBREAK_RST

> +_break_handler = DBG_SWBREAK_RST

> +#else

> +_break_handler = _debug_swbreak

> +#endif

> +  __endasm;

> +}

> +#endif /* DBG_SWBREAK */

>

> +/******************************************************************************/

> +#ifdef DBG_HWBREAK

> +#ifndef DBG_HWBREAK_SIZE

> +#define DBG_HWBREAK_SIZE 0

> +#endif /* DBG_HWBREAK_SIZE */

> +void

> +debug_hwbreak (void) __naked

> +{

> +  __asm

> +       ld      (#_state + R_SP), sp

> +       LOAD_SP

> +       call    _save_cpu_state

> +       ld      hl, #-DBG_HWBREAK_SIZE

> +       push    hl

> +       ld      hl, #EX_HWBREAK

> +       push    hl

> +       call    _stub_main

> +  __endasm;

> +}

> +#endif /* DBG_HWBREAK_SET */

>

> +/******************************************************************************/

> +void

> +debug_exception (int ex) __naked

> +{

> +  __asm

> +       ld      (#_state + R_SP), sp

> +       LOAD_SP

> +       call    _save_cpu_state

> +       ld      hl, #0

> +       push    hl

> +#ifdef __SDCC_gbz80

> +       ld      hl, #_state + R_SP

> +       ld      a, (hl+)

> +       ld      h, (hl)

> +       ld      l, a

> +#else

> +       ld      hl, (#_state + R_SP)

> +#endif

> +       inc     hl

> +       inc     hl

> +       ld      e, (hl)

> +       inc     hl

> +       ld      d, (hl)

> +       push    de

> +       call    _stub_main

> +  __endasm;

> +  (void)ex;

> +}

>

> +/******************************************************************************/

> +#ifndef __SDCC_gbz80

> +void

> +debug_nmi(void) __naked

> +{

> +  __asm

> +       ld      (#_state + R_SP), sp

> +       LOAD_SP

> +       call    _save_cpu_state

> +       ld      hl, #0  ;pc_adj

> +       push    hl

> +       ld      hl, #DBG_NMI_EX

> +       push    hl

> +       ld      hl, #_stub_main

> +       push    hl

> +       push    hl

> +       retn

> +  __endasm;

> +}

> +#endif

>

> +/******************************************************************************/

> +void

> +debug_int(void) __naked

> +{

> +  __asm

> +       ld      (#_state + R_SP), sp

> +       LOAD_SP

> +       call    _save_cpu_state

> +       ld      hl, #0  ;pc_adj

> +       push    hl

> +       ld      hl, #DBG_INT_EX

> +       push    hl

> +       ld      hl, #_stub_main

> +       push    hl

> +       push    hl

> +       ei

> +       reti

> +  __endasm;

> +}

>

> +/******************************************************************************/

> +#ifdef DBG_PRINT

> +void

> +debug_print(const char *str)

> +{

> +  putDebugChar ('$');

> +  putDebugChar ('O');

> +  char csum = 'O';

> +  for (; *str != '\0'; )

> +    {

> +      char c = high_hex (*str);

> +      csum += c;

> +      putDebugChar (c);

> +      c = low_hex (*str++);

> +      csum += c;

> +      putDebugChar (c);

> +    }

> +  putDebugChar ('#');

> +  putDebugChar (high_hex (csum));

> +  putDebugChar (low_hex (csum));

> +}

> +#endif /* DBG_PRINT */

>

> +/******************************************************************************/

> +static void store_pc_sp (int pc_adj) FASTCALL;

> +#define get_reg_value(mem) (*(void* const*)(mem))

> +#define set_reg_value(mem,val) do { (*(void**)(mem) = (val)); } while (0)

> +static char* byte2hex(char *buf, byte val);

> +static int hex2int (const char **buf) FASTCALL;

> +static char* int2hex (char *buf, int v);

> +static void get_packet (char *buffer);

> +static void put_packet (const char *buffer);

> +static char process (char *buffer) FASTCALL;

> +static void rest_cpu_state (void);

> +

> +static void

> +stub_main (int ex, int pc_adj)

> +{

> +  char buffer[DBG_PACKET_SIZE+1];

> +  sigval = (signed char)ex;

> +  store_pc_sp (pc_adj);

> +

> +  DBG_ENTER

> +

> +  /* after starting gdb_stub must always return stop reason */

> +  *buffer = '?';

> +  for (; process (buffer);)

> +    {

> +      put_packet (buffer);

> +      get_packet (buffer);

> +    }

> +  put_packet (buffer);

> +  rest_cpu_state ();

> +}

> +

> +static void

> +get_packet (char *buffer)

> +{

> +  byte csum;

> +  char ch;

> +  char *p;

> +  byte esc;

> +#if DBG_PACKET_SIZE <= 256

> +  byte count; /* it is OK to use up to 256 here */

> +#else

> +  unsigned count;

> +#endif

> +  for (;; putDebugChar ('-'))

> +    {

> +      /* wait for packet start character */

> +      while (getDebugChar () != '$');

> +retry:

> +      csum = 0;

> +      esc = 0;

> +      p = buffer;

> +      count = DBG_PACKET_SIZE;

> +      do

> +       {

> +         ch = getDebugChar ();

> +         switch (ch)

> +           {

> +           case '$':

> +             goto retry;

> +           case '#':

> +             goto finish;

> +           case '}':

> +             esc = 0x20;

> +             break;

> +           default:

> +             *p++ = ch ^ esc;

> +             esc = 0;

> +             --count;

> +           }

> +         csum += ch;

> +       }

> +      while (count != 0);

> +finish:

> +      *p = '\0';

> +      if (ch != '#') /* packet is too large */

> +       continue;

> +      ch = getDebugChar ();

> +      if (ch != high_hex (csum))

> +       continue;

> +      ch = getDebugChar ();

> +      if (ch != low_hex (csum))

> +       continue;

> +      break;

> +    }

> +  putDebugChar ('+');

> +}

> +

> +static void

> +put_packet (const char *buffer)

> +{

> +  /*  $<packet info>#<checksum>. */

> +  for (;;)

> +    {

> +      putDebugChar ('$');

> +      char checksum = put_packet_info (buffer);

> +      putDebugChar ('#');

> +      putDebugChar (high_hex(checksum));

> +      putDebugChar (low_hex(checksum));

> +      for (;;)

> +       {

> +         char c = getDebugChar ();

> +         switch (c)

> +           {

> +           case '+': return;

> +           case '-': break;

> +           default:

> +             putDebugChar (c);

> +             continue;

> +           }

> +         break;

> +       }

> +    }

> +}

> +

> +static char

> +put_packet_info (const char *src) FASTCALL

> +{

> +  char ch;

> +  char checksum = 0;

> +  for (;;)

> +    {

> +      ch = *src++;

> +      if (ch == '\0')

> +       break;

> +      if (ch == '}' || ch == '*' || ch == '#' || ch == '$')

> +       {

> +         /* escape special characters */

> +         putDebugChar ('}');

> +         checksum += '}';

> +         ch ^= 0x20;

> +       }

> +      putDebugChar (ch);

> +      checksum += ch;

> +    }

> +  return checksum;

> +}

> +

> +static void

> +store_pc_sp (int pc_adj) FASTCALL

> +{

> +  byte *sp = get_reg_value (&state[R_SP]);

> +  byte *pc = get_reg_value (sp);

> +  pc += pc_adj;

> +  set_reg_value (&state[R_PC], pc);

> +  set_reg_value (&state[R_SP], sp + REG_SIZE);

> +}

> +

> +static char *mem2hex (char *buf, const byte *mem, unsigned bytes);

> +static char *hex2mem (byte *mem, const char *buf, unsigned bytes);

> +

> +/* Command processors. Takes pointer to buffer (begins from command

> symbol),

> +   modifies buffer, returns: -1 - empty response (ignore), 0 - success,

> +   positive: error code. */

> +

> +#ifdef DBG_MIN_SIZE

> +static signed char

> +process_question (char *p) FASTCALL

> +{

> +  signed char sig;

> +  *p++ = 'S';

> +  sig = sigval;

> +  if (sig <= 0)

> +    sig = EX_SIGTRAP;

> +  p = byte2hex (p, (byte)sig);

> +  *p = '\0';

> +  return 0;

> +}

> +#else /* DBG_MIN_SIZE */

> +static char *format_reg_value (char *p, unsigned reg_num, const byte

> *value);

> +

> +static signed char

> +process_question (char *p) FASTCALL

> +{

> +  signed char sig;

> +  *p++ = 'T';

> +  sig = sigval;

> +  if (sig <= 0)

> +    sig = EX_SIGTRAP;

> +  p = byte2hex (p, (byte)sig);

> +  p = format_reg_value(p, R_AF/REG_SIZE, &state[R_AF]);

> +  p = format_reg_value(p, R_SP/REG_SIZE, &state[R_SP]);

> +  p = format_reg_value(p, R_PC/REG_SIZE, &state[R_PC]);

> +#if defined(DBG_SWBREAK_PROC) || defined(DBG_HWBREAK) ||

> defined(DBG_WWATCH) || defined(DBG_RWATCH) || defined(DBG_AWATCH)

> +  const char *reason;

> +  unsigned addr = 0;

> +  switch (sigval)

> +    {

> +#ifdef DBG_SWBREAK_PROC

> +    case EX_SWBREAK:

> +      reason = "swbreak";

> +      break;

> +#endif

> +#ifdef DBG_HWBREAK

> +    case EX_HWBREAK:

> +      reason = "hwbreak";

> +      break;

> +#endif

> +#ifdef DBG_WWATCH

> +    case EX_WWATCH:

> +      reason = "watch";

> +      addr = 1;

> +      break;

> +#endif

> +#ifdef DBG_RWATCH

> +    case EX_RWATCH:

> +      reason = "rwatch";

> +      addr = 1;

> +      break;

> +#endif

> +#ifdef DBG_AWATCH

> +    case EX_AWATCH:

> +      reason = "awatch";

> +      addr = 1;

> +      break;

> +#endif

> +    default:

> +      goto finish;

> +    }

> +  while ((*p++ = *reason++))

> +    ;

> +  --p;

> +  *p++ = ':';

> +  if (addr != 0)

> +    p = int2hex(p, addr);

> +  *p++ = ';';

> +finish:

> +#endif /* DBG_HWBREAK, DBG_WWATCH, DBG_RWATCH, DBG_AWATCH */

> +  *p++ = '\0';

> +  return 0;

> +}

> +#endif /* DBG_MINSIZE */

> +

> +#define STRING2(x) #x

> +#define STRING1(x) STRING2(x)

> +#define STRING(x) STRING1(x)

> +#ifdef DBG_MEMORY_MAP

> +static void read_memory_map (char *buffer, unsigned offset, unsigned

> length);

> +#endif

> +

> +static signed char

> +process_q (char *buffer) FASTCALL

> +{

> +  char *p;

> +  if (memcmp (buffer + 1, "Supported", 9) == 0)

> +    {

> +      memcpy (buffer, "PacketSize=", 11);

> +      p = int2hex (&buffer[11], DBG_PACKET_SIZE);

> +#ifndef DBG_MIN_SIZE

> +#ifdef DBG_SWBREAK_PROC

> +      memcpy (p, ";swbreak+", 9);

> +      p += 9;

> +#endif

> +#ifdef DBG_HWBREAK

> +      memcpy (p, ";hwbreak+", 9);

> +      p += 9;

> +#endif

> +#endif /* DBG_MIN_SIZE */

> +

> +#ifdef DBG_MEMORY_MAP

> +      memcpy (p, ";qXfer:memory-map:read+", 23);

> +      p += 23;

> +#endif

> +      *p = '\0';

> +      return 0;

> +    }

> +#ifdef DBG_MEMORY_MAP

> +  if (memcmp (buffer + 1, "Xfer:memory-map:read:", 21) == 0)

> +    {

> +      p = strchr (buffer + 1 + 21, ':');

> +      if (p == NULL)

> +       return 1;

> +      ++p;

> +      unsigned offset = hex2int (&p);

> +      if (*p++ != ',')

> +       return 2;

> +      unsigned length = hex2int (&p);

> +      if (length == 0)

> +       return 3;

> +      if (length > DBG_PACKET_SIZE)

> +       return 4;

> +      read_memory_map (buffer, offset, length);

> +      return 0;

> +    }

> +#endif

> +#ifndef DBG_MIN_SIZE

> +  if (memcmp (&buffer[1], "Attached", 9) == 0)

> +    {

> +      /* Just report that GDB attached to existing process

> +        if it is not applicable for you, then send patches */

> +      memcpy(buffer, "1", 2);

> +      return 0;

> +    }

> +#endif /* DBG_MIN_SIZE */

> +  *buffer = '\0';

> +  return -1;

> +}

> +

> +static signed char

> +process_g (char *buffer) FASTCALL

> +{

> +  mem2hex (buffer, state, NUMREGBYTES);

> +  return 0;

> +}

> +

> +static signed char

> +process_G (char *buffer) FASTCALL

> +{

> +  hex2mem (state, &buffer[1], NUMREGBYTES);

> +  /* OK response */

> +  *buffer = '\0';

> +  return 0;

> +}

> +

> +static signed char

> +process_m (char *buffer) FASTCALL

> +{/* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */

> +  char *p = &buffer[1];

> +  byte *addr = (void*)hex2int(&p);

> +  if (*p++ != ',')

> +    return 1;

> +  unsigned len = (unsigned)hex2int(&p);

> +  if (len == 0)

> +    return 2;

> +  if (len > DBG_PACKET_SIZE/2)

> +    return 3;

> +  p = buffer;

> +#ifdef DBG_MEMCPY

> +  do

> +    {

> +      byte tmp[16];

> +      unsigned tlen = sizeof(tmp);

> +      if (tlen > len)

> +       tlen = len;

> +      if (!DBG_MEMCPY(tmp, addr, tlen))

> +       return 4;

> +      p = mem2hex (p, tmp, tlen);

> +      addr += tlen;

> +      len -= tlen;

> +    }

> +  while (len);

> +#else

> +  p = mem2hex (p, addr, len);

> +#endif

> +  return 0;

> +}

> +

> +static signed char

> +process_M (char *buffer) FASTCALL

> +{/* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */

> +  char *p = &buffer[1];

> +  byte *addr = (void*)hex2int(&p);

> +  if (*p != ',')

> +    return 1;

> +  ++p;

> +  unsigned len = (unsigned)hex2int(&p);

> +  if (*p++ != ':')

> +    return 2;

> +  if (len == 0)

> +    goto end;

> +  if (len*2 + (p - buffer) > DBG_PACKET_SIZE)

> +    return 3;

> +#ifdef DBG_MEMCPY

> +  do

> +    {

> +      byte tmp[16];

> +      unsigned tlen = sizeof(tmp);

> +      if (tlen > len)

> +       tlen = len;

> +      p = hex2mem (tmp, p, tlen);

> +      if (!DBG_MEMCPY(addr, tmp, tlen))

> +       return 4;

> +      addr += tlen;

> +       len -= tlen;

> +    }

> +  while (len);

> +#else

> +  hex2mem (addr, p, len);

> +#endif

> +end:

> +  /* OK response */

> +  *buffer = '\0';

> +  return 0;

> +}

> +

> +#ifndef DBG_MIN_SIZE

> +static signed char

> +process_X (char *buffer) FASTCALL

> +{/* XAA..AA,LLLL: Write LLLL binary bytes at address AA.AA return OK */

> +  char *p = &buffer[1];

> +  byte *addr = (void*)hex2int(&p);

> +  if (*p != ',')

> +    return 1;

> +  ++p;

> +  unsigned len = (unsigned)hex2int(&p);

> +  if (*p++ != ':')

> +    return 2;

> +  if (len == 0)

> +    goto end;

> +  if (len + (p - buffer) > DBG_PACKET_SIZE)

> +    return 3;

> +#ifdef DBG_MEMCPY

> +  if (!DBG_MEMCPY(addr, p, len))

> +    return 4;

> +#else

> +  memcpy (addr, p, len);

> +#endif

> +end:

> +  /* OK response */

> +  *buffer = '\0';

> +  return 0;

> +}

> +#else /* DBG_MIN_SIZE */

> +static signed char

> +process_X (char *buffer) FASTCALL

> +{

> +  (void)buffer;

> +  return -1;

> +}

> +#endif /* DBG_MIN_SIZE */

> +

> +static signed char

> +process_c (char *buffer) FASTCALL

> +{/* 'cAAAA' - Continue at address AAAA(optional) */

> +  const char *p = &buffer[1];

> +  if (*p != '\0')

> +    {

> +      void *addr = (void*)hex2int(&p);

> +      set_reg_value (&state[R_PC], addr);

> +    }

> +  rest_cpu_state ();

> +  return 0;

> +}

> +

> +static signed char

> +process_D (char *buffer) FASTCALL

> +{/* 'D' - detach the program: continue execution */

> +  *buffer = '\0';

> +  return -2;

> +}

> +

> +static signed char

> +process_k (char *buffer) FASTCALL

> +{/* 'k' - Kill the program */

> +  set_reg_value (&state[R_PC], 0);

> +  rest_cpu_state ();

> +  (void)buffer;

> +  return 0;

> +}

> +

> +static signed char

> +process_v (char *buffer) FASTCALL

> +{

> +#ifndef DBG_MIN_SIZE

> +  if (memcmp (&buffer[1], "Cont", 4) == 0)

> +    {

> +      if (buffer[5] == '?')

> +       {

> +         /* result response will be "vCont;c;C"; C action must be

> +            supported too, because GDB reguires at lease both of them */

> +         memcpy (&buffer[5], ";c;C", 5);

> +         return 0;

> +       }

> +      buffer[0] = '\0';

> +      if (buffer[5] == ';' && (buffer[6] == 'c' || buffer[6] == 'C'))

> +       return -2; /* resume execution */

> +      return 1;

> +  }

> +#endif /* DBG_MIN_SIZE */

> +  return -1;

> +}

> +

> +static signed char

> +process_zZ (char *buffer) FASTCALL

> +{ /* insert/remove breakpoint */

> +#if defined(DBG_SWBREAK_PROC) || defined(DBG_HWBREAK) || \

> +    defined(DBG_WWATCH) || defined(DBG_RWATCH) || defined(DBG_AWATCH)

> +  const byte set = (*buffer == 'Z');

> +  const char *p = &buffer[3];

> +  void *addr = (void*)hex2int(&p);

> +  if (*p != ',')

> +    return 1;

> +  p++;

> +  int kind = hex2int(&p);

> +  *buffer = '\0';

> +  switch (buffer[1])

> +    {

> +#ifdef DBG_SWBREAK_PROC

> +    case '0': /* sw break */

> +      return DBG_SWBREAK_PROC(set, addr);

> +#endif

> +#ifdef DBG_HWBREAK

> +    case '1': /* hw break */

> +      return DBG_HWBREAK(set, addr);

> +#endif

> +#ifdef DBG_WWATCH

> +    case '2': /* write watch */

> +      return DBG_WWATCH(set, addr, kind);

> +#endif

> +#ifdef DBG_RWATCH

> +    case '3': /* read watch */

> +      return DBG_RWATCH(set, addr, kind);

> +#endif

> +#ifdef DBG_AWATCH

> +    case '4': /* access watch */

> +      return DBG_AWATCH(set, addr, kind);

> +#endif

> +    default:; /* not supported */

> +    }

> +#endif

> +  (void)buffer;

> +  return -1;

> +}

> +

> +static signed char

> +do_process (char *buffer) FASTCALL

> +{

> +  switch (*buffer)

> +    {

> +    case '?': return process_question (buffer);

> +    case 'G': return process_G (buffer);

> +    case 'k': return process_k (buffer);

> +    case 'M': return process_M (buffer);

> +    case 'X': return process_X (buffer);

> +    case 'Z': return process_zZ (buffer);

> +    case 'c': return process_c (buffer);

> +    case 'D': return process_D (buffer);

> +    case 'g': return process_g (buffer);

> +    case 'm': return process_m (buffer);

> +    case 'q': return process_q (buffer);

> +    case 'v': return process_v (buffer);

> +    case 'z': return process_zZ (buffer);

> +    default:  return -1; /* empty response */

> +    }

> +}

> +

> +static char

> +process (char *buffer) FASTCALL

> +{

> +  signed char err = do_process (buffer);

> +  char *p = buffer;

> +  char ret = 1;

> +  if (err == -2)

> +    {

> +      ret = 0;

> +      err = 0;

> +    }

> +  if (err > 0)

> +    {

> +      *p++ = 'E';

> +      p = byte2hex (p, err);

> +      *p = '\0';

> +    }

> +  else if (err < 0)

> +    {

> +      *p = '\0';

> +    }

> +  else if (*p == '\0')

> +    memcpy(p, "OK", 3);

> +  return ret;

> +}

> +

> +static char *

> +byte2hex (char *p, byte v)

> +{

> +  *p++ = high_hex (v);

> +  *p++ = low_hex (v);

> +  return p;

> +}

> +

> +static signed char

> +hex2val (unsigned char hex) FASTCALL

> +{

> +  if (hex <= '9')

> +    return hex - '0';

> +  hex &= 0xdf; /* make uppercase */

> +  hex -= 'A' - 10;

> +  return (hex >= 10 && hex < 16) ? hex : -1;

> +}

> +

> +static int

> +hex2byte (const char *p) FASTCALL

> +{

> +  signed char h = hex2val (p[0]);

> +  signed char l = hex2val (p[1]);

> +  if (h < 0 || l < 0)

> +    return -1;

> +  return (byte)((byte)h << 4) | (byte)l;

> +}

> +

> +static int

> +hex2int (const char **buf) FASTCALL

> +{

> +  word r = 0;

> +  for (;; (*buf)++)

> +    {

> +      signed char a = hex2val(**buf);

> +      if (a < 0)

> +       break;

> +      r <<= 4;

> +      r += (byte)a;

> +    }

> +  return (int)r;

> +}

> +

> +static char *

> +int2hex (char *buf, int v)

> +{

> +  buf = byte2hex(buf, (word)v >> 8);

> +  return byte2hex(buf, (byte)v);

> +}

> +

> +static char

> +high_hex (byte v) FASTCALL

> +{

> +  return low_hex(v >> 4);

> +}

> +

> +static char

> +low_hex (byte v) FASTCALL

> +{

> +/*

> +  __asm

> +       ld      a, l

> +       and     a, #0x0f

> +       add     a, #0x90

> +       daa

> +       adc     a, #0x40

> +       daa

> +       ld      l, a

> +  __endasm;

> +  (void)v;

> +*/

> +  v &= 0x0f;

> +  v += '0';

> +  if (v < '9'+1)

> +    return v;

> +  return v + 'a' - '0' - 10;

> +}

> +

> +/* convert the memory, pointed to by mem into hex, placing result in buf

> */

> +/* return a pointer to the last char put in buf (null) */

> +static char *

> +mem2hex (char *buf, const byte *mem, unsigned bytes)

> +{

> +  char *d = buf;

> +  if (bytes != 0)

> +    {

> +      do

> +       {

> +         d = byte2hex (d, *mem++);

> +       }

> +      while (--bytes);

> +    }

> +  *d = 0;

> +  return d;

> +}

> +

> +/* convert the hex array pointed to by buf into binary, to be placed in

> mem

> +   return a pointer to the character after the last byte written */

> +

> +static const char *

> +hex2mem (byte *mem, const char *buf, unsigned bytes)

> +{

> +  if (bytes != 0)

> +    {

> +      do

> +       {

> +         *mem++ = hex2byte (buf);

> +         buf += 2;

> +       }

> +      while (--bytes);

> +    }

> +  return buf;

> +}

> +

> +#ifdef DBG_MEMORY_MAP

> +static void

> +read_memory_map (char *buffer, unsigned offset, unsigned length)

> +{

> +  const char *map = DBG_MEMORY_MAP;

> +  const unsigned map_sz = strlen(map);

> +  if (offset >= map_sz)

> +    {

> +      buffer[0] = 'l';

> +      buffer[1] = '\0';

> +      return;

> +    }

> +  if (offset + length > map_sz)

> +    length = map_sz - offset;

> +  buffer[0] = 'm';

> +  memcpy (&buffer[1], &map[offset], length);

> +  buffer[1+length] = '\0';

> +}

> +#endif

> +

> +/* write string like " nn:0123" and return pointer after it */

> +#ifndef DBG_MIN_SIZE

> +static char *

> +format_reg_value (char *p, unsigned reg_num, const byte *value)

> +{

> +  char *d = p;

> +  unsigned char i;

> +  d = byte2hex(d, reg_num);

> +  *d++ = ':';

> +  value += REG_SIZE;

> +  i = REG_SIZE;

> +  do

> +    {

> +      d = byte2hex(d, *--value);

> +    }

> +  while (--i != 0);

> +  *d++ = ';';

> +  return d;

> +}

> +#endif /* DBG_MIN_SIZE */

> +

> +#ifdef __SDCC_gbz80

> +/* saves all state.except PC and SP */

> +static void

> +save_cpu_state() __naked

> +{

> +  __asm

> +       push    af

> +       ld      a, l

> +       ld      (#_state + R_HL + 0), a

> +       ld      a, h

> +       ld      (#_state + R_HL + 1), a

> +       ld      hl, #_state + R_HL - 1

> +       ld      (hl), d

> +       dec     hl

> +       ld      (hl), e

> +       dec     hl

> +       ld      (hl), b

> +       dec     hl

> +       ld      (hl), c

> +       dec     hl

> +       pop     bc

> +       ld      (hl), b

> +       dec     hl

> +       ld      (hl), c

> +       ret

> +  __endasm;

> +}

> +

> +/* restore CPU state and continue execution */

> +static void

> +rest_cpu_state() __naked

> +{

> +  __asm

> +;restore SP

> +       ld      a, (#_state + R_SP + 0)

> +       ld      l,a

> +       ld      a, (#_state + R_SP + 1)

> +       ld      h,a

> +       ld      sp, hl

> +;push PC value as return address

> +       ld      a, (#_state + R_PC + 0)

> +       ld      l, a

> +       ld      a, (#_state + R_PC + 1)

> +       ld      h, a

> +       push    hl

> +;restore registers

> +       ld      hl, #_state + R_AF

> +       ld      c, (hl)

> +       inc     hl

> +       ld      b, (hl)

> +       inc     hl

> +       push    bc

> +       ld      c, (hl)

> +       inc     hl

> +       ld      b, (hl)

> +       inc     hl

> +       ld      e, (hl)

> +       inc     hl

> +       ld      d, (hl)

> +       inc     hl

> +       ld      a, (hl)

> +       inc     hl

> +       ld      h, (hl)

> +       ld      l, a

> +       pop     af

> +       ret

> +  __endasm;

> +}

> +#else

> +/* saves all state.except PC and SP */

> +static void

> +save_cpu_state() __naked

> +{

> +  __asm

> +       ld      (#_state + R_HL), hl

> +       ld      (#_state + R_DE), de

> +       ld      (#_state + R_BC), bc

> +       push    af

> +       pop     hl

> +       ld      (#_state + R_AF), hl

> +       ld      a, r    ;R is increased by 7 or by 8 if called via RST

> +       ld      l, a

> +       sub     a, #7

> +       xor     a, l

> +       and     a, #0x7f

> +       xor     a, l

> +#ifdef __SDCC_ez80_adl

> +       ld      hl, i

> +       ex      de, hl

> +       ld      hl, #_state + R_IR

> +       ld      (hl), a

> +       inc     hl

> +       ld      (hl), e

> +       inc     hl

> +       ld      (hl), d

> +       ld      a, MB

> +       ld      (#_state + R_AF+2), a

> +#else

> +       ld      l, a

> +       ld      a, i

> +       ld      h, a

> +       ld      (#_state + R_IR), hl

> +#endif /* __SDCC_ez80_adl */

> +       ld      (#_state + R_IX), ix

> +       ld      (#_state + R_IY), iy

> +       ex      af, af' ;'

> +       exx

> +       ld      (#_state + R_HL_), hl

> +       ld      (#_state + R_DE_), de

> +       ld      (#_state + R_BC_), bc

> +       push    af

> +       pop     hl

> +       ld      (#_state + R_AF_), hl

> +       ret

> +  __endasm;

> +}

> +

> +/* restore CPU state and continue execution */

> +static void

> +rest_cpu_state() __naked

> +{

> +  __asm

> +#ifdef DBG_USE_TRAMPOLINE

> +       ld      sp, _stack + DBG_STACK_SIZE

> +       ld      hl, (#_state + R_PC)

> +       push    hl      /* resume address */

> +#ifdef __SDCC_ez80_adl

> +       ld      hl, 0xc30000 ; use 0xc34000 for jp.s

> +#else

> +       ld      hl, 0xc300

> +#endif

> +       push    hl      /* JP opcode */

> +#endif /* DBG_USE_TRAMPOLINE */

> +       ld      hl, (#_state + R_AF_)

> +       push    hl

> +       pop     af

> +       ld      bc, (#_state + R_BC_)

> +       ld      de, (#_state + R_DE_)

> +       ld      hl, (#_state + R_HL_)

> +       exx

> +       ex      af, af' ;'

> +       ld      iy, (#_state + R_IY)

> +       ld      ix, (#_state + R_IX)

> +#ifdef __SDCC_ez80_adl

> +       ld      a, (#_state + R_AF + 2)

> +       ld      MB, a

> +       ld      hl, (#_state + R_IR + 1) ;I register

> +       ld      i, hl

> +       ld      a, (#_state + R_IR + 0) ; R register

> +       ld      l, a

> +#else

> +       ld      hl, (#_state + R_IR)

> +       ld      a, h

> +       ld      i, a

> +       ld      a, l

> +#endif /* __SDCC_ez80_adl */

> +       sub     a, #10  ;number of M1 cycles after ld r,a

> +       xor     a, l

> +       and     a, #0x7f

> +       xor     a, l

> +       ld      r, a

> +       ld      de, (#_state + R_DE)

> +       ld      bc, (#_state + R_BC)

> +       ld      hl, (#_state + R_AF)

> +       push    hl

> +       pop     af

> +       ld      sp, (#_state + R_SP)

> +#ifndef DBG_USE_TRAMPOLINE

> +       ld      hl, (#_state + R_PC)

> +       push    hl

> +       ld      hl, (#_state + R_HL)

> +       DBG_RESUME

> +#else

> +       ld      hl, (#_state + R_HL)

> +#ifdef __SDCC_ez80_adl

> +       jp      #_stack + DBG_STACK_SIZE - 4

> +#else

> +       jp      #_stack + DBG_STACK_SIZE - 3

> +#endif

> +#endif /* DBG_USE_TRAMPOLINE */

> +  __endasm;

> +}

> +#endif /* __SDCC_gbz80 */

> diff --git a/gdb/z80-tdep.c b/gdb/z80-tdep.c

> new file mode 100644

> index 000000000000..7b9a7e23501b

> --- /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,

Patch

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 2274b9b6a61a..73a1bf83c858 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -853,7 +853,8 @@  ALL_TARGET_OBS = \
 	xstormy16-tdep.o \
 	xtensa-config.o \
 	xtensa-linux-tdep.o \
-	xtensa-tdep.o
+	xtensa-tdep.o \
+	z80-tdep.o
 
 # The following native-target dependent variables are defined on
 # configure.nat.
diff --git a/gdb/NEWS b/gdb/NEWS
index 1fea2f56ff69..9560710dd4fe 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -426,6 +426,7 @@  alias [-a] [--] ALIAS = COMMAND [DEFAULT-ARGS...]
 
 GNU/Linux/RISC-V (gdbserver)	riscv*-*-linux*
 BPF				bpf-unknown-none
+Z80				z80-unknown-*
 
 * Python API
 
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 643973917fe0..97a5a57c3788 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -761,6 +761,10 @@  xtensa*-*-*linux*)
 	# Target: GNU/Linux Xtensa
 	gdb_target_obs="xtensa-linux-tdep.o symfile-mem.o linux-tdep.o"
 	;;
+z80*)
+	# Target: Z80
+	gdb_target_obs="z80-tdep.o"
+	;;
 
 esac
 
diff --git a/gdb/features/Makefile b/gdb/features/Makefile
index 522ad58aab0f..ded8c3bb9da4 100644
--- a/gdb/features/Makefile
+++ b/gdb/features/Makefile
@@ -170,7 +170,8 @@  XMLTOC = \
 	s390x-tevx-linux64.xml \
 	s390x-vx-linux64.xml \
 	s390-gs-linux64.xml \
-	s390x-gs-linux64.xml
+	s390x-gs-linux64.xml \
+	z80.xml
 
 TDESC_CFILES = $(patsubst %.xml,%.c,$(XMLTOC))
 GDB = false
diff --git a/gdb/features/z80-cpu.xml b/gdb/features/z80-cpu.xml
new file mode 100644
index 000000000000..98498b1bcc13
--- /dev/null
+++ b/gdb/features/z80-cpu.xml
@@ -0,0 +1,33 @@ 
+<?xml version="1.0"?>
+<!-- Copyright (C) 2020 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.z80.cpu">
+  <flags id="af_flags" size="2">
+    <field name="C" start="0" end="0"/>
+    <field name="N" start="1" end="1"/>
+    <field name="P/V" start="2" end="2"/>
+    <field name="F3" start="3" end="3"/>
+    <field name="H" start="4" end="4"/>
+    <field name="F5" start="5" end="5"/>
+    <field name="Z" start="6" end="6"/>
+    <field name="S" start="7" end="7"/>
+  </flags>
+  <reg name="af" bitsize="16" type="af_flags"/>
+  <reg name="bc" bitsize="16" type="uint16"/>
+  <reg name="de" bitsize="16" type="data_ptr"/>
+  <reg name="hl" bitsize="16" type="data_ptr"/>
+  <reg name="sp" bitsize="16" type="data_ptr" />
+  <reg name="pc" bitsize="32" type="code_ptr" />
+  <reg name="ix" bitsize="16" type="data_ptr"/>
+  <reg name="iy" bitsize="16" type="data_ptr"/>
+  <reg name="af'" bitsize="16" type="af_flags"/>
+  <reg name="bc'" bitsize="16" type="uint16"/>
+  <reg name="de'" bitsize="16" type="data_ptr"/>
+  <reg name="hl'" bitsize="16" type="data_ptr"/>
+  <reg name="ir" bitsize="16" type="uint16"/>
+</feature>
diff --git a/gdb/features/z80.c b/gdb/features/z80.c
new file mode 100644
index 000000000000..944b563aca47
--- /dev/null
+++ b/gdb/features/z80.c
@@ -0,0 +1,44 @@ 
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: z80.xml */
+
+#include "defs.h"
+#include "osabi.h"
+#include "target-descriptions.h"
+
+struct target_desc *tdesc_z80;
+static void
+initialize_tdesc_z80 (void)
+{
+  target_desc_up result = allocate_target_description ();
+  set_tdesc_architecture (result.get (), bfd_scan_arch ("z80"));
+
+  struct tdesc_feature *feature;
+
+  feature = tdesc_create_feature (result.get (), "org.gnu.gdb.z80.cpu");
+  tdesc_type_with_fields *type_with_fields;
+  type_with_fields = tdesc_create_flags (feature, "af_flags", 2);
+  tdesc_add_flag (type_with_fields, 0, "C");
+  tdesc_add_flag (type_with_fields, 1, "N");
+  tdesc_add_flag (type_with_fields, 2, "P/V");
+  tdesc_add_flag (type_with_fields, 3, "F3");
+  tdesc_add_flag (type_with_fields, 4, "H");
+  tdesc_add_flag (type_with_fields, 5, "F5");
+  tdesc_add_flag (type_with_fields, 6, "Z");
+  tdesc_add_flag (type_with_fields, 7, "S");
+
+  tdesc_create_reg (feature, "af", 0, 1, NULL, 16, "af_flags");
+  tdesc_create_reg (feature, "bc", 1, 1, NULL, 16, "uint16");
+  tdesc_create_reg (feature, "de", 2, 1, NULL, 16, "data_ptr");
+  tdesc_create_reg (feature, "hl", 3, 1, NULL, 16, "data_ptr");
+  tdesc_create_reg (feature, "sp", 4, 1, NULL, 16, "data_ptr");
+  tdesc_create_reg (feature, "pc", 5, 1, NULL, 32, "code_ptr");
+  tdesc_create_reg (feature, "ix", 6, 1, NULL, 16, "data_ptr");
+  tdesc_create_reg (feature, "iy", 7, 1, NULL, 16, "data_ptr");
+  tdesc_create_reg (feature, "af'", 8, 1, NULL, 16, "af_flags");
+  tdesc_create_reg (feature, "bc'", 9, 1, NULL, 16, "uint16");
+  tdesc_create_reg (feature, "de'", 10, 1, NULL, 16, "data_ptr");
+  tdesc_create_reg (feature, "hl'", 11, 1, NULL, 16, "data_ptr");
+  tdesc_create_reg (feature, "ir", 12, 1, NULL, 16, "uint16");
+
+  tdesc_z80 = result.release ();
+}
diff --git a/gdb/features/z80.xml b/gdb/features/z80.xml
new file mode 100644
index 000000000000..238687a127e2
--- /dev/null
+++ b/gdb/features/z80.xml
@@ -0,0 +1,12 @@ 
+<?xml version="1.0"?>
+<!-- Copyright (C) 2020 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target>
+  <architecture>z80</architecture>
+  <xi:include href="z80-cpu.xml"/>
+</target>
diff --git a/gdb/stubs/z80-stub.c b/gdb/stubs/z80-stub.c
new file mode 100644
index 000000000000..0ec128fbe6a6
--- /dev/null
+++ b/gdb/stubs/z80-stub.c
@@ -0,0 +1,1355 @@ 
+/* Debug stub for Z80.
+
+   Copyright (C) 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/>.  */
+
+/* Usage:
+  1. Copy this file to project directory
+  2. Configure it commenting/uncommenting macros below or define DBG_CONFIGURED
+     and all required macros and then include this file to one of your C-source
+     files.
+  3. Implement getDebugChar() and putDebugChar(), functions must not return
+     until data received or sent.
+  4. Implement all optional functions used to toggle breakpoints/watchpoints,
+     if supported. Do not write fuctions to toggle software breakpoints if
+     you unsure (GDB will do itself).
+  5. Implement serial port initialization routine called at program start.
+  6. Add necessary debugger entry points to your program, for example:
+	.org 0x08	;RST 8 handler
+	jp _debug_swbreak
+	...
+	.org	0x66	;NMI handler
+	jp	_debug_nmi
+	...
+	main_loop:
+	halt
+	call	isDbgInterrupt
+	jr	z,101$
+	ld	hl, 2	;EX_SIGINT
+	push	hl
+	call	_debug_exception
+	101$:
+	...
+  7. Compile file using SDCC (supported ports are: z80, z180, z80n, gbz80 and
+     ez80_z80), do not use --peep-asm option. For example:
+	$ sdcc -mz80 --opt-code-size --max-allocs-per-node 50000 z80-stub.c
+*/
+/******************************************************************************\
+			     Configuration
+\******************************************************************************/
+#ifndef DBG_CONFIGURED
+/* Uncomment this line, if stub size is critical for you */
+//#define DBG_MIN_SIZE
+
+/* Comment this line out if software breakpoints are unsupported.
+   If you have special function to toggle software breakpoints, then provide
+   here name of these function. Expected prototype:
+       int toggle_swbreak(int set, void *addr);
+   function must return 0 on success. */
+//#define DBG_SWBREAK toggle_swbreak
+#define DBG_SWBREAK
+
+/* Define if one of standard RST handlers is used as software
+   breakpoint entry point */
+//#define DBG_SWBREAK_RST 0x08
+
+/* if platform supports hardware breakpoints then define following macro
+   by name of function. Fuction must have next prototype:
+     int toggle_hwbreak(int set, void *addr);
+   function must return 0 on success. */
+//#define DBG_HWBREAK toggle_hwbreak
+
+/* if platform supports hardware watchpoints then define all or some of
+   following macros by names of functions. Fuctions prototypes:
+     int toggle_watch(int set, void *addr, size_t size);  // memory write watch
+     int toggle_rwatch(int set, void *addr, size_t size); // memory read watch
+     int toggle_awatch(int set, void *addr, size_t size); // memory access watch
+   function must return 0 on success. */
+//#define DBG_WWATCH toggle_watch
+//#define DBG_RWATCH toggle_rwatch
+//#define DBG_AWATCH toggle_awatch
+
+/* Size of hardware breakpoint. Required to correct PC. */
+#define DBG_HWBREAK_SIZE 0
+
+/* Define following macro if you need custom memory read/write routine.
+   Function should return non-zero on success, and zero on failure
+   (for example, write to ROM area).
+   Useful with overlays (bank switching).
+   Do not forget to define:
+   _ovly_table - overlay table
+   _novlys - number of items in _ovly_table
+   or
+   _ovly_region_table - overlay regions table
+   _novly_regions - number of items in _ovly_region_table
+
+   _ovly_debug_prepare - function is called before overlay mapping
+   _ovly_debug_event - function is called after overlay mapping
+ */
+//#define DBG_MEMCPY memcpy
+
+/* define dedicated stack size if required */
+//#define DBG_STACK_SIZE 256
+
+/* max GDB packet size
+   should be much less that DBG_STACK_SIZE because it will be allocated on stack
+*/
+#define DBG_PACKET_SIZE 150
+
+/* Uncomment if required to use trampoline when resuming operation.
+   Useful with dedicated stack when stack pointer do not point to the stack or
+   stack is not writable */
+//#define DBG_USE_TRAMPOLINE
+
+/* Uncomment following macro to enable debug printing to debugger console */
+//#define DBG_PRINT
+
+#define DBG_NMI_EX EX_HWBREAK
+#define DBG_INT_EX EX_SIGINT
+
+/* Define following macro to statement, which will be exectuted after entering to
+   stub_main function. Statement should include semicolon. */
+//#define DBG_ENTER debug_enter();
+
+/* Define following macro to instruction(s), which will be execute before return
+   control to the program. It is useful when gdb-stub is placed in one of overlays.
+   This procedure must not change any register. On top of stack before invocation
+   will be return address of the program. */
+//#define DBG_RESUME jp _restore_bank
+
+/* Define following macro to the string containing memory map definition XML.
+   GDB will use it to select proper breakpoint type (HW or SW). */
+/*#define DBG_MEMORY_MAP "\
+<memory-map>\
+	<memory type=\"rom\" start=\"0x0000\" length=\"0x4000\"/>\
+<!--	<memory type=\"flash\" start=\"0x4000\" length=\"0x4000\">\
+		<property name=\"blocksize\">128</property>\
+	</memory> -->\
+	<memory type=\"ram\" start=\"0x8000\" length=\"0x8000\"/>\
+</memory-map>\
+"
+*/
+#endif /* DBG_CONFIGURED */
+/******************************************************************************\
+			     Public Interface
+\******************************************************************************/
+
+/* Enter to debug mode from software or hardware breakpoint.
+   Assume address of next instruction after breakpoint call is on top of stack.
+   Do JP _debug_swbreak or JP _debug_hwbreak from RST handler, for example.
+ */
+void debug_swbreak (void);
+void debug_hwbreak (void);
+
+/* Jump to this function from NMI handler. Just replace RETN instruction by
+   JP _debug_nmi
+   Use if NMI detects request to enter to debug mode.
+ */
+void debug_nmi (void);
+
+/* Jump to this function from INT handler. Just replace EI+RETI instructions by
+   JP _debug_int
+   Use if INT detects request to enter to debug mode.
+ */
+void debug_int (void);
+
+#define EX_SWBREAK	0	/* sw breakpoint */
+#define EX_HWBREAK	-1	/* hw breakpoint */
+#define EX_WWATCH	-2	/* memory write watch */
+#define EX_RWATCH	-3	/* memory read watch */
+#define EX_AWATCH	-4	/* memory access watch */
+#define EX_SIGINT	2
+#define EX_SIGTRAP	5
+#define EX_SIGABRT	6
+#define EX_SIGBUS	10
+#define EX_SIGSEGV	11
+/* or any standard *nix signal value */
+
+/* Enter to debug mode (after receiving BREAK from GDB, for example)
+ * Assume:
+ *   program PC in (SP+0)
+ *   caught signal in (SP+2)
+ *   program SP is SP+4
+ */
+void debug_exception (int ex);
+
+/* Prints to debugger console. */
+void debug_print(const char *str);
+/******************************************************************************\
+			      Required functions
+\******************************************************************************/
+
+extern int getDebugChar (void);
+extern void putDebugChar (int ch);
+
+#ifdef DBG_SWBREAK
+#define DO_EXPAND(VAL)  VAL ## 123456
+#define EXPAND(VAL)     DO_EXPAND(VAL)
+
+#if EXPAND(DBG_SWBREAK) != 123456
+#define DBG_SWBREAK_PROC DBG_SWBREAK
+extern int DBG_SWBREAK(int set, void *addr);
+#endif
+
+#undef EXPAND
+#undef DO_EXPAND
+#endif /* DBG_SWBREAK */
+
+#ifdef DBG_HWBREAK
+extern int DBG_HWBREAK(int set, void *addr);
+#endif
+
+#ifdef DBG_MEMCPY
+extern void* DBG_MEMCPY (void *dest, const void *src, unsigned n);
+#endif
+
+#ifdef DBG_WWATCH
+extern int DBG_WWATCH(int set, void *addr, unsigned size);
+#endif
+
+#ifdef DBG_RWATCH
+extern int DBG_RWATCH(int set, void *addr, unsigned size);
+#endif
+
+#ifdef DBG_AWATCH
+extern int DBG_AWATCH(int set, void *addr, unsigned size);
+#endif
+
+/******************************************************************************\
+			       IMPLEMENTATION
+\******************************************************************************/
+
+#include <string.h>
+
+#ifndef NULL
+# define NULL (void*)0
+#endif
+
+typedef unsigned char byte;
+typedef unsigned short word;
+
+/* CPU state */
+#ifdef __SDCC_ez80_adl
+# define REG_SIZE 3
+#else
+# define REG_SIZE 2
+#endif /* __SDCC_ez80_adl */
+
+#define R_AF    (0*REG_SIZE)
+#define R_BC    (1*REG_SIZE)
+#define R_DE    (2*REG_SIZE)
+#define R_HL    (3*REG_SIZE)
+#define R_SP    (4*REG_SIZE)
+#define R_PC    (5*REG_SIZE)
+
+#ifndef __SDCC_gbz80
+#define R_IX    (6*REG_SIZE)
+#define R_IY    (7*REG_SIZE)
+#define R_AF_   (8*REG_SIZE)
+#define R_BC_   (9*REG_SIZE)
+#define R_DE_   (10*REG_SIZE)
+#define R_HL_   (11*REG_SIZE)
+#define R_IR    (12*REG_SIZE)
+
+#ifdef __SDCC_ez80_adl
+#define R_SPS   (13*REG_SIZE)
+#define NUMREGBYTES (14*REG_SIZE)
+#else
+#define NUMREGBYTES (13*REG_SIZE)
+#endif /* __SDCC_ez80_adl */
+#else
+#define NUMREGBYTES (6*REG_SIZE)
+#define FASTCALL
+#endif /*__SDCC_gbz80 */
+static byte state[NUMREGBYTES];
+
+#if DBG_PACKET_SIZE < (NUMREGBYTES*2+5)
+#error "Too small DBG_PACKET_SIZE"
+#endif
+
+#ifndef FASTCALL
+#define FASTCALL __z88dk_fastcall
+#endif
+
+/* dedicated stack */
+#ifdef DBG_STACK_SIZE
+
+#define LOAD_SP	ld	sp, #_stack + DBG_STACK_SIZE
+
+static char stack[DBG_STACK_SIZE];
+
+#else
+
+#undef DBG_USE_TRAMPOLINE
+#define LOAD_SP
+
+#endif
+
+#ifndef DBG_ENTER
+#define DBG_ENTER
+#endif
+
+#ifndef DBG_RESUME
+#define DBG_RESUME ret
+#endif
+
+static signed char sigval;
+
+static void stub_main (int sigval, int pc_adj);
+static char high_hex (byte v) FASTCALL;
+static char low_hex (byte v) FASTCALL;
+static char put_packet_info (const char *buffer) FASTCALL;
+static void save_cpu_state (void);
+static void rest_cpu_state (void);
+
+/******************************************************************************/
+#ifdef DBG_SWBREAK
+#ifdef DBG_SWBREAK_RST
+#define DBG_SWBREAK_SIZE 1
+#else
+#define DBG_SWBREAK_SIZE 3
+#endif
+void
+debug_swbreak (void) __naked
+{
+  __asm
+	ld	(#_state + R_SP), sp
+	LOAD_SP
+	call	_save_cpu_state
+	ld	hl, #-DBG_SWBREAK_SIZE
+	push	hl
+	ld	hl, #EX_SWBREAK
+	push	hl
+	call	_stub_main
+	.globl	_break_handler
+#ifdef DBG_SWBREAK_RST
+_break_handler = DBG_SWBREAK_RST
+#else
+_break_handler = _debug_swbreak
+#endif
+  __endasm;
+}
+#endif /* DBG_SWBREAK */
+/******************************************************************************/
+#ifdef DBG_HWBREAK
+#ifndef DBG_HWBREAK_SIZE
+#define DBG_HWBREAK_SIZE 0
+#endif /* DBG_HWBREAK_SIZE */
+void
+debug_hwbreak (void) __naked
+{
+  __asm
+	ld	(#_state + R_SP), sp
+	LOAD_SP
+	call	_save_cpu_state
+	ld	hl, #-DBG_HWBREAK_SIZE
+	push	hl
+	ld	hl, #EX_HWBREAK
+	push	hl
+	call	_stub_main
+  __endasm;
+}
+#endif /* DBG_HWBREAK_SET */
+/******************************************************************************/
+void
+debug_exception (int ex) __naked
+{
+  __asm
+	ld	(#_state + R_SP), sp
+	LOAD_SP
+	call	_save_cpu_state
+	ld	hl, #0
+	push	hl
+#ifdef __SDCC_gbz80
+	ld	hl, #_state + R_SP
+	ld	a, (hl+)
+	ld	h, (hl)
+	ld	l, a
+#else
+	ld	hl, (#_state + R_SP)
+#endif
+	inc	hl
+	inc	hl
+	ld	e, (hl)
+	inc	hl
+	ld	d, (hl)
+	push	de
+	call	_stub_main
+  __endasm;
+  (void)ex;
+}
+/******************************************************************************/
+#ifndef __SDCC_gbz80
+void
+debug_nmi(void) __naked
+{
+  __asm
+	ld	(#_state + R_SP), sp
+	LOAD_SP
+	call	_save_cpu_state
+	ld	hl, #0	;pc_adj
+	push	hl
+	ld	hl, #DBG_NMI_EX
+	push	hl
+	ld	hl, #_stub_main
+	push	hl
+	push	hl
+	retn
+  __endasm;
+}
+#endif
+/******************************************************************************/
+void
+debug_int(void) __naked
+{
+  __asm
+	ld	(#_state + R_SP), sp
+	LOAD_SP
+	call	_save_cpu_state
+	ld	hl, #0	;pc_adj
+	push	hl
+	ld	hl, #DBG_INT_EX
+	push	hl
+	ld	hl, #_stub_main
+	push	hl
+	push	hl
+	ei
+	reti
+  __endasm;
+}
+/******************************************************************************/
+#ifdef DBG_PRINT
+void
+debug_print(const char *str)
+{
+  putDebugChar ('$');
+  putDebugChar ('O');
+  char csum = 'O';
+  for (; *str != '\0'; )
+    {
+      char c = high_hex (*str);
+      csum += c;
+      putDebugChar (c);
+      c = low_hex (*str++);
+      csum += c;
+      putDebugChar (c);
+    }
+  putDebugChar ('#');
+  putDebugChar (high_hex (csum));
+  putDebugChar (low_hex (csum));
+}
+#endif /* DBG_PRINT */
+/******************************************************************************/
+static void store_pc_sp (int pc_adj) FASTCALL;
+#define get_reg_value(mem) (*(void* const*)(mem))
+#define set_reg_value(mem,val) do { (*(void**)(mem) = (val)); } while (0)
+static char* byte2hex(char *buf, byte val);
+static int hex2int (const char **buf) FASTCALL;
+static char* int2hex (char *buf, int v);
+static void get_packet (char *buffer);
+static void put_packet (const char *buffer);
+static char process (char *buffer) FASTCALL;
+static void rest_cpu_state (void);
+
+static void
+stub_main (int ex, int pc_adj)
+{
+  char buffer[DBG_PACKET_SIZE+1];
+  sigval = (signed char)ex;
+  store_pc_sp (pc_adj);
+
+  DBG_ENTER
+
+  /* after starting gdb_stub must always return stop reason */
+  *buffer = '?';
+  for (; process (buffer);)
+    {
+      put_packet (buffer);
+      get_packet (buffer);
+    }
+  put_packet (buffer);
+  rest_cpu_state ();
+}
+
+static void
+get_packet (char *buffer)
+{
+  byte csum;
+  char ch;
+  char *p;
+  byte esc;
+#if DBG_PACKET_SIZE <= 256
+  byte count; /* it is OK to use up to 256 here */
+#else
+  unsigned count;
+#endif
+  for (;; putDebugChar ('-'))
+    {
+      /* wait for packet start character */
+      while (getDebugChar () != '$');
+retry:
+      csum = 0;
+      esc = 0;
+      p = buffer;
+      count = DBG_PACKET_SIZE;
+      do
+	{
+	  ch = getDebugChar ();
+	  switch (ch)
+	    {
+	    case '$':
+	      goto retry;
+	    case '#':
+	      goto finish;
+	    case '}':
+	      esc = 0x20;
+	      break;
+	    default:
+	      *p++ = ch ^ esc;
+	      esc = 0;
+	      --count;
+	    }
+	  csum += ch;
+	}
+      while (count != 0);
+finish:
+      *p = '\0';
+      if (ch != '#') /* packet is too large */
+	continue;
+      ch = getDebugChar ();
+      if (ch != high_hex (csum))
+	continue;
+      ch = getDebugChar ();
+      if (ch != low_hex (csum))
+	continue;
+      break;
+    }
+  putDebugChar ('+');
+}
+
+static void
+put_packet (const char *buffer)
+{
+  /*  $<packet info>#<checksum>. */
+  for (;;)
+    {
+      putDebugChar ('$');
+      char checksum = put_packet_info (buffer);
+      putDebugChar ('#');
+      putDebugChar (high_hex(checksum));
+      putDebugChar (low_hex(checksum));
+      for (;;)
+	{
+	  char c = getDebugChar ();
+	  switch (c)
+	    {
+	    case '+': return;
+	    case '-': break;
+	    default:
+	      putDebugChar (c);
+	      continue;
+	    }
+	  break;
+	}
+    }
+}
+
+static char
+put_packet_info (const char *src) FASTCALL
+{
+  char ch;
+  char checksum = 0;
+  for (;;)
+    {
+      ch = *src++;
+      if (ch == '\0')
+	break;
+      if (ch == '}' || ch == '*' || ch == '#' || ch == '$')
+	{
+	  /* escape special characters */
+	  putDebugChar ('}');
+	  checksum += '}';
+	  ch ^= 0x20;
+	}
+      putDebugChar (ch);
+      checksum += ch;
+    }
+  return checksum;
+}
+
+static void
+store_pc_sp (int pc_adj) FASTCALL
+{
+  byte *sp = get_reg_value (&state[R_SP]);
+  byte *pc = get_reg_value (sp);
+  pc += pc_adj;
+  set_reg_value (&state[R_PC], pc);
+  set_reg_value (&state[R_SP], sp + REG_SIZE);
+}
+
+static char *mem2hex (char *buf, const byte *mem, unsigned bytes);
+static char *hex2mem (byte *mem, const char *buf, unsigned bytes);
+
+/* Command processors. Takes pointer to buffer (begins from command symbol),
+   modifies buffer, returns: -1 - empty response (ignore), 0 - success,
+   positive: error code. */
+
+#ifdef DBG_MIN_SIZE
+static signed char
+process_question (char *p) FASTCALL
+{
+  signed char sig;
+  *p++ = 'S';
+  sig = sigval;
+  if (sig <= 0)
+    sig = EX_SIGTRAP;
+  p = byte2hex (p, (byte)sig);
+  *p = '\0';
+  return 0;
+}
+#else /* DBG_MIN_SIZE */
+static char *format_reg_value (char *p, unsigned reg_num, const byte *value);
+
+static signed char
+process_question (char *p) FASTCALL
+{
+  signed char sig;
+  *p++ = 'T';
+  sig = sigval;
+  if (sig <= 0)
+    sig = EX_SIGTRAP;
+  p = byte2hex (p, (byte)sig);
+  p = format_reg_value(p, R_AF/REG_SIZE, &state[R_AF]);
+  p = format_reg_value(p, R_SP/REG_SIZE, &state[R_SP]);
+  p = format_reg_value(p, R_PC/REG_SIZE, &state[R_PC]);
+#if defined(DBG_SWBREAK_PROC) || defined(DBG_HWBREAK) || defined(DBG_WWATCH) || defined(DBG_RWATCH) || defined(DBG_AWATCH)
+  const char *reason;
+  unsigned addr = 0;
+  switch (sigval)
+    {
+#ifdef DBG_SWBREAK_PROC
+    case EX_SWBREAK:
+      reason = "swbreak";
+      break;
+#endif
+#ifdef DBG_HWBREAK
+    case EX_HWBREAK:
+      reason = "hwbreak";
+      break;
+#endif
+#ifdef DBG_WWATCH
+    case EX_WWATCH:
+      reason = "watch";
+      addr = 1;
+      break;
+#endif
+#ifdef DBG_RWATCH
+    case EX_RWATCH:
+      reason = "rwatch";
+      addr = 1;
+      break;
+#endif
+#ifdef DBG_AWATCH
+    case EX_AWATCH:
+      reason = "awatch";
+      addr = 1;
+      break;
+#endif
+    default:
+      goto finish;
+    }
+  while ((*p++ = *reason++))
+    ;
+  --p;
+  *p++ = ':';
+  if (addr != 0)
+    p = int2hex(p, addr);
+  *p++ = ';';
+finish:
+#endif /* DBG_HWBREAK, DBG_WWATCH, DBG_RWATCH, DBG_AWATCH */
+  *p++ = '\0';
+  return 0;
+}
+#endif /* DBG_MINSIZE */
+
+#define STRING2(x) #x
+#define STRING1(x) STRING2(x)
+#define STRING(x) STRING1(x)
+#ifdef DBG_MEMORY_MAP
+static void read_memory_map (char *buffer, unsigned offset, unsigned length);
+#endif
+
+static signed char
+process_q (char *buffer) FASTCALL
+{
+  char *p;
+  if (memcmp (buffer + 1, "Supported", 9) == 0)
+    {
+      memcpy (buffer, "PacketSize=", 11);
+      p = int2hex (&buffer[11], DBG_PACKET_SIZE);
+#ifndef DBG_MIN_SIZE
+#ifdef DBG_SWBREAK_PROC
+      memcpy (p, ";swbreak+", 9);
+      p += 9;
+#endif
+#ifdef DBG_HWBREAK
+      memcpy (p, ";hwbreak+", 9);
+      p += 9;
+#endif
+#endif /* DBG_MIN_SIZE */
+
+#ifdef DBG_MEMORY_MAP
+      memcpy (p, ";qXfer:memory-map:read+", 23);
+      p += 23;
+#endif
+      *p = '\0';
+      return 0;
+    }
+#ifdef DBG_MEMORY_MAP
+  if (memcmp (buffer + 1, "Xfer:memory-map:read:", 21) == 0)
+    {
+      p = strchr (buffer + 1 + 21, ':');
+      if (p == NULL)
+	return 1;
+      ++p;
+      unsigned offset = hex2int (&p);
+      if (*p++ != ',')
+	return 2;
+      unsigned length = hex2int (&p);
+      if (length == 0)
+	return 3;
+      if (length > DBG_PACKET_SIZE)
+	return 4;
+      read_memory_map (buffer, offset, length);
+      return 0;
+    }
+#endif
+#ifndef DBG_MIN_SIZE
+  if (memcmp (&buffer[1], "Attached", 9) == 0)
+    {
+      /* Just report that GDB attached to existing process
+	 if it is not applicable for you, then send patches */
+      memcpy(buffer, "1", 2);
+      return 0;
+    }
+#endif /* DBG_MIN_SIZE */
+  *buffer = '\0';
+  return -1;
+}
+
+static signed char
+process_g (char *buffer) FASTCALL
+{
+  mem2hex (buffer, state, NUMREGBYTES);
+  return 0;
+}
+
+static signed char
+process_G (char *buffer) FASTCALL
+{
+  hex2mem (state, &buffer[1], NUMREGBYTES);
+  /* OK response */
+  *buffer = '\0';
+  return 0;
+}
+
+static signed char
+process_m (char *buffer) FASTCALL
+{/* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
+  char *p = &buffer[1];
+  byte *addr = (void*)hex2int(&p);
+  if (*p++ != ',')
+    return 1;
+  unsigned len = (unsigned)hex2int(&p);
+  if (len == 0)
+    return 2;
+  if (len > DBG_PACKET_SIZE/2)
+    return 3;
+  p = buffer;
+#ifdef DBG_MEMCPY
+  do
+    {
+      byte tmp[16];
+      unsigned tlen = sizeof(tmp);
+      if (tlen > len)
+	tlen = len;
+      if (!DBG_MEMCPY(tmp, addr, tlen))
+	return 4;
+      p = mem2hex (p, tmp, tlen);
+      addr += tlen;
+      len -= tlen;
+    }
+  while (len);
+#else
+  p = mem2hex (p, addr, len);
+#endif
+  return 0;
+}
+
+static signed char
+process_M (char *buffer) FASTCALL
+{/* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
+  char *p = &buffer[1];
+  byte *addr = (void*)hex2int(&p);
+  if (*p != ',')
+    return 1;
+  ++p;
+  unsigned len = (unsigned)hex2int(&p);
+  if (*p++ != ':')
+    return 2;
+  if (len == 0)
+    goto end;
+  if (len*2 + (p - buffer) > DBG_PACKET_SIZE)
+    return 3;
+#ifdef DBG_MEMCPY
+  do
+    {
+      byte tmp[16];
+      unsigned tlen = sizeof(tmp);
+      if (tlen > len)
+	tlen = len;
+      p = hex2mem (tmp, p, tlen);
+      if (!DBG_MEMCPY(addr, tmp, tlen))
+	return 4;
+      addr += tlen;
+	len -= tlen;
+    }
+  while (len);
+#else
+  hex2mem (addr, p, len);
+#endif
+end:
+  /* OK response */
+  *buffer = '\0';
+  return 0;
+}
+
+#ifndef DBG_MIN_SIZE
+static signed char
+process_X (char *buffer) FASTCALL
+{/* XAA..AA,LLLL: Write LLLL binary bytes at address AA.AA return OK */
+  char *p = &buffer[1];
+  byte *addr = (void*)hex2int(&p);
+  if (*p != ',')
+    return 1;
+  ++p;
+  unsigned len = (unsigned)hex2int(&p);
+  if (*p++ != ':')
+    return 2;
+  if (len == 0)
+    goto end;
+  if (len + (p - buffer) > DBG_PACKET_SIZE)
+    return 3;
+#ifdef DBG_MEMCPY
+  if (!DBG_MEMCPY(addr, p, len))
+    return 4;
+#else
+  memcpy (addr, p, len);
+#endif
+end:
+  /* OK response */
+  *buffer = '\0';
+  return 0;
+}
+#else /* DBG_MIN_SIZE */
+static signed char
+process_X (char *buffer) FASTCALL
+{
+  (void)buffer;
+  return -1;
+}
+#endif /* DBG_MIN_SIZE */
+
+static signed char
+process_c (char *buffer) FASTCALL
+{/* 'cAAAA' - Continue at address AAAA(optional) */
+  const char *p = &buffer[1];
+  if (*p != '\0')
+    {
+      void *addr = (void*)hex2int(&p);
+      set_reg_value (&state[R_PC], addr);
+    }
+  rest_cpu_state ();
+  return 0;
+}
+
+static signed char
+process_D (char *buffer) FASTCALL
+{/* 'D' - detach the program: continue execution */
+  *buffer = '\0';
+  return -2;
+}
+
+static signed char
+process_k (char *buffer) FASTCALL
+{/* 'k' - Kill the program */
+  set_reg_value (&state[R_PC], 0);
+  rest_cpu_state ();
+  (void)buffer;
+  return 0;
+}
+
+static signed char
+process_v (char *buffer) FASTCALL
+{
+#ifndef DBG_MIN_SIZE
+  if (memcmp (&buffer[1], "Cont", 4) == 0)
+    {
+      if (buffer[5] == '?')
+	{
+	  /* result response will be "vCont;c;C"; C action must be
+	     supported too, because GDB reguires at lease both of them */
+	  memcpy (&buffer[5], ";c;C", 5);
+	  return 0;
+	}
+      buffer[0] = '\0';
+      if (buffer[5] == ';' && (buffer[6] == 'c' || buffer[6] == 'C'))
+	return -2; /* resume execution */
+      return 1;
+  }
+#endif /* DBG_MIN_SIZE */
+  return -1;
+}
+
+static signed char
+process_zZ (char *buffer) FASTCALL
+{ /* insert/remove breakpoint */
+#if defined(DBG_SWBREAK_PROC) || defined(DBG_HWBREAK) || \
+    defined(DBG_WWATCH) || defined(DBG_RWATCH) || defined(DBG_AWATCH)
+  const byte set = (*buffer == 'Z');
+  const char *p = &buffer[3];
+  void *addr = (void*)hex2int(&p);
+  if (*p != ',')
+    return 1;
+  p++;
+  int kind = hex2int(&p);
+  *buffer = '\0';
+  switch (buffer[1])
+    {
+#ifdef DBG_SWBREAK_PROC
+    case '0': /* sw break */
+      return DBG_SWBREAK_PROC(set, addr);
+#endif
+#ifdef DBG_HWBREAK
+    case '1': /* hw break */
+      return DBG_HWBREAK(set, addr);
+#endif
+#ifdef DBG_WWATCH
+    case '2': /* write watch */
+      return DBG_WWATCH(set, addr, kind);
+#endif
+#ifdef DBG_RWATCH
+    case '3': /* read watch */
+      return DBG_RWATCH(set, addr, kind);
+#endif
+#ifdef DBG_AWATCH
+    case '4': /* access watch */
+      return DBG_AWATCH(set, addr, kind);
+#endif
+    default:; /* not supported */
+    }
+#endif
+  (void)buffer;
+  return -1;
+}
+
+static signed char
+do_process (char *buffer) FASTCALL
+{
+  switch (*buffer)
+    {
+    case '?': return process_question (buffer);
+    case 'G': return process_G (buffer);
+    case 'k': return process_k (buffer);
+    case 'M': return process_M (buffer);
+    case 'X': return process_X (buffer);
+    case 'Z': return process_zZ (buffer);
+    case 'c': return process_c (buffer);
+    case 'D': return process_D (buffer);
+    case 'g': return process_g (buffer);
+    case 'm': return process_m (buffer);
+    case 'q': return process_q (buffer);
+    case 'v': return process_v (buffer);
+    case 'z': return process_zZ (buffer);
+    default:  return -1; /* empty response */
+    }
+}
+
+static char
+process (char *buffer) FASTCALL
+{
+  signed char err = do_process (buffer);
+  char *p = buffer;
+  char ret = 1;
+  if (err == -2)
+    {
+      ret = 0;
+      err = 0;
+    }
+  if (err > 0)
+    {
+      *p++ = 'E';
+      p = byte2hex (p, err);
+      *p = '\0';
+    }
+  else if (err < 0)
+    {
+      *p = '\0';
+    }
+  else if (*p == '\0')
+    memcpy(p, "OK", 3);
+  return ret;
+}
+
+static char *
+byte2hex (char *p, byte v)
+{
+  *p++ = high_hex (v);
+  *p++ = low_hex (v);
+  return p;
+}
+
+static signed char
+hex2val (unsigned char hex) FASTCALL
+{
+  if (hex <= '9')
+    return hex - '0';
+  hex &= 0xdf; /* make uppercase */
+  hex -= 'A' - 10;
+  return (hex >= 10 && hex < 16) ? hex : -1;
+}
+
+static int
+hex2byte (const char *p) FASTCALL
+{
+  signed char h = hex2val (p[0]);
+  signed char l = hex2val (p[1]);
+  if (h < 0 || l < 0)
+    return -1;
+  return (byte)((byte)h << 4) | (byte)l;
+}
+
+static int
+hex2int (const char **buf) FASTCALL
+{
+  word r = 0;
+  for (;; (*buf)++)
+    {
+      signed char a = hex2val(**buf);
+      if (a < 0)
+	break;
+      r <<= 4;
+      r += (byte)a;
+    }
+  return (int)r;
+}
+
+static char *
+int2hex (char *buf, int v)
+{
+  buf = byte2hex(buf, (word)v >> 8);
+  return byte2hex(buf, (byte)v);
+}
+
+static char
+high_hex (byte v) FASTCALL
+{
+  return low_hex(v >> 4);
+}
+
+static char
+low_hex (byte v) FASTCALL
+{
+/*
+  __asm
+	ld	a, l
+	and	a, #0x0f
+	add	a, #0x90
+	daa
+	adc	a, #0x40
+	daa
+	ld	l, a
+  __endasm;
+  (void)v;
+*/
+  v &= 0x0f;
+  v += '0';
+  if (v < '9'+1)
+    return v;
+  return v + 'a' - '0' - 10;
+}
+
+/* convert the memory, pointed to by mem into hex, placing result in buf */
+/* return a pointer to the last char put in buf (null) */
+static char *
+mem2hex (char *buf, const byte *mem, unsigned bytes)
+{
+  char *d = buf;
+  if (bytes != 0)
+    {
+      do
+	{
+	  d = byte2hex (d, *mem++);
+	}
+      while (--bytes);
+    }
+  *d = 0;
+  return d;
+}
+
+/* convert the hex array pointed to by buf into binary, to be placed in mem
+   return a pointer to the character after the last byte written */
+
+static const char *
+hex2mem (byte *mem, const char *buf, unsigned bytes)
+{
+  if (bytes != 0)
+    {
+      do
+	{
+	  *mem++ = hex2byte (buf);
+	  buf += 2;
+	}
+      while (--bytes);
+    }
+  return buf;
+}
+
+#ifdef DBG_MEMORY_MAP
+static void
+read_memory_map (char *buffer, unsigned offset, unsigned length)
+{
+  const char *map = DBG_MEMORY_MAP;
+  const unsigned map_sz = strlen(map);
+  if (offset >= map_sz)
+    {
+      buffer[0] = 'l';
+      buffer[1] = '\0';
+      return;
+    }
+  if (offset + length > map_sz)
+    length = map_sz - offset;
+  buffer[0] = 'm';
+  memcpy (&buffer[1], &map[offset], length);
+  buffer[1+length] = '\0';
+}
+#endif
+
+/* write string like " nn:0123" and return pointer after it */
+#ifndef DBG_MIN_SIZE
+static char *
+format_reg_value (char *p, unsigned reg_num, const byte *value)
+{
+  char *d = p;
+  unsigned char i;
+  d = byte2hex(d, reg_num);
+  *d++ = ':';
+  value += REG_SIZE;
+  i = REG_SIZE;
+  do
+    {
+      d = byte2hex(d, *--value);
+    }
+  while (--i != 0);
+  *d++ = ';';
+  return d;
+}
+#endif /* DBG_MIN_SIZE */
+
+#ifdef __SDCC_gbz80
+/* saves all state.except PC and SP */
+static void
+save_cpu_state() __naked
+{
+  __asm
+	push	af
+	ld	a, l
+	ld	(#_state + R_HL + 0), a
+	ld	a, h
+	ld	(#_state + R_HL + 1), a
+	ld	hl, #_state + R_HL - 1
+	ld	(hl), d
+	dec	hl
+	ld	(hl), e
+	dec	hl
+	ld	(hl), b
+	dec	hl
+	ld	(hl), c
+	dec	hl
+	pop	bc
+	ld	(hl), b
+	dec	hl
+	ld	(hl), c
+	ret
+  __endasm;
+}
+
+/* restore CPU state and continue execution */
+static void
+rest_cpu_state() __naked
+{
+  __asm
+;restore SP
+	ld	a, (#_state + R_SP + 0)
+	ld	l,a
+	ld	a, (#_state + R_SP + 1)
+	ld	h,a
+	ld	sp, hl
+;push PC value as return address
+	ld	a, (#_state + R_PC + 0)
+	ld	l, a
+	ld	a, (#_state + R_PC + 1)
+	ld	h, a
+	push	hl
+;restore registers
+	ld	hl, #_state + R_AF
+	ld	c, (hl)
+	inc	hl
+	ld	b, (hl)
+	inc	hl
+	push	bc
+	ld	c, (hl)
+	inc	hl
+	ld	b, (hl)
+	inc	hl
+	ld	e, (hl)
+	inc	hl
+	ld	d, (hl)
+	inc	hl
+	ld	a, (hl)
+	inc	hl
+	ld	h, (hl)
+	ld	l, a
+	pop	af
+	ret
+  __endasm;
+}
+#else
+/* saves all state.except PC and SP */
+static void
+save_cpu_state() __naked
+{
+  __asm
+	ld	(#_state + R_HL), hl
+	ld	(#_state + R_DE), de
+	ld	(#_state + R_BC), bc
+	push	af
+	pop	hl
+	ld	(#_state + R_AF), hl
+	ld	a, r	;R is increased by 7 or by 8 if called via RST
+	ld	l, a
+	sub	a, #7
+	xor	a, l
+	and	a, #0x7f
+	xor	a, l
+#ifdef __SDCC_ez80_adl
+	ld	hl, i
+	ex	de, hl
+	ld	hl, #_state + R_IR
+	ld	(hl), a
+	inc	hl
+	ld	(hl), e
+	inc	hl
+	ld	(hl), d
+	ld	a, MB
+	ld	(#_state + R_AF+2), a
+#else
+	ld	l, a
+	ld	a, i
+	ld	h, a
+	ld	(#_state + R_IR), hl
+#endif /* __SDCC_ez80_adl */
+	ld	(#_state + R_IX), ix
+	ld	(#_state + R_IY), iy
+	ex	af, af'	;'
+	exx
+	ld	(#_state + R_HL_), hl
+	ld	(#_state + R_DE_), de
+	ld	(#_state + R_BC_), bc
+	push	af
+	pop	hl
+	ld	(#_state + R_AF_), hl
+	ret
+  __endasm;
+}
+
+/* restore CPU state and continue execution */
+static void
+rest_cpu_state() __naked
+{
+  __asm
+#ifdef DBG_USE_TRAMPOLINE
+	ld	sp, _stack + DBG_STACK_SIZE
+	ld	hl, (#_state + R_PC)
+	push	hl	/* resume address */
+#ifdef __SDCC_ez80_adl
+	ld	hl, 0xc30000 ; use 0xc34000 for jp.s
+#else
+	ld	hl, 0xc300
+#endif
+	push	hl	/* JP opcode */
+#endif /* DBG_USE_TRAMPOLINE */
+	ld	hl, (#_state + R_AF_)
+	push	hl
+	pop	af
+	ld	bc, (#_state + R_BC_)
+	ld	de, (#_state + R_DE_)
+	ld	hl, (#_state + R_HL_)
+	exx
+	ex	af, af'	;'
+	ld	iy, (#_state + R_IY)
+	ld	ix, (#_state + R_IX)
+#ifdef __SDCC_ez80_adl
+	ld	a, (#_state + R_AF + 2)
+	ld	MB, a
+	ld	hl, (#_state + R_IR + 1) ;I register
+	ld	i, hl
+	ld	a, (#_state + R_IR + 0) ; R register
+	ld	l, a
+#else
+	ld	hl, (#_state + R_IR)
+	ld	a, h
+	ld	i, a
+	ld	a, l
+#endif /* __SDCC_ez80_adl */
+	sub	a, #10	;number of M1 cycles after ld r,a
+	xor	a, l
+	and	a, #0x7f
+	xor	a, l
+	ld	r, a
+	ld	de, (#_state + R_DE)
+	ld	bc, (#_state + R_BC)
+	ld	hl, (#_state + R_AF)
+	push	hl
+	pop	af
+	ld	sp, (#_state + R_SP)
+#ifndef DBG_USE_TRAMPOLINE
+	ld	hl, (#_state + R_PC)
+	push	hl
+	ld	hl, (#_state + R_HL)
+	DBG_RESUME
+#else
+	ld	hl, (#_state + R_HL)
+#ifdef __SDCC_ez80_adl
+	jp	#_stack + DBG_STACK_SIZE - 4
+#else
+	jp	#_stack + DBG_STACK_SIZE - 3
+#endif
+#endif /* DBG_USE_TRAMPOLINE */
+  __endasm;
+}
+#endif /* __SDCC_gbz80 */
diff --git a/gdb/z80-tdep.c b/gdb/z80-tdep.c
new file mode 100644
index 000000000000..7b9a7e23501b
--- /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 ();
+}
diff --git a/gdb/z80-tdep.h b/gdb/z80-tdep.h
new file mode 100644
index 000000000000..4d73aeb17fad
--- /dev/null
+++ b/gdb/z80-tdep.h
@@ -0,0 +1,52 @@ 
+/* Target-dependent code for the Z80.
+
+   Copyright (C) 2002-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/>.  */
+
+#ifndef Z80_TDEP_H
+#define Z80_TDEP_H
+
+/* Register pair constants
+   Order optimized for gdb-stub implementation
+   Most of register pairs are 16 bit length on Z80 and
+   24 bit on eZ80 in ADL or MADL modes */
+enum z80_regnum
+{
+  Z80_AF_REGNUM,
+  Z80_BC_REGNUM,
+  Z80_DE_REGNUM,
+  Z80_HL_REGNUM,
+  Z80_SP_REGNUM,	/* SPL on eZ80 CPU */
+  Z80_PC_REGNUM,
+  Z80_IX_REGNUM,
+  Z80_IY_REGNUM,
+  Z80_AFA_REGNUM,
+  Z80_BCA_REGNUM,
+  Z80_DEA_REGNUM,
+  Z80_HLA_REGNUM,
+  Z80_IR_REGNUM,
+/* eZ80 only registers */
+  Z80_SPS_REGNUM	/* SPS register of eZ80 CPU */
+};
+
+#define Z80_NUM_REGS	13
+#define Z80_REG_BYTES	(Z80_NUM_REGS*2)
+
+#define EZ80_NUM_REGS	(Z80_NUM_REGS + 1)
+#define EZ80_REG_BYTES	(EZ80_NUM_REGS*3)
+
+#endif /* z80-tdep.h */