2326 lines
65 KiB
C
2326 lines
65 KiB
C
/* BDM/m68k specific low level interface, for the remote server for GDB.
|
|
Copyright (C) 1989, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2002, 2003,
|
|
2004, 2005, 2006, 2007 Free Software Foundation, Inc.
|
|
Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
|
|
2007 Chris Johns (chrisj@rtems.org).
|
|
Copyright (C) 1995 W. Eric Norum
|
|
Copyright (C) 2000 Bryan Feir (bryan@sgl.crestech.ca)
|
|
|
|
This file is part of M68K BDM.
|
|
|
|
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/>.
|
|
|
|
The code in the this file is based on the GDB server code in GDB and
|
|
the code in M68K BDM GDB patch file called 'remote-m68k-bdm.c'.
|
|
Based on:
|
|
1. `A Background Debug Mode Driver Package for Motorola's
|
|
16-bit and 32-Bit Microcontrollers', Scott Howard, Motorola
|
|
Canada, 1993.
|
|
2. `Linux device driver for public domain BDM Interface',
|
|
M. Schraut, Technische Universitaet Muenchen, Lehrstuhl
|
|
fuer Prozessrechner, 1995. */
|
|
|
|
#include <ctype.h>
|
|
#include <unistd.h>
|
|
|
|
#include "server.h"
|
|
#include "regdef.h"
|
|
|
|
#include "m68k-bdm-low.h"
|
|
|
|
/*
|
|
* Compare a string with a constant string.
|
|
*/
|
|
#define M68K_BDM_STR_IS(_s, _c) \
|
|
(strncmp (_s, _c, sizeof (_c) - 1) == 0)
|
|
|
|
/*
|
|
* Map the internal GDB wait kinds to the response letters for the
|
|
* remote protocol.
|
|
*/
|
|
#define TARGET_WAITKIND_STOPPED 'S'
|
|
#define TARGET_WAITKIND_TRAP 'T'
|
|
#define TARGET_WAITKIND_EXITED 'X'
|
|
|
|
/*
|
|
* The version of BDM hardware.
|
|
*/
|
|
#define M68K_BDM_VER_A (0)
|
|
#define M68K_BDM_VER_B (1)
|
|
#define M68K_BDM_VER_B_PLUS (9)
|
|
#define M68K_BDM_VER_C (2)
|
|
#define M68K_BDM_VER_D (3)
|
|
#define M68K_BDM_VER_D_PLUS (12)
|
|
|
|
/*
|
|
* The type of CPU.
|
|
*/
|
|
#define M68K_BDM_MARCH_68000 (0)
|
|
#define M68K_BDM_MARCH_CPU32 (1)
|
|
#define M68K_BDM_MARCH_CPU32PLUS (2)
|
|
#define M68K_BDM_MARCH_CF5200 (3)
|
|
#define M68K_BDM_MARCH_CF5235 (4)
|
|
#define M68K_BDM_MARCH_CF5272 (5)
|
|
#define M68K_BDM_MARCH_CF5282 (6)
|
|
#define M68K_BDM_MARCH_CF52223 (7)
|
|
#define M68K_BDM_MARCH_CF5307 (8)
|
|
#define M68K_BDM_MARCH_CFV4E (9)
|
|
|
|
/*
|
|
* The CPU labels.
|
|
*/
|
|
#define M68K_BDM_MARCH_68000_LABEL "68000"
|
|
#define M68K_BDM_MARCH_CPU32_LABEL "CPU32"
|
|
#define M68K_BDM_MARCH_CPU32PLUS_LABEL "CPU32+"
|
|
#define M68K_BDM_MARCH_CF5200_LABEL "CF5200"
|
|
#define M68K_BDM_MARCH_CF5235_LABEL "CF5235"
|
|
#define M68K_BDM_MARCH_CF5272_LABEL "CF5272"
|
|
#define M68K_BDM_MARCH_CF5282_LABEL "CF5282"
|
|
#define M68K_BDM_MARCH_CF52223_LABEL "CF52223"
|
|
#define M68K_BDM_MARCH_CF5307_LABEL "CF5307"
|
|
#define M68K_BDM_MARCH_CFV4E_LABEL "CFV4E"
|
|
|
|
/*
|
|
* The size of the register in bits.
|
|
*/
|
|
static const int m68k_bdm_reg_sizes[4] = { 32, 32, 32, 64 };
|
|
|
|
/*
|
|
* The array of registers for each support processor.
|
|
*/
|
|
struct m68k_bdm_registers {
|
|
const char const* xml_name;
|
|
const struct m68k_bdm_reg_mapping* map;
|
|
const int* num_regs;
|
|
int watchpoints;
|
|
int breakpoints;
|
|
};
|
|
|
|
/*
|
|
* The number of registers.
|
|
*/
|
|
#define M68K_BDM_NUM_REGS_BDM (*m68k_bdm_regs->num_regs)
|
|
|
|
/*
|
|
* Get a BDM register.
|
|
*/
|
|
#define M68K_BDM_REG_XML() (m68k_bdm_regs->xml_name)
|
|
#define M68K_BDM_REG_NAME_INDEXED(_r) (m68k_bdm_regs->map[_r].name)
|
|
#define M68K_BDM_REG_TYPE_INDEXED(_r) (m68k_bdm_regs->map[_r].type)
|
|
#define M68K_BDM_REG_NUM_INDEXED(_r) (m68k_bdm_regs->map[_r].num)
|
|
#define M68K_BDM_REG_CODE_INDEXED(_r) (m68k_bdm_regs->map[_r].code)
|
|
#define M68K_BDM_REG_FLAGS_INDEXED(_r) (m68k_bdm_regs->map[_r].flags)
|
|
#define M68K_BDM_REG_SIZE_INDEXED(_r) (m68k_bdm_reg_sizes[M68K_BDM_REG_TYPE_INDEXED (_r)])
|
|
#define M68K_BDM_REG_NAME(_r) M68K_BDM_REG_NAME_INDEXED(m68k_bdm_register_index (_r))
|
|
#define M68K_BDM_REG_TYPE(_r) M68K_BDM_REG_TYPE_INDEXED(m68k_bdm_register_index (_r))
|
|
#define M68K_BDM_REG_NUM(_r) M68K_BDM_REG_NUM_INDEXED(m68k_bdm_register_index (_r))
|
|
#define M68K_BDM_REG_CODE(_r) M68K_BDM_REG_CODE_INDEXED(m68k_bdm_register_index (_r))
|
|
#define M68K_BDM_REG_FLAGS(_r) M68K_BDM_REG_FLAGS_INDEXED(m68k_bdm_register_index (_r))
|
|
#define M68K_BDM_REG_SIZE(_r) M68K_BDM_REG_SIZE_INDEXED(m68k_bdm_register_index (_r))
|
|
|
|
/*
|
|
* The supported registers maps.
|
|
*/
|
|
|
|
extern const struct m68k_bdm_reg_mapping m68k_bdm_68000_reg_map[];
|
|
extern const int m68k_bdm_68000_reg_map_size;
|
|
extern const struct m68k_bdm_reg_mapping m68k_bdm_cpu32_reg_map[];
|
|
extern const int m68k_bdm_cpu32_reg_map_size;
|
|
extern const struct m68k_bdm_reg_mapping m68k_bdm_cpu32plus_reg_map[];
|
|
extern const int m68k_bdm_cpu32plus_reg_map_size;
|
|
extern const struct m68k_bdm_reg_mapping m68k_bdm_cf5200_reg_map[];
|
|
extern const int m68k_bdm_cf5200_reg_map_size;
|
|
extern const struct m68k_bdm_reg_mapping m68k_bdm_cf52223_reg_map[];
|
|
extern const int m68k_bdm_cf52223_reg_map_size;
|
|
extern const struct m68k_bdm_reg_mapping m68k_bdm_cf5235_reg_map[];
|
|
extern const int m68k_bdm_cf5235_reg_map_size;
|
|
extern const struct m68k_bdm_reg_mapping m68k_bdm_cf5272_reg_map[];
|
|
extern const int m68k_bdm_cf5272_reg_map_size;
|
|
extern const struct m68k_bdm_reg_mapping m68k_bdm_cf5282_reg_map[];
|
|
extern const int m68k_bdm_cf5282_reg_map_size;
|
|
extern const struct m68k_bdm_reg_mapping m68k_bdm_cf5307_reg_map[];
|
|
extern const int m68k_bdm_cf5307_reg_map_size;
|
|
extern const struct m68k_bdm_reg_mapping m68k_bdm_cfv4e_reg_map[];
|
|
extern const int m68k_bdm_cfv4e_reg_map_size;
|
|
|
|
/*
|
|
* Must match the type of CPU index at the start of this file.
|
|
*/
|
|
const struct m68k_bdm_registers m68k_bdm_reg_map[] = {
|
|
/* 0 */ { "m68k-core.xml",
|
|
m68k_bdm_68000_reg_map, &m68k_bdm_68000_reg_map_size, 0, 0 },
|
|
/* 1 */ { "m68k-cpu32.xml",
|
|
m68k_bdm_cpu32_reg_map, &m68k_bdm_cpu32_reg_map_size, 0, 0 },
|
|
/* 2 */ { "m68k-cpu32plus.xml",
|
|
m68k_bdm_cpu32plus_reg_map, &m68k_bdm_cpu32plus_reg_map_size, 0, 0 },
|
|
/* 3 */ { "m68k-cf5200.xml",
|
|
m68k_bdm_cf5200_reg_map, &m68k_bdm_cf5200_reg_map_size, 1, 1 },
|
|
/* 4 */ { "m68k-cf5235.xml",
|
|
m68k_bdm_cf5235_reg_map, &m68k_bdm_cf5235_reg_map_size, 1, 1 },
|
|
/* 5 */ { "m68k-cf5272.xml",
|
|
m68k_bdm_cf5272_reg_map, &m68k_bdm_cf5272_reg_map_size, 1, 1 },
|
|
/* 6 */ { "m68k-cf5282.xml",
|
|
m68k_bdm_cf5282_reg_map, &m68k_bdm_cf5282_reg_map_size, 1, 1 },
|
|
/* 7 */ { "m68k-cf52223.xml",
|
|
m68k_bdm_cf52223_reg_map, &m68k_bdm_cf52223_reg_map_size, 1, 4 },
|
|
/* 8 */ { "m68k-cf5307.xml",
|
|
m68k_bdm_cf5307_reg_map, &m68k_bdm_cf5307_reg_map_size, 1, 1 },
|
|
/* 9 */ { "m68k-cfv4e.xml",
|
|
m68k_bdm_cfv4e_reg_map, &m68k_bdm_cfv4e_reg_map_size, 2, 4 }
|
|
};
|
|
|
|
const char *m68k_bdm_expedite_regs[] = { "sp", "fp", "pc", 0 };
|
|
|
|
/*
|
|
* The name of the BDM driver special file
|
|
*/
|
|
static char* m68k_bdm_dev_name;
|
|
static int m68k_bdm_cpu_family;
|
|
static int m68k_bdm_cpu_type = M68K_BDM_MARCH_68000;
|
|
static const char* m68k_bdm_cpu_label = M68K_BDM_MARCH_68000_LABEL;
|
|
static const struct m68k_bdm_registers *m68k_bdm_regs = &m68k_bdm_reg_map[M68K_BDM_MARCH_68000];
|
|
|
|
static int m68k_bdm_kill_on_exit;
|
|
|
|
/*
|
|
* Hold BDM ATEMP register (CPU32 only).
|
|
*/
|
|
static unsigned long m68k_bdm_atemp;
|
|
static int m68k_bdm_have_atemp;
|
|
|
|
/*
|
|
* CF BDM Debug hardware version number.
|
|
*/
|
|
|
|
static unsigned long m68k_bdm_cf_debug_ver;
|
|
|
|
/*
|
|
* Have we set a debug level.
|
|
*/
|
|
static int m68k_bdm_debug_level;
|
|
|
|
/*
|
|
* give target time to come up after reset
|
|
* time in usec
|
|
*/
|
|
#define M68K_BDM_TIME_TO_COME_UP 60000
|
|
|
|
/*
|
|
* We are quitting, so do not call error and therefore
|
|
* jump back into the main event handler.
|
|
*/
|
|
static int m68k_bdm_gdb_is_quitting;
|
|
|
|
/*
|
|
* Release the processor on a close.
|
|
*/
|
|
static int m68k_bdm_release_on_exit;
|
|
|
|
/*
|
|
* Our pid.
|
|
*/
|
|
#define null_ptid (0)
|
|
|
|
unsigned long m68k_bdm_ptid;
|
|
|
|
/*
|
|
* The breakpoint codes for the different processors
|
|
*/
|
|
#define M68K_BDM_BREAKPOINT_SIZE_MAX (2)
|
|
static unsigned char m68k_bdm_cpu32_breakpoint[] = {0x4a, 0xfa};
|
|
static unsigned char m68k_bdm_cf_breakpoint[] = {0x4a, 0xc8};
|
|
static unsigned char* m68k_bdm_breakpoint_code = (unsigned char*) "\x4e\x41";
|
|
static unsigned int m68k_bdm_breakpoint_size = 2;
|
|
|
|
/*
|
|
* Trial of not stopping on an error.
|
|
*/
|
|
static int m68k_bdm_use_error;
|
|
|
|
/*
|
|
* Treat all breakpoints as hardware breakpoints.
|
|
*/
|
|
static int m68k_bdm_breakpoints_hard;
|
|
|
|
/*
|
|
* Display error message and jump back to main input loop
|
|
*/
|
|
static void
|
|
m68k_bdm_report_error (void)
|
|
{
|
|
if (!m68k_bdm_gdb_is_quitting)
|
|
{
|
|
if (m68k_bdm_use_error)
|
|
error ("m68k-bdm: error: %s", bdmErrorString ());
|
|
else
|
|
printf_filtered ("m68k-bdm: error: %s", bdmErrorString ());
|
|
}
|
|
}
|
|
|
|
static void
|
|
m68k_bdm_help (void)
|
|
{
|
|
printf_filtered ("%s\n" \
|
|
"%s -vVhBDd -t <time> <device>\n" \
|
|
"\t-v\tVerbose. More than one the more verbose.\n" \
|
|
"\t-V\tVersion.\n" \
|
|
"\t-h\tThis help.\n" \
|
|
"\t-B\tTreat all breakpoints as hardware breakpoints. Useful for flash.\n" \
|
|
"\t-D\tDriver debug level. More than one for more debug.\n" \
|
|
"\t-d\tBDM Library debug level. More than one for more debug.\n" \
|
|
"\t-t time\tDelay timing for the parallel ports.\n" \
|
|
"\tdevice\tThe device to connect to such as /dev/bdmcf0.\n",
|
|
PACKAGE_STRING, PACKAGE_NAME);
|
|
}
|
|
|
|
static void
|
|
m68k_bdm_version (void)
|
|
{
|
|
printf_filtered ("%s\n" \
|
|
"%s is free software, covered by the GNU General Public License.\n" \
|
|
"Reports bugs to %s.\n",
|
|
PACKAGE_STRING, PACKAGE_NAME, PACKAGE_BUGREPORT);
|
|
}
|
|
|
|
static int
|
|
m68k_bdm_register_index (int regno)
|
|
{
|
|
int index;
|
|
for (index = 0; index < M68K_BDM_NUM_REGS_BDM; index++)
|
|
if (M68K_BDM_REG_NUM_INDEXED (index) == regno)
|
|
return index;
|
|
fatal ("m68k-bdm: no register found: %d", regno);
|
|
}
|
|
|
|
static int
|
|
m68k_bdm_register_index_by_name (const char* name)
|
|
{
|
|
int index;
|
|
for (index = 0; index < M68K_BDM_NUM_REGS_BDM; index++)
|
|
if (M68K_BDM_STR_IS (name, M68K_BDM_REG_NAME_INDEXED (index)))
|
|
return index;
|
|
fatal ("m68k-bdm: no register found: %s", name);
|
|
}
|
|
|
|
static int
|
|
m68k_bdm_register_by_name (const char* name)
|
|
{
|
|
return M68K_BDM_REG_CODE_INDEXED (m68k_bdm_register_index_by_name (name));
|
|
}
|
|
|
|
static int
|
|
m68k_bdm_register_offset (int regno)
|
|
{
|
|
int index;
|
|
int offset = 0;
|
|
for (index = 0; index < M68K_BDM_NUM_REGS_BDM; index++) {
|
|
if (M68K_BDM_REG_NUM_INDEXED (index) == regno)
|
|
return offset;
|
|
if (M68K_BDM_REG_NUM_INDEXED (index) < regno)
|
|
offset += M68K_BDM_REG_SIZE_INDEXED (index);
|
|
}
|
|
fatal ("m68k-bdm: no register found: %d", regno);
|
|
}
|
|
|
|
static void
|
|
m68k_bdm_init_registers (void)
|
|
{
|
|
int reg;
|
|
struct reg *regs;
|
|
|
|
m68k_bdm_regs = &m68k_bdm_reg_map[m68k_bdm_cpu_type];
|
|
|
|
regs = calloc (sizeof (struct reg), M68K_BDM_NUM_REGS_BDM);
|
|
|
|
if (!regs)
|
|
fatal ("m68k-bdm: no memory for regs");
|
|
|
|
for (reg = 0; reg < M68K_BDM_NUM_REGS_BDM; reg++) {
|
|
regs[reg].name = M68K_BDM_REG_NAME (reg);
|
|
regs[reg].offset = m68k_bdm_register_offset (reg);
|
|
regs[reg].size = M68K_BDM_REG_SIZE (reg);
|
|
regs[reg].flags = M68K_BDM_REG_FLAGS (reg);
|
|
}
|
|
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: registers xml:%s number:%d size:%d\n",
|
|
M68K_BDM_REG_XML(), M68K_BDM_NUM_REGS_BDM,
|
|
m68k_bdm_register_offset (M68K_BDM_NUM_REGS_BDM - 1));
|
|
|
|
set_register_cache (regs, M68K_BDM_NUM_REGS_BDM);
|
|
gdbserver_expedite_regs = m68k_bdm_expedite_regs;
|
|
}
|
|
|
|
/*
|
|
* Read a system or control registers.
|
|
*/
|
|
static int
|
|
m68k_bdm_read_sys_ctl_reg (const char* name, int cregno, unsigned long* l)
|
|
{
|
|
int ret;
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68K_bdm_read_sys_ctl_reg: %s (0x%03x)\n",
|
|
name, cregno & BDM_REG_MASK);
|
|
if (cregno & BDM_REG_VIRTUAL_REG) {
|
|
*l = ((cregno & BDM_REG_MASK) << 16) | (cregno & BDM_REG_MASK);
|
|
ret = 0;
|
|
}
|
|
else if (cregno & BDM_REG_CONTROL_REG)
|
|
ret = bdmReadControlRegister (cregno & BDM_REG_CONTROL_REG_MASK, l);
|
|
else if (cregno & BDM_REG_DEBUG_REG)
|
|
ret = bdmReadDebugRegister (cregno & BDM_REG_DEBUG_REG_MASK, l);
|
|
else
|
|
ret = bdmReadSystemRegister (cregno, l);
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Write a system or control registers.
|
|
*/
|
|
static int
|
|
m68k_bdm_write_sys_ctl_reg (const char* name, int cregno, unsigned long l)
|
|
{
|
|
int ret;
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k_bdm_write_sys_ctl_reg: %s (0x%03x)\n",
|
|
name, cregno & BDM_REG_CONTROL_REG_MASK);
|
|
if (cregno & BDM_REG_CONTROL_REG)
|
|
ret = bdmWriteControlRegister (cregno & BDM_REG_CONTROL_REG_MASK, l);
|
|
else if (cregno & BDM_REG_DEBUG_REG)
|
|
ret = bdmWriteDebugRegister (cregno & BDM_REG_DEBUG_REG_MASK, l);
|
|
else
|
|
ret = bdmWriteSystemRegister (cregno, l);
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* The following routines handle the Coldfire hardware breakpoints. Only one
|
|
* breakpoint supported so far, and it can be either a PC breakpoint or an
|
|
* address watchpoint. Unfortunately, the TARGET_CAN_USE_HARDWARE_WATCHPOINT
|
|
* macro only allows for bounds checking within one of the two types and not
|
|
* limits that cover the sum of both, so extra work is needed.
|
|
*
|
|
* (Actually, very few processors seem to have much support for that routine
|
|
* at all.)
|
|
*
|
|
* As a result, the way this is handled is that the can_use routine will allow
|
|
* the first breakpoint of either type to be added. Any further checking so
|
|
* that only one of the two can be used is done later when GDB actually tries
|
|
* to create the breakpoints, usually when the processor is restarted.
|
|
*
|
|
* We keep a local copy of the breakpoints list becasue the chain that GDB
|
|
* keeps isn't exported globally.
|
|
*
|
|
* While things could be simplified with only one breakpoint present, setting
|
|
* up more general routines allows for later expansion if newer versions of
|
|
* the ColdFire chip support more breakpoints at once.
|
|
*
|
|
* Also, the ColdFire supports things like multi-level triggers and triggers
|
|
* based on the data bus instead of just the address bus. The GDB commands
|
|
* don't allow for access to this, but much of it isn't necessary anyway,
|
|
* as GDB has its own method of handling 'breakpoint conditions' that is
|
|
* sufficient for most tasks.
|
|
*/
|
|
|
|
#define TDR_TRC_DDATA 0x00000000
|
|
#define TDR_TRC_HALT 0x40000000
|
|
#define TDR_TRC_DINT 0x80000000
|
|
#define TDR_L2_EBL 0x20000000
|
|
#define TDR_L2_ALL 0x1FFF0000
|
|
#define TDR_L2_EDLW 0x10000000
|
|
#define TDR_L2_EDWL 0x08000000
|
|
#define TDR_L2_EDWU 0x04000000
|
|
#define TDR_L2_EDLL 0x02000000
|
|
#define TDR_L2_EDLM 0x01000000
|
|
#define TDR_L2_EDUM 0x00800000
|
|
#define TDR_L2_EDUU 0x00400000
|
|
#define TDR_L2_DI 0x00200000
|
|
#define TDR_L2_EAI 0x00100000
|
|
#define TDR_L2_EAR 0x00080000
|
|
#define TDR_L2_EAL 0x00040000
|
|
#define TDR_L2_EPC 0x00020000
|
|
#define TDR_L2_PCI 0x00010000
|
|
#define TDR_L1_EBL 0x00002000
|
|
#define TDR_L1_ALL 0x00001FFF
|
|
#define TDR_L1_EDLW 0x00001000
|
|
#define TDR_L1_EDWL 0x00000800
|
|
#define TDR_L1_EDWU 0x00000400
|
|
#define TDR_L1_EDLL 0x00000200
|
|
#define TDR_L1_EDLM 0x00000100
|
|
#define TDR_L1_EDUM 0x00000080
|
|
#define TDR_L1_EDUU 0x00000040
|
|
#define TDR_L1_DI 0x00000020
|
|
#define TDR_L1_EAI 0x00000010
|
|
#define TDR_L1_EAR 0x00000008
|
|
#define TDR_L1_EAL 0x00000004
|
|
#define TDR_L1_EPC 0x00000002
|
|
#define TDR_L1_PCI 0x00000001
|
|
|
|
/*
|
|
* The type is coded as follows:
|
|
* 0 = software breakpoint
|
|
* 1 = hardware breakpoint
|
|
* 2 = write watchpoint
|
|
* 3 = read watchpoint
|
|
* 4 = access watchpoint
|
|
*/
|
|
#define M68K_BDM_WP_TYPE_BREAK ('0')
|
|
#define M68K_BDM_WP_TYPE_HBREAK ('1')
|
|
#define M68K_BDM_WP_TYPE_WRITE ('2')
|
|
#define M68K_BDM_WP_TYPE_READ ('3')
|
|
#define M68K_BDM_WP_TYPE_ACCESS ('4')
|
|
#define M68K_BDM_WP_TYPE_EXEC ('5')
|
|
|
|
struct m68k_bdm_watch {
|
|
char type;
|
|
CORE_ADDR addr;
|
|
int len;
|
|
};
|
|
|
|
struct m68k_bdm_break {
|
|
CORE_ADDR addr;
|
|
int len;
|
|
unsigned char code[M68K_BDM_BREAKPOINT_SIZE_MAX];
|
|
};
|
|
|
|
/*
|
|
* We can have a variable number of hardware watch and break
|
|
* points.
|
|
*/
|
|
static struct m68k_bdm_watch* m68k_bdm_hwatchpoints;
|
|
static int m68k_bdm_hbreakpoint_max;
|
|
static struct m68k_bdm_watch* m68k_bdm_hbreakpoints;
|
|
static int m68k_bdm_hwatchpoint_max;
|
|
static int m68k_bdm_hit_watchpoint;
|
|
|
|
/*
|
|
* An array that increases in size as more break points are added. It
|
|
* does not decrease in size.
|
|
*/
|
|
#define M68K_BDM_BREAKPOINT_BLOCK_SIZE (50)
|
|
static struct m68k_bdm_break *m68k_bdm_breakpoints;
|
|
static int m68k_bdm_num_breakpoints;
|
|
|
|
static int
|
|
m68k_bdm_init_watchpoints(void)
|
|
{
|
|
/*
|
|
* Return 0 if not supported as an error will abort this program.
|
|
*/
|
|
if (m68k_bdm_cpu_family != BDM_COLDFIRE)
|
|
return 0;
|
|
|
|
m68k_bdm_hwatchpoint_max = m68k_bdm_reg_map[m68k_bdm_cpu_type].watchpoints;
|
|
m68k_bdm_hbreakpoint_max = m68k_bdm_reg_map[m68k_bdm_cpu_type].breakpoints;
|
|
|
|
/*
|
|
* Nothing defined is an error for a Coldfire.
|
|
*/
|
|
if ((m68k_bdm_hwatchpoint_max == 0) && (m68k_bdm_hbreakpoint_max == 0))
|
|
return -1;
|
|
|
|
if (bdmWriteSystemRegister (BDM_REG_TDR, TDR_TRC_HALT) < 0) {
|
|
m68k_bdm_report_error ();
|
|
return -1;
|
|
}
|
|
|
|
m68k_bdm_hwatchpoints = calloc (m68k_bdm_hwatchpoint_max,
|
|
sizeof (struct m68k_bdm_watch));
|
|
|
|
if (!m68k_bdm_hwatchpoints)
|
|
return -1;
|
|
|
|
m68k_bdm_hbreakpoints = calloc (m68k_bdm_hbreakpoint_max,
|
|
sizeof (struct m68k_bdm_watch));
|
|
|
|
if (!m68k_bdm_hbreakpoints) {
|
|
free (m68k_bdm_hwatchpoints);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
m68k_bdm_get_pbr_register (int index)
|
|
{
|
|
char pbr[6];
|
|
|
|
if (index == 0)
|
|
strcpy (pbr, "pbr");
|
|
else
|
|
sprintf (pbr, "pbr%d", index);
|
|
|
|
return m68k_bdm_register_by_name (pbr);
|
|
}
|
|
|
|
static int
|
|
m68k_bdm_get_ablr_register (int index)
|
|
{
|
|
char ablr[6];
|
|
|
|
if (index == 0)
|
|
strcpy (ablr, "ablr");
|
|
else
|
|
sprintf (ablr, "ablr%d", index);
|
|
|
|
return m68k_bdm_register_by_name (ablr);
|
|
}
|
|
|
|
static int
|
|
m68k_bdm_get_abhr_register (int index)
|
|
{
|
|
char abhr[6];
|
|
|
|
if (index == 0)
|
|
strcpy (abhr, "abhr");
|
|
else
|
|
sprintf (abhr, "abhr%d", index);
|
|
|
|
return m68k_bdm_register_by_name (abhr);
|
|
}
|
|
|
|
static int
|
|
m68k_bdm_find_hbreakpoint (char type, CORE_ADDR addr, int len)
|
|
{
|
|
int i;
|
|
for (i = 0; i < m68k_bdm_hbreakpoint_max; i++) {
|
|
if (m68k_bdm_hbreakpoints[i].type == type &&
|
|
m68k_bdm_hbreakpoints[i].addr == addr &&
|
|
m68k_bdm_hbreakpoints[i].len == len) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int
|
|
m68k_bdm_find_hwatchpoint (char type, CORE_ADDR addr, int len)
|
|
{
|
|
int i;
|
|
for (i = 0; i < m68k_bdm_hwatchpoint_max; i++) {
|
|
if (m68k_bdm_hwatchpoints[i].type == type &&
|
|
m68k_bdm_hwatchpoints[i].addr == addr &&
|
|
m68k_bdm_hwatchpoints[i].len == len) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int
|
|
m68k_bdm_hbreakpoint_active ()
|
|
{
|
|
int i;
|
|
int c;
|
|
for (c = 0, i = 0; i < m68k_bdm_hbreakpoint_max; i++)
|
|
if (m68k_bdm_hbreakpoints[i].len)
|
|
c++;
|
|
return c;
|
|
}
|
|
|
|
#if NOTUSED
|
|
static int
|
|
m68k_bdm_hwatchpoint_active ()
|
|
{
|
|
int i;
|
|
int c;
|
|
for (c = 0, i = 0; i < m68k_bdm_hwatchpoint_max; i++)
|
|
if (m68k_bdm_hwatchpoints[i].len)
|
|
c++;
|
|
return c;
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
m68k_bdm_grow_breakpoints (int count)
|
|
{
|
|
struct m68k_bdm_break *new_breakpoints;
|
|
new_breakpoints = calloc(m68k_bdm_num_breakpoints + count,
|
|
sizeof (struct m68k_bdm_break));
|
|
if (!new_breakpoints)
|
|
fatal("no memory for breakpoints");
|
|
if (m68k_bdm_breakpoints) {
|
|
memcpy (new_breakpoints, m68k_bdm_breakpoints,
|
|
m68k_bdm_num_breakpoints * sizeof (struct m68k_bdm_break));
|
|
free (m68k_bdm_breakpoints);
|
|
}
|
|
m68k_bdm_breakpoints = new_breakpoints;
|
|
m68k_bdm_num_breakpoints += count;
|
|
}
|
|
|
|
static int
|
|
m68k_bdm_insert_breakpoint (char type, CORE_ADDR addr, int len)
|
|
{
|
|
unsigned long tdr;
|
|
int pbr;
|
|
int hb;
|
|
|
|
if (!m68k_bdm_breakpoints_hard && (type == M68K_BDM_WP_TYPE_BREAK)) {
|
|
int next_free = -1;
|
|
|
|
if (len != m68k_bdm_breakpoint_size) {
|
|
warning ("m68k-bdm: invalid breakpoint size");
|
|
}
|
|
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: insert breakpoint @0x%08lx\n",
|
|
(unsigned long) addr);
|
|
|
|
if (m68k_bdm_breakpoints) {
|
|
/*
|
|
* Do we already have a breakpoint set at this address ?
|
|
* Which is the next free bp slot ?
|
|
*/
|
|
|
|
int bp;
|
|
for (bp = 0; bp < m68k_bdm_num_breakpoints; bp++) {
|
|
if (m68k_bdm_breakpoints[bp].len) {
|
|
if (m68k_bdm_breakpoints[bp].addr == addr)
|
|
return 0;
|
|
}
|
|
else if (next_free < 0)
|
|
next_free = bp;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Are all the slots free ?
|
|
*/
|
|
if (next_free < 0) {
|
|
next_free = m68k_bdm_num_breakpoints;
|
|
m68k_bdm_grow_breakpoints (M68K_BDM_BREAKPOINT_BLOCK_SIZE);
|
|
}
|
|
|
|
m68k_bdm_breakpoints[next_free].addr = addr;
|
|
m68k_bdm_breakpoints[next_free].len = len;
|
|
|
|
if (bdmReadMemory (addr,
|
|
m68k_bdm_breakpoints[next_free].code,
|
|
m68k_bdm_breakpoint_size) < 0) {
|
|
m68k_bdm_report_error ();
|
|
return 1;
|
|
}
|
|
|
|
if (bdmWriteMemory (addr,
|
|
m68k_bdm_breakpoint_code,
|
|
m68k_bdm_breakpoint_size) < 0) {
|
|
m68k_bdm_report_error ();
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Hardware breakpoints.
|
|
*/
|
|
|
|
if (m68k_bdm_cpu_family != BDM_COLDFIRE)
|
|
return 1;
|
|
|
|
hb = m68k_bdm_find_hbreakpoint (M68K_BDM_WP_TYPE_HBREAK, addr, 2);
|
|
|
|
if (hb >= 0)
|
|
return 0;
|
|
|
|
for (hb = 0; hb < m68k_bdm_hbreakpoint_max; hb++)
|
|
if (!m68k_bdm_hbreakpoints[hb].len)
|
|
break;
|
|
|
|
if (hb == m68k_bdm_hbreakpoint_max)
|
|
return -1;
|
|
|
|
m68k_bdm_hbreakpoints[hb].type = M68K_BDM_WP_TYPE_HBREAK;
|
|
m68k_bdm_hbreakpoints[hb].addr = addr;
|
|
m68k_bdm_hbreakpoints[hb].len = 2;
|
|
|
|
if (bdmReadSystemRegister (BDM_REG_TDR, &tdr) < 0)
|
|
m68k_bdm_report_error ();
|
|
|
|
tdr |= TDR_L1_EBL | TDR_L1_EPC;
|
|
|
|
/*
|
|
* If the BDM version is C then each PBR register has a
|
|
* valid bit (bit 0). If not the first PBR is controlled
|
|
* by the TDR bits and any more if they exist have valid
|
|
* bits.
|
|
*/
|
|
|
|
if ((m68k_bdm_cf_debug_ver == M68K_BDM_VER_C) || (hb > 0))
|
|
addr |= 1;
|
|
|
|
pbr = m68k_bdm_get_pbr_register (hb);
|
|
|
|
if (bdmWriteDebugRegister (pbr, addr) < 0)
|
|
m68k_bdm_report_error ();
|
|
|
|
if (bdmWriteSystemRegister (BDM_REG_PBMR, 0) < 0)
|
|
m68k_bdm_report_error ();
|
|
if (bdmWriteSystemRegister (BDM_REG_TDR, tdr) < 0)
|
|
m68k_bdm_report_error ();
|
|
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: insert hbreakpoint:%d: @0x%08lx\n",
|
|
hb, (unsigned long) addr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
m68k_bdm_remove_breakpoint (char type, CORE_ADDR addr, int len)
|
|
{
|
|
unsigned long tdr;
|
|
int pbr;
|
|
int hb;
|
|
|
|
if (!m68k_bdm_breakpoints_hard && (type == M68K_BDM_WP_TYPE_BREAK)) {
|
|
int bp;
|
|
for (bp = 0; bp < m68k_bdm_num_breakpoints; bp++) {
|
|
if (m68k_bdm_breakpoints[bp].len) {
|
|
if (m68k_bdm_breakpoints[bp].addr == addr) {
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: remove breakpoint @0x%08lx\n",
|
|
(unsigned long) addr);
|
|
m68k_bdm_breakpoints[bp].addr = 0;
|
|
m68k_bdm_breakpoints[bp].len = 0;
|
|
if (bdmWriteMemory (addr,
|
|
m68k_bdm_breakpoints[bp].code,
|
|
m68k_bdm_breakpoint_size) < 0) {
|
|
m68k_bdm_report_error ();
|
|
return 1;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Hardware breakpoints.
|
|
*/
|
|
|
|
if (m68k_bdm_cpu_family != BDM_COLDFIRE)
|
|
return 1;
|
|
|
|
hb = m68k_bdm_find_hbreakpoint (M68K_BDM_WP_TYPE_HBREAK, addr, 2);
|
|
|
|
if (hb < 0)
|
|
return -1;
|
|
|
|
if (bdmReadSystemRegister (BDM_REG_TDR, &tdr) < 0)
|
|
m68k_bdm_report_error ();
|
|
|
|
/*
|
|
* If the BDM version is not C and there is more than one PBR
|
|
* register then we need to move the higher PBR registers down
|
|
* from PBR registers with the valid bit to PBR(0) or turn
|
|
* off the trigger in the TDR register.
|
|
*/
|
|
|
|
pbr = m68k_bdm_get_pbr_register (hb);
|
|
|
|
if ((hb == 0) &&
|
|
(m68k_bdm_cf_debug_ver != M68K_BDM_VER_C) &&
|
|
(m68k_bdm_hbreakpoint_max > 1)) {
|
|
/*
|
|
* See if any other breakpoints are set. If one is move to
|
|
* slot 0.
|
|
*/
|
|
int bp;
|
|
for (bp = 1; bp < m68k_bdm_hbreakpoint_max; bp++) {
|
|
if (m68k_bdm_hbreakpoints[bp].len) {
|
|
if (bdmWriteDebugRegister (pbr, m68k_bdm_hbreakpoints[bp].addr) < 0)
|
|
m68k_bdm_report_error ();
|
|
pbr = m68k_bdm_get_pbr_register (bp);
|
|
m68k_bdm_hbreakpoints[0] = m68k_bdm_hbreakpoints[bp];
|
|
m68k_bdm_hbreakpoints[bp].len = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (bp == m68k_bdm_hbreakpoint_max)
|
|
m68k_bdm_hbreakpoints[hb].len = 0;
|
|
}
|
|
else
|
|
m68k_bdm_hbreakpoints[hb].len = 0;
|
|
|
|
/*
|
|
* Assume all PBR registers have a valid bit.
|
|
*/
|
|
if (bdmWriteDebugRegister (pbr, 0) < 0)
|
|
m68k_bdm_report_error ();
|
|
|
|
if (!m68k_bdm_hbreakpoint_active ())
|
|
tdr &= ~TDR_L1_EPC;
|
|
|
|
if ((tdr & TDR_L1_ALL) == 0)
|
|
tdr &= ~TDR_L1_EBL;
|
|
|
|
if (bdmWriteSystemRegister (BDM_REG_TDR, tdr) < 0)
|
|
m68k_bdm_report_error ();
|
|
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: remove hbreakpoint:%d: @0x%08lx\n",
|
|
hb, (unsigned long) addr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define AATR_READONLY 0x7F85
|
|
#define AATR_WRITEONLY 0x7F05
|
|
#define AATR_READWRITE 0xFF05
|
|
|
|
static int
|
|
m68k_bdm_insert_watchpoint (char type, CORE_ADDR addr, int len)
|
|
{
|
|
int tdr;
|
|
unsigned long tdr_value;
|
|
int ablr;
|
|
int abhr;
|
|
int hw;
|
|
|
|
if (m68k_bdm_cpu_family != BDM_COLDFIRE)
|
|
return 1;
|
|
|
|
hw = m68k_bdm_find_hwatchpoint (type, addr, len);
|
|
|
|
if (hw >= 0)
|
|
return 0;
|
|
|
|
for (hw = 0; hw < m68k_bdm_hwatchpoint_max; hw++)
|
|
if (!m68k_bdm_hwatchpoints[hw].len)
|
|
break;
|
|
|
|
if (hw == m68k_bdm_hwatchpoint_max)
|
|
return -1;
|
|
|
|
m68k_bdm_hwatchpoints[hw].type = type;
|
|
m68k_bdm_hwatchpoints[hw].addr = addr;
|
|
m68k_bdm_hwatchpoints[hw].len = len;
|
|
|
|
/*
|
|
* If the BDM version is C then we have 2 TDR registers
|
|
*/
|
|
if ((m68k_bdm_cf_debug_ver == M68K_BDM_VER_C) && (hw > 0))
|
|
tdr = m68k_bdm_register_by_name ("xtdr");
|
|
else
|
|
tdr = m68k_bdm_register_by_name ("tdr");
|
|
|
|
if (bdmReadDebugRegister (tdr, &tdr_value) < 0)
|
|
m68k_bdm_report_error ();
|
|
|
|
tdr_value |= TDR_L1_EBL | TDR_L1_EAR;
|
|
|
|
ablr = m68k_bdm_get_ablr_register (hw);
|
|
abhr = m68k_bdm_get_abhr_register (hw);
|
|
|
|
if (bdmWriteDebugRegister (ablr, addr) < 0)
|
|
m68k_bdm_report_error ();
|
|
if (bdmWriteDebugRegister (abhr, addr + len - 1) < 0)
|
|
m68k_bdm_report_error ();
|
|
|
|
if (type == M68K_BDM_WP_TYPE_READ) {
|
|
if (bdmWriteSystemRegister (BDM_REG_AATR, AATR_READONLY) < 0)
|
|
m68k_bdm_report_error ();
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: insert read hwatchpoint:%d: @0x%08lx-0x%08lx\n",
|
|
hw,
|
|
(unsigned long) addr, (unsigned long) addr + len - 1);
|
|
}
|
|
else if (type == M68K_BDM_WP_TYPE_WRITE) {
|
|
if (bdmWriteSystemRegister (BDM_REG_AATR, AATR_WRITEONLY) < 0)
|
|
m68k_bdm_report_error ();
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: insert write hwatchpoint:%d @0x%08lx-0x%08lx\n",
|
|
hw,
|
|
(long unsigned int) addr, (unsigned long) addr + len - 1);
|
|
}
|
|
else {
|
|
if (bdmWriteSystemRegister (BDM_REG_AATR, AATR_READWRITE) < 0)
|
|
m68k_bdm_report_error ();
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: insert access hwatchpoint:%d @0x%08lx-0x%08lx\n",
|
|
hw,
|
|
(unsigned long) addr, (unsigned long) addr + len - 1);
|
|
}
|
|
|
|
if (bdmWriteDebugRegister (tdr, tdr_value) < 0)
|
|
m68k_bdm_report_error ();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
m68k_bdm_remove_watchpoint (char type, CORE_ADDR addr, int len)
|
|
{
|
|
int tdr;
|
|
unsigned long tdr_value;
|
|
int hw;
|
|
|
|
if (m68k_bdm_cpu_family != BDM_COLDFIRE)
|
|
return -1;
|
|
|
|
hw = m68k_bdm_find_hwatchpoint (type, addr, len);
|
|
|
|
if (hw < 0)
|
|
return -1;
|
|
|
|
m68k_bdm_hwatchpoints[hw].len = 0;
|
|
|
|
/*
|
|
* If the BDM version is C then we have 2 TDR registers
|
|
*/
|
|
if ((m68k_bdm_cf_debug_ver == M68K_BDM_VER_C) && (hw > 0))
|
|
tdr = m68k_bdm_register_by_name ("xtdr");
|
|
else
|
|
tdr = m68k_bdm_register_by_name ("tdr");
|
|
|
|
if (bdmReadDebugRegister (tdr, &tdr_value) < 0)
|
|
m68k_bdm_report_error ();
|
|
|
|
tdr &= ~TDR_L1_EAR;
|
|
|
|
if ((tdr & TDR_L1_ALL) == 0)
|
|
tdr &= ~TDR_L1_EBL;
|
|
|
|
if (bdmWriteDebugRegister (tdr, tdr_value) < 0)
|
|
m68k_bdm_report_error ();
|
|
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: remove %s watchpoint:%d: @0x%08lx-0x%08lx\n",
|
|
(type == M68K_BDM_WP_TYPE_READ) ? "read" :
|
|
((type == M68K_BDM_WP_TYPE_WRITE) ? "write" : "access"),
|
|
hw,
|
|
(unsigned long) addr, (unsigned long) addr + len - 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
m68k_bdm_insert_point (char type, CORE_ADDR addr, int len)
|
|
{
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: inserting type:%c @0x%08lx %i\n",
|
|
type, (unsigned long) addr, len);
|
|
if ((type == M68K_BDM_WP_TYPE_BREAK) || (type == M68K_BDM_WP_TYPE_HBREAK))
|
|
return m68k_bdm_insert_breakpoint (type, addr, len);
|
|
return m68k_bdm_insert_watchpoint (type, addr, len);
|
|
}
|
|
|
|
static int
|
|
m68k_bdm_remove_point (char type, CORE_ADDR addr, int len)
|
|
{
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: removing type:%c @0x%08lx %i\n",
|
|
type, (unsigned long) addr, len);
|
|
if ((type == M68K_BDM_WP_TYPE_BREAK) || (type == M68K_BDM_WP_TYPE_HBREAK))
|
|
return m68k_bdm_remove_breakpoint (type, addr, len);
|
|
return m68k_bdm_remove_watchpoint (type, addr, len);
|
|
}
|
|
|
|
static int
|
|
m68k_bdm_stopped_by_watchpoint (void)
|
|
{
|
|
return m68k_bdm_hit_watchpoint;
|
|
}
|
|
|
|
static CORE_ADDR
|
|
m68k_bdm_stopped_data_address (void)
|
|
{
|
|
unsigned long tdr;
|
|
unsigned long ablr;
|
|
|
|
if (m68k_bdm_cpu_family != BDM_COLDFIRE)
|
|
return 0;
|
|
|
|
if (bdmReadSystemRegister (BDM_REG_TDR, &tdr) < 0)
|
|
m68k_bdm_report_error ();
|
|
if (bdmReadSystemRegister (BDM_REG_ABLR, &ablr) < 0)
|
|
m68k_bdm_report_error ();
|
|
|
|
if (tdr & TDR_L1_EAR) {
|
|
return (CORE_ADDR) ablr;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#ifdef SYSCALL_TRAP
|
|
/* Immediately after a function call, return the saved pc before the frame
|
|
is setup. For uCLinux which uses a TRAP #0 for a system call we need to
|
|
read the first long word of the stack to see if the stack frame format is
|
|
type 4 and the vector is 32 (0x4080), and the opcode at the PC is
|
|
"move.w #0x2700,sr". If it is then get the second long from the stack. */
|
|
|
|
CORE_ADDR
|
|
m68k_bdm_saved_pc_after_call (struct frame_info *frame)
|
|
{
|
|
unsigned int op;
|
|
unsigned int eframe;
|
|
int sp;
|
|
|
|
if(!IS_BDM)
|
|
return gdbarch_saved_pc_after_call (current_gdbarch, frame);
|
|
|
|
sp = read_register (SP_REGNUM);
|
|
eframe = read_memory_integer (sp, 2);
|
|
op = read_memory_integer (frame->pc, 4);
|
|
|
|
/*
|
|
* This test could break if some changes the syste call.
|
|
*/
|
|
|
|
if (eframe == 0x4080 && op == 0x46fc2700)
|
|
return read_memory_integer (sp + 4, 4);
|
|
else
|
|
return read_memory_integer (sp, 4);
|
|
}
|
|
#endif /* SYSCALL_TRAP */
|
|
|
|
/*
|
|
* Short pause
|
|
*/
|
|
static void
|
|
m68k_bdm_nap (int microseconds)
|
|
{
|
|
#if defined (__MINGW32__)
|
|
Sleep (microseconds / 1000);
|
|
#else
|
|
struct timeval tv;
|
|
tv.tv_sec = microseconds / 1000000;
|
|
tv.tv_usec = microseconds % 1000000;
|
|
select (0, NULL, NULL, NULL, &tv);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Return interface status
|
|
*/
|
|
static int
|
|
m68k_bdm_get_status (void)
|
|
{
|
|
int status;
|
|
|
|
if ((status = bdmStatus ()) < 0)
|
|
m68k_bdm_report_error ();
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* release chip: reset and disable bdm mode
|
|
*/
|
|
#if 0
|
|
static void
|
|
m68k_bdm_release_chip (void)
|
|
{
|
|
m68k_bdm_have_atemp = 0;
|
|
m68k_bdm_ptid = null_ptid;
|
|
if (bdmRelease () < 0)
|
|
m68k_bdm_report_error ();
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* stop chip
|
|
*/
|
|
static void
|
|
m68k_bdm_stop_chip (void)
|
|
{
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: stop chip\n");
|
|
if (bdmStop () < 0)
|
|
m68k_bdm_report_error ();
|
|
}
|
|
|
|
/*
|
|
* Allow chip to resume execution
|
|
*/
|
|
static void
|
|
m68k_bdm_go (void)
|
|
{
|
|
m68k_bdm_have_atemp = 0;
|
|
if (bdmGo () < 0)
|
|
m68k_bdm_report_error ();
|
|
}
|
|
|
|
/*
|
|
* Reset chip, enter BDM mode
|
|
*/
|
|
static void
|
|
m68k_bdm_reset (void)
|
|
{
|
|
m68k_bdm_have_atemp = 0;
|
|
m68k_bdm_ptid = null_ptid;
|
|
if (bdmReset () < 0)
|
|
m68k_bdm_report_error ();
|
|
m68k_bdm_nap (M68K_BDM_TIME_TO_COME_UP);
|
|
}
|
|
|
|
/*
|
|
* step cpu32 chip: execute a single instruction
|
|
* This is complicated by the presence of interrupts.
|
|
* Consider the following sequence of events:
|
|
* - User attempts to `continue' from a breakpoint.
|
|
* - Gdb calls bdm_step_chip to single-step the instruction that
|
|
* had been replaced by the BGND instruction.
|
|
* - The target processor executes the instruction and stops.
|
|
* - GDB replaces the instruction with a BGND instruction to
|
|
* force a breakpoint the next time the instruction is hit.
|
|
* - GDB calls bdm_go and the target resumes execution.
|
|
* This all seems fine, but now consider what happens when a interrupt
|
|
* is pending:
|
|
* - User attempts to `continue' from a breakpoint.
|
|
* - Gdb calls bdm_step_chip to single-step the instruction that
|
|
* had been replaced by the BGND instruction.
|
|
* - The target processor does not execute the replaced instruction,
|
|
* but rather executes the first instruction of the interrupt
|
|
* service routine, then stops.
|
|
* - GDB replaces the instruction with a BGND instruction to
|
|
* force a breakpoint the next time the instruction is hit.
|
|
* - GDB calls bdm_go and the target resumes execution.
|
|
* - The target finishes off the interrupt, and upon returing from
|
|
* the interrupt generates another breakpoint!
|
|
* The solution is simple -- disable interrupts when single stepping.
|
|
* The problem then becomes the handling of instructions which involve
|
|
* the program status word!
|
|
*/
|
|
static void
|
|
m68k_bdm_step_cpu32_chip (void)
|
|
{
|
|
unsigned long pc;
|
|
unsigned short instruction;
|
|
unsigned short immediate;
|
|
unsigned long d7;
|
|
unsigned long sr;
|
|
unsigned long nsr;
|
|
enum {
|
|
op_other,
|
|
op_ANDIsr,
|
|
op_EORIsr,
|
|
op_ORIsr,
|
|
op_TOsr,
|
|
op_FROMsr,
|
|
op_FROMsrTOd7
|
|
} op;
|
|
|
|
/*
|
|
* Get the existing status register
|
|
*/
|
|
if (bdmReadSystemRegister (BDM_REG_SR, &sr) < 0)
|
|
m68k_bdm_report_error ();
|
|
|
|
/*
|
|
* Read the instuction about to be executed
|
|
*/
|
|
if ((bdmReadSystemRegister (BDM_REG_RPC, &pc) < 0)
|
|
|| (bdmReadWord (pc, &instruction) < 0))
|
|
m68k_bdm_report_error ();
|
|
|
|
/*
|
|
* See what operation is to be performed
|
|
*/
|
|
if (instruction == 0x027C)
|
|
op = op_ANDIsr;
|
|
else if (instruction == 0x0A7C)
|
|
op = op_EORIsr;
|
|
else if (instruction == 0x007C)
|
|
op = op_ORIsr;
|
|
else if (instruction == 0x40C7)
|
|
op = op_FROMsrTOd7;
|
|
else if ((instruction & 0xFFC0) == 0x40C0)
|
|
op = op_FROMsr;
|
|
else if ((instruction & 0xFFC0) == 0x46C0)
|
|
op = op_TOsr;
|
|
else
|
|
op = op_other;
|
|
|
|
/*
|
|
* Set things up for the single-step operation
|
|
*/
|
|
switch (op) {
|
|
case op_FROMsr:
|
|
case op_FROMsrTOd7:
|
|
/*
|
|
* It's storing the SR somewhere.
|
|
* Store the SR in D7 and change the instruction
|
|
* to save D7. This fails if the addressing mode
|
|
* is one of the esoteric modes that uses D7 as
|
|
* and index register, but we'll just have to hope
|
|
* that doesn't happen too often.
|
|
*/
|
|
if ((bdmReadRegister (7, &d7) < 0)
|
|
|| (bdmWriteRegister (7, sr) < 0)
|
|
|| (bdmWriteWord (pc, 0x3007 |
|
|
((instruction & 0x38) << 3) |
|
|
((instruction & 0x07) << 9)) < 0))
|
|
m68k_bdm_report_error ();
|
|
break;
|
|
|
|
case op_ANDIsr:
|
|
case op_EORIsr:
|
|
case op_ORIsr:
|
|
/*
|
|
* It's an immediate operation to the SR -- pick up the value
|
|
*/
|
|
if (bdmReadWord (pc+2, &immediate) < 0)
|
|
m68k_bdm_report_error ();
|
|
break;
|
|
|
|
case op_TOsr:
|
|
case op_other:
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Ensure the step is done with interrupts disabled
|
|
*/
|
|
if (bdmWriteSystemRegister (BDM_REG_SR, sr | 0x0700) < 0)
|
|
m68k_bdm_report_error ();
|
|
|
|
/*
|
|
* Do the single-step
|
|
*/
|
|
if (bdmStep () < 0)
|
|
m68k_bdm_report_error ();
|
|
|
|
/*
|
|
* Get the ATEMP register since the following operations may
|
|
* modify it.
|
|
*/
|
|
if (bdmReadSystemRegister (BDM_REG_ATEMP, &m68k_bdm_atemp) < 0)
|
|
m68k_bdm_report_error ();
|
|
m68k_bdm_have_atemp = 1;
|
|
|
|
/*
|
|
* Clean things up
|
|
*/
|
|
switch (op) {
|
|
case op_FROMsr:
|
|
if ((bdmWriteRegister (7, d7) < 0)
|
|
|| (bdmWriteWord (pc, instruction) < 0)
|
|
|| (bdmWriteSystemRegister (BDM_REG_SR, sr) < 0))
|
|
m68k_bdm_report_error ();
|
|
break;
|
|
|
|
case op_FROMsrTOd7:
|
|
if ((bdmReadRegister (7, &d7) < 0)
|
|
|| (bdmWriteRegister (7, (d7 & ~0xFFFF) | (sr & 0xFFFF)) < 0)
|
|
|| (bdmWriteSystemRegister (BDM_REG_SR, sr) < 0))
|
|
m68k_bdm_report_error ();
|
|
break;
|
|
|
|
case op_ANDIsr:
|
|
if (bdmWriteSystemRegister (BDM_REG_SR, sr & immediate) < 0)
|
|
m68k_bdm_report_error ();
|
|
break;
|
|
|
|
case op_EORIsr:
|
|
if (bdmWriteSystemRegister (BDM_REG_SR, sr ^ immediate) < 0)
|
|
m68k_bdm_report_error ();
|
|
break;
|
|
|
|
case op_ORIsr:
|
|
if (bdmWriteSystemRegister (BDM_REG_SR, sr | immediate) < 0)
|
|
m68k_bdm_report_error ();
|
|
break;
|
|
|
|
case op_TOsr:
|
|
break;
|
|
|
|
case op_other:
|
|
if ((bdmReadSystemRegister (BDM_REG_SR, &nsr) < 0) ||
|
|
(bdmWriteSystemRegister (BDM_REG_SR,
|
|
(nsr & ~0x0700) | (sr & 0x0700)) < 0))
|
|
m68k_bdm_report_error ();
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
m68k_bdm_step_chip (void)
|
|
{
|
|
/*
|
|
* The cpu32 is harder to step than the Coldfire.
|
|
*/
|
|
if (m68k_bdm_cpu_family == BDM_CPU32) {
|
|
m68k_bdm_step_cpu32_chip();
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Do the single-step
|
|
*/
|
|
if (bdmStep () < 0)
|
|
m68k_bdm_report_error ();
|
|
}
|
|
|
|
/* Make a copy of the string at PTR with SIZE characters
|
|
(and add a null character at the end in the copy).
|
|
Uses malloc to get the space. Returns the address of the copy. */
|
|
|
|
static char *
|
|
savestring (const char *ptr, size_t size)
|
|
{
|
|
char *p = (char *) malloc (size + 1);
|
|
if (!p)
|
|
error ("m68k-bdm: no memory for string");
|
|
memcpy (p, ptr, size);
|
|
p[size] = 0;
|
|
return p;
|
|
}
|
|
static void m68k_bdm_close (void);
|
|
|
|
/* Start an inferior process and returns its pid.
|
|
ALLARGS is a vector of program-name and args. */
|
|
static int
|
|
m68k_bdm_create_inferior (char *program, char *argv[])
|
|
{
|
|
char* device = NULL;
|
|
char* p;
|
|
int arg = 0;
|
|
unsigned int version = 0;
|
|
unsigned long csr = 0;
|
|
int delay = -1;
|
|
int driver_debug_level = 0;
|
|
int debug_level = 0;
|
|
|
|
warning_prefix = "m68k-bdm-gdbserver";
|
|
|
|
while (argv[arg]) {
|
|
if (argv[arg][0] == '-') {
|
|
switch (argv[arg][1])
|
|
{
|
|
case 'B':
|
|
m68k_bdm_breakpoints_hard = 1;
|
|
break;
|
|
case 'D':
|
|
driver_debug_level++;
|
|
break;
|
|
case 'd':
|
|
debug_level++;
|
|
break;
|
|
case 't':
|
|
arg++;
|
|
if (!argv[arg])
|
|
fatal ("m68k-bdm: no delay timeout argument found");
|
|
delay = strtoul (argv[arg], 0, 0);
|
|
break;
|
|
case 'v':
|
|
m68k_bdm_debug_level++;
|
|
break;
|
|
case 'V':
|
|
m68k_bdm_version ();
|
|
break;
|
|
case 'h':
|
|
m68k_bdm_help ();
|
|
break;
|
|
default:
|
|
fatal ("m68k-bdm: invalid option: %s, try -h", argv[arg]);
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
if (device)
|
|
warning ("m68k-bdm: device alread set to %s, ignoring %s\n",
|
|
device, argv[arg]);
|
|
else
|
|
device = argv[arg];
|
|
}
|
|
arg++;
|
|
}
|
|
|
|
if (!device)
|
|
error ("no device path found");
|
|
|
|
/*
|
|
* Open a connection the target via bdm
|
|
* name is the devicename of bdm and the filename to be used
|
|
* used for communication.
|
|
*/
|
|
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: create inferior called\n");
|
|
|
|
if (bdmIsOpen ()) {
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: bdm driver is already open; closing.\n");
|
|
bdmClose ();
|
|
}
|
|
|
|
m68k_bdm_ptid = null_ptid;
|
|
|
|
/*
|
|
* Find the first whitespace character after device and chop it off
|
|
*/
|
|
for (p = device; (*p != '\0') && (!isspace (*p)); p++);
|
|
if ((*p == '\0') && (p == device))
|
|
error ("m68k-bdm: the name of the bdm port device is missing.");
|
|
m68k_bdm_dev_name = savestring (device, p - device);
|
|
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: opening: %s\n", m68k_bdm_dev_name);
|
|
|
|
if (bdmOpen (m68k_bdm_dev_name) < 0)
|
|
m68k_bdm_report_error ();
|
|
|
|
if (debug_level > 0) {
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: set BDM lib debug level: %d\n",
|
|
debug_level);
|
|
bdmSetDebugFlag (debug_level);
|
|
}
|
|
|
|
if (driver_debug_level > 0) {
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: set driver debug level: %d\n",
|
|
driver_debug_level);
|
|
bdmSetDriverDebugFlag (driver_debug_level);
|
|
}
|
|
|
|
if (delay > 0) {
|
|
if (bdmSetDelay (delay) < 0)
|
|
m68k_bdm_report_error ();
|
|
}
|
|
|
|
if (bdmStatus () & (BDM_TARGETPOWER | BDM_TARGETNC)) {
|
|
bdmClose ();
|
|
error ("m68k-bdm: target or cable problem");
|
|
}
|
|
|
|
/*
|
|
* Ask the driver for it's version.
|
|
* We are only interested in the major number when checking the
|
|
* driver version number.
|
|
*/
|
|
if (bdmGetDrvVersion (&version) < 0)
|
|
m68k_bdm_report_error ();
|
|
if ((version & 0xff00) != (BDM_DRV_VERSION & 0xff00)) {
|
|
printf_filtered ("m68k-bdm: incorrect driver version, looking for %i.%i"\
|
|
" and found %i.%i\n",
|
|
BDM_DRV_VERSION >> 8, BDM_DRV_VERSION & 0xff,
|
|
version >> 8, version & 0xff);
|
|
bdmClose ();
|
|
error ("m68k-bdm: can't run with incorrect BDM driver version");
|
|
}
|
|
|
|
/*
|
|
* Get the processor type.
|
|
*/
|
|
if (bdmGetProcessor (&m68k_bdm_cpu_family) < 0)
|
|
m68k_bdm_report_error ();
|
|
|
|
switch (m68k_bdm_cpu_family) {
|
|
case BDM_CPU32:
|
|
m68k_bdm_breakpoint_code = m68k_bdm_cpu32_breakpoint;
|
|
m68k_bdm_breakpoint_size = sizeof m68k_bdm_cpu32_breakpoint;
|
|
m68k_bdm_cpu_type = M68K_BDM_MARCH_CPU32;
|
|
m68k_bdm_cpu_label = M68K_BDM_MARCH_CPU32_LABEL;
|
|
break;
|
|
|
|
case BDM_COLDFIRE:
|
|
m68k_bdm_breakpoint_code = m68k_bdm_cf_breakpoint;
|
|
m68k_bdm_breakpoint_size = sizeof m68k_bdm_cf_breakpoint;
|
|
|
|
/*
|
|
* Read the CSR register to determine the debug module
|
|
* version.
|
|
*/
|
|
if (bdmReadSystemRegister (BDM_REG_CSR, &csr) < 0)
|
|
m68k_bdm_report_error ();
|
|
m68k_bdm_cf_debug_ver = (csr >> 20) & 0x0f;
|
|
|
|
/*
|
|
* If the processor is a version 0 read the PC and VBR
|
|
* an if they can be read read the mbar. If that fails
|
|
* we have a 5282.
|
|
*/
|
|
if (m68k_bdm_cf_debug_ver == M68K_BDM_VER_A) {
|
|
unsigned long junk;
|
|
m68k_bdm_cpu_type = M68K_BDM_MARCH_CF5200;
|
|
m68k_bdm_cpu_label = M68K_BDM_MARCH_CF5200_LABEL;
|
|
if ((bdmReadSystemRegister (BDM_REG_RPC, &junk) == 0) &&
|
|
(bdmReadSystemRegister (BDM_REG_VBR, &junk) == 0)) {
|
|
if (bdmReadControlRegister (0xc0f, &junk) < 0) {
|
|
/* XCSR on the 5235 */
|
|
if (bdmReadDebugRegister (0x1, &junk) < 0) {
|
|
m68k_bdm_cpu_type = M68K_BDM_MARCH_CF5282;
|
|
m68k_bdm_cpu_label = M68K_BDM_MARCH_CF5282_LABEL;
|
|
printf_filtered ("m68k-bdm: detected MCF5282\n");
|
|
}
|
|
else {
|
|
m68k_bdm_cpu_type = M68K_BDM_MARCH_CF5235;
|
|
m68k_bdm_cpu_label = M68K_BDM_MARCH_CF5235_LABEL;
|
|
printf_filtered ("m68k-bdm: detected MCF5235\n");
|
|
}
|
|
}
|
|
else {
|
|
m68k_bdm_cpu_type = M68K_BDM_MARCH_CF5272;
|
|
m68k_bdm_cpu_label = M68K_BDM_MARCH_CF5272_LABEL;
|
|
printf_filtered ("m68k-bdm: detected V2 core\n");
|
|
}
|
|
}
|
|
} else if (m68k_bdm_cf_debug_ver == M68K_BDM_VER_B_PLUS) {
|
|
m68k_bdm_cpu_type = M68K_BDM_MARCH_CF52223;
|
|
m68k_bdm_cpu_label = M68K_BDM_MARCH_CF52223_LABEL;
|
|
printf_filtered ("m68k-bdm: detected MCF52223 (MCF52235)\n");
|
|
} else if (m68k_bdm_cf_debug_ver == M68K_BDM_VER_B) {
|
|
m68k_bdm_cpu_type = M68K_BDM_MARCH_CF5307;
|
|
m68k_bdm_cpu_label = M68K_BDM_MARCH_CF5307_LABEL;
|
|
printf_filtered ("m68k-bdm: detected MCF5307\n");
|
|
} else if (m68k_bdm_cf_debug_ver == M68K_BDM_VER_C) {
|
|
m68k_bdm_cpu_type = M68K_BDM_MARCH_CFV4E;
|
|
m68k_bdm_cpu_label = M68K_BDM_MARCH_CFV4E_LABEL;
|
|
printf_filtered ("m68k-bdm: detected V4e core\n");
|
|
} else {
|
|
bdmClose ();
|
|
error ("m68k-bdm: unknown processor debug version.");
|
|
}
|
|
break;
|
|
|
|
default:
|
|
bdmClose ();
|
|
error ("m68k-bdm: unknown processor type returned from the driver.");
|
|
}
|
|
|
|
printf_filtered ("m68k-bdm: architecture %s connected to %s\n",
|
|
m68k_bdm_cpu_label, m68k_bdm_dev_name);
|
|
if (m68k_bdm_cpu_family == BDM_COLDFIRE)
|
|
{
|
|
char* cf_type = "5206(e)/5235/5272/5282";
|
|
m68k_bdm_ptid = 0x5200;
|
|
if (m68k_bdm_cf_debug_ver == M68K_BDM_VER_B) {
|
|
cf_type = "5307/5407";
|
|
m68k_bdm_ptid = 0x5300;
|
|
}
|
|
else if (m68k_bdm_cf_debug_ver == M68K_BDM_VER_B_PLUS) {
|
|
cf_type = "52223/52235";
|
|
m68k_bdm_ptid = 0x52223;
|
|
}
|
|
else if (m68k_bdm_cf_debug_ver == M68K_BDM_VER_C) {
|
|
cf_type = "V4e (547x/548x)";
|
|
m68k_bdm_ptid = 0x5400;
|
|
}
|
|
printf_filtered ("m68k-bdm: Coldfire debug module version is %ld (%s)\n",
|
|
m68k_bdm_cf_debug_ver, cf_type);
|
|
}
|
|
else {
|
|
m68k_bdm_ptid = 0x68300;
|
|
}
|
|
|
|
m68k_bdm_init_registers ();
|
|
|
|
m68k_bdm_init_watchpoints ();
|
|
|
|
set_breakpoint_data (m68k_bdm_breakpoint_code, m68k_bdm_breakpoint_size);
|
|
|
|
add_thread (m68k_bdm_ptid, NULL, m68k_bdm_ptid);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
m68k_bdm_attach (unsigned long pid)
|
|
{
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: attach\n");
|
|
m68k_bdm_ptid = pid;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Terminate current application and return to system prompt.
|
|
* On a target, just let the program keep on running
|
|
*/
|
|
static void
|
|
m68k_bdm_kill (void)
|
|
{
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: kill: release on exit: %d\n",
|
|
m68k_bdm_release_on_exit);
|
|
if (m68k_bdm_release_on_exit) {
|
|
if (m68k_bdm_get_status () & BDM_TARGETSTOPPED)
|
|
m68k_bdm_go ();
|
|
} else {
|
|
m68k_bdm_stop_chip ();
|
|
m68k_bdm_reset ();
|
|
}
|
|
}
|
|
|
|
static void
|
|
m68k_bdm_close (void)
|
|
{
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: close\n");
|
|
m68k_bdm_gdb_is_quitting = 1;
|
|
m68k_bdm_have_atemp = 0;
|
|
if (m68k_bdm_kill_on_exit)
|
|
m68k_bdm_kill ();
|
|
bdmClose ();
|
|
m68k_bdm_ptid = null_ptid;
|
|
}
|
|
|
|
/*
|
|
* m68k_bdm_detach -- Terminate the open connection to the remote debugger.
|
|
* takes a program previously attached to and detaches it.
|
|
* We better not have left any breakpoints
|
|
* in the program or it'll die when it hits one.
|
|
* Close the open connection to the remote debugger.
|
|
* Use this when you want to detach and do something else
|
|
* with your gdb.
|
|
*/
|
|
static int
|
|
m68k_bdm_detach (void)
|
|
{
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: detach\n");
|
|
m68k_bdm_ptid = null_ptid;
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
m68k_bdm_join (void)
|
|
{
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: join\n");
|
|
}
|
|
|
|
static int
|
|
m68k_bdm_thread_alive (unsigned long tid)
|
|
{
|
|
return tid == m68k_bdm_ptid;
|
|
}
|
|
|
|
/*
|
|
* m68k_bdm_resume -- Tell the remote machine to resume.
|
|
*/
|
|
static void
|
|
m68k_bdm_resume (struct thread_resume *resume_info)
|
|
{
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: resume: thread:%ld leave stopped:%d step:%d\n",
|
|
resume_info->thread, resume_info->leave_stopped,
|
|
resume_info->step);
|
|
|
|
/*
|
|
* Invalidate the reigsters in the register cache.
|
|
*/
|
|
regcache_invalidate ();
|
|
|
|
if (resume_info->step)
|
|
m68k_bdm_step_chip ();
|
|
else
|
|
m68k_bdm_go ();
|
|
}
|
|
|
|
/*
|
|
* We have fallen into an exception supported by the runtime system.
|
|
* by executing a `breakpoint' instruction.
|
|
*/
|
|
static unsigned char
|
|
m68k_bdm_analyze_exception (char* status)
|
|
{
|
|
unsigned long pc;
|
|
unsigned char opcode[20]; /* `big enough' */
|
|
|
|
if (m68k_bdm_cpu_family == BDM_CPU32) {
|
|
if (bdmReadSystemRegister (BDM_REG_PCC, &pc) < 0)
|
|
m68k_bdm_report_error ();
|
|
}
|
|
else {
|
|
if (bdmReadSystemRegister (BDM_REG_RPC, &pc) < 0)
|
|
m68k_bdm_report_error ();
|
|
if (pc)
|
|
pc -= 2;
|
|
}
|
|
|
|
*status = TARGET_WAITKIND_STOPPED;
|
|
|
|
/*
|
|
* See if it was a `breakpoint' instruction
|
|
*/
|
|
if (bdmReadMemory (pc, opcode, m68k_bdm_breakpoint_size) < 0)
|
|
m68k_bdm_report_error ();
|
|
if (memcmp (m68k_bdm_breakpoint_code, opcode, m68k_bdm_breakpoint_size) == 0) {
|
|
if (bdmWriteSystemRegister (BDM_REG_RPC, pc) < 0)
|
|
m68k_bdm_report_error ();
|
|
return TARGET_SIGNAL_TRAP;
|
|
}
|
|
|
|
/*
|
|
* FIXME: Why an illegal instruction signal ?
|
|
*/
|
|
return TARGET_SIGNAL_ILL;
|
|
}
|
|
|
|
/*
|
|
* Wait until the remote machine stops, then return the
|
|
* signals that stopped us and the status flag. The flags
|
|
* are documented on the GDB manual for the remote protocol.
|
|
*
|
|
* 'S' : AA is the returned signal number.
|
|
*
|
|
* 'T' : AA is the returned signal number. The server
|
|
* will attempt to see if the stop was due to a
|
|
* watch point.
|
|
*
|
|
* 'W' : AA is the returned exit code for the process that has
|
|
* exitted.
|
|
*
|
|
* 'X' : AA is the returned signal number for the terminated
|
|
* process.
|
|
*/
|
|
|
|
static unsigned char
|
|
m68k_bdm_wait (char* status)
|
|
{
|
|
unsigned char signal;
|
|
int bdm_stat;
|
|
|
|
m68k_bdm_hit_watchpoint = 0;
|
|
*status = TARGET_WAITKIND_EXITED;
|
|
signal = TARGET_SIGNAL_0;
|
|
|
|
/*
|
|
* A work around a problem with the 5206e processor. Not sure
|
|
* what the issue is. It could be the processor.
|
|
*/
|
|
if (m68k_bdm_cpu_family == BDM_COLDFIRE && m68k_bdm_cf_debug_ver == 0)
|
|
m68k_bdm_nap (10000);
|
|
|
|
/*
|
|
* Wait here till the target requires service
|
|
*/
|
|
while ((bdm_stat = m68k_bdm_get_status ()) == 0) {
|
|
check_remote_input_interrupt_request ();
|
|
m68k_bdm_nap (20000);
|
|
}
|
|
|
|
/*
|
|
* Determine why the target stopped
|
|
*/
|
|
switch (bdm_stat) {
|
|
case BDM_TARGETNC:
|
|
*status = TARGET_WAITKIND_EXITED;
|
|
signal = TARGET_SIGNAL_LOST;
|
|
break;
|
|
case BDM_TARGETPOWER:
|
|
*status = TARGET_WAITKIND_EXITED;
|
|
signal = TARGET_SIGNAL_PWR;
|
|
break;
|
|
case BDM_TARGETRESET:
|
|
*status = TARGET_WAITKIND_STOPPED;
|
|
signal = TARGET_SIGNAL_KILL;
|
|
break;
|
|
case BDM_TARGETSTOPPED:
|
|
case BDM_TARGETHALT:
|
|
case BDM_TARGETSTOPPED | BDM_TARGETHALT:
|
|
if (m68k_bdm_cpu_family == BDM_CPU32) {
|
|
if (!m68k_bdm_have_atemp
|
|
&& (bdmReadSystemRegister (BDM_REG_ATEMP, &m68k_bdm_atemp) < 0))
|
|
m68k_bdm_report_error ();
|
|
switch (m68k_bdm_atemp & 0xffff) {
|
|
case 0xffff: /* double bus fault */
|
|
*status = TARGET_WAITKIND_STOPPED;
|
|
signal = TARGET_SIGNAL_BUS;
|
|
break;
|
|
case 0x0: /* HW bkpt */
|
|
*status = TARGET_WAITKIND_TRAP;
|
|
signal = TARGET_SIGNAL_TRAP;
|
|
break;
|
|
case 0x1: /* background mode */
|
|
signal = m68k_bdm_analyze_exception (status);
|
|
break;
|
|
default:
|
|
printf_filtered ("m68 bdm: wait: unknown atemp: %#lx\n", m68k_bdm_atemp);
|
|
*status = TARGET_WAITKIND_STOPPED;
|
|
signal = TARGET_SIGNAL_GRANT;
|
|
}
|
|
}
|
|
else {
|
|
unsigned long csr;
|
|
if (bdmReadSystemRegister (BDM_REG_CSR, &csr) < 0)
|
|
m68k_bdm_report_error ();
|
|
if (csr & 0x08000000) { /* double bus fault */
|
|
*status = TARGET_WAITKIND_STOPPED;
|
|
signal = TARGET_SIGNAL_BUS;
|
|
}
|
|
else {
|
|
if (csr & 0x04000000) { /* hardware trigger */
|
|
m68k_bdm_hit_watchpoint = 1;
|
|
*status = TARGET_WAITKIND_STOPPED;
|
|
signal = TARGET_SIGNAL_TRAP;
|
|
}
|
|
else {
|
|
if (csr & 0x01000000) { /* -BKPT signal */
|
|
*status = TARGET_WAITKIND_STOPPED;
|
|
signal = TARGET_SIGNAL_TRAP;
|
|
}
|
|
else {
|
|
if (csr & 0x02000000) { /* HALT/software bkpt */
|
|
signal = m68k_bdm_analyze_exception (status);
|
|
}
|
|
else {
|
|
printf_filtered ("m68k-bdm: wait: unknown csr: %#lx", csr);
|
|
*status = TARGET_WAITKIND_STOPPED;
|
|
signal = TARGET_SIGNAL_GRANT;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
printf_filtered ("m68k-bdm: wait: unknown bdm status: %#x", bdm_stat);
|
|
break;
|
|
}
|
|
m68k_bdm_have_atemp = 0;
|
|
return signal;
|
|
}
|
|
|
|
/*
|
|
* Fetch register REGNO, or all user registers if REGNO is -1.
|
|
*/
|
|
static void
|
|
m68k_bdm_fetch_registers (int regno)
|
|
{
|
|
unsigned long lu = 0;
|
|
unsigned long ll = 0;
|
|
unsigned char cbuf[8];
|
|
int ret;
|
|
|
|
/* ??? Some callers use 0 to mean all registers. */
|
|
if (regno == 0)
|
|
regno = -1;
|
|
|
|
if (regno < 0) {
|
|
for (regno = 1; regno <= M68K_BDM_NUM_REGS_BDM; regno++)
|
|
m68k_bdm_fetch_registers (regno);
|
|
}
|
|
else {
|
|
/*
|
|
* Drop down to be from 0..M68K_BDM_NUM_REGS_BDM.
|
|
*/
|
|
regno--;
|
|
|
|
if (M68K_BDM_REG_FLAGS (regno) & REG_NOT_ACCESSABLE) {
|
|
if (m68k_bdm_debug_level) {
|
|
printf_filtered ("m68k-bdm: fetch reg:%s(%i) is not accessable\n",
|
|
M68K_BDM_REG_NAME (regno), regno);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (M68K_BDM_REG_FLAGS (regno) & REG_WRITE_ONLY) {
|
|
if (m68k_bdm_debug_level) {
|
|
printf_filtered ("m68k-bdm: fetch reg:%s(%i) is write only\n",
|
|
M68K_BDM_REG_NAME (regno), regno);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (regno < 16) {
|
|
ret = bdmReadRegister (regno, &lu);
|
|
}
|
|
else {
|
|
if (regno < M68K_BDM_NUM_REGS_BDM) {
|
|
ret = m68k_bdm_read_sys_ctl_reg (M68K_BDM_REG_NAME (regno),
|
|
M68K_BDM_REG_CODE (regno),
|
|
&lu);
|
|
if ((ret == 0) &&
|
|
(M68K_BDM_REG_TYPE (regno) == M68K_BDM_REG_TYPE_M68881_EXT))
|
|
ret = m68k_bdm_read_sys_ctl_reg (M68K_BDM_REG_NAME (regno),
|
|
M68K_BDM_REG_CODE (regno) + 1,
|
|
&ll);
|
|
}
|
|
else {
|
|
error ("Bad register number (%d)", regno);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (ret < 0)
|
|
m68k_bdm_report_error ();
|
|
|
|
cbuf[0] = lu >> 24;
|
|
cbuf[1] = lu >> 16;
|
|
cbuf[2] = lu >> 8;
|
|
cbuf[3] = lu;
|
|
cbuf[4] = ll >> 24;
|
|
cbuf[5] = ll >> 16;
|
|
cbuf[6] = ll >> 8;
|
|
cbuf[7] = ll;
|
|
|
|
if (m68k_bdm_debug_level) {
|
|
if (M68K_BDM_REG_TYPE (regno) == M68K_BDM_REG_TYPE_M68881_EXT)
|
|
printf_filtered ("m68k-bdm: fetch reg:%s(%i) = 0x%08lx%08lx\n",
|
|
M68K_BDM_REG_NAME (regno), regno, lu, ll);
|
|
else
|
|
printf_filtered ("m68k-bdm: fetch reg:%s(%i) = 0x%08lx\n",
|
|
M68K_BDM_REG_NAME (regno), regno, lu);
|
|
}
|
|
supply_register (regno, (char*) cbuf);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Store register REGNO, or all user registers if REGNO == -1.
|
|
*/
|
|
void
|
|
m68k_bdm_store_registers (int regno)
|
|
{
|
|
/* ??? Some callers use 0 to mean all registers. */
|
|
if (regno == 0)
|
|
regno = -1;
|
|
|
|
if (regno == -1) {
|
|
for (regno = 1; regno <= M68K_BDM_NUM_REGS_BDM; regno++)
|
|
m68k_bdm_store_registers (regno);
|
|
}
|
|
else {
|
|
unsigned char cbuf[8];
|
|
|
|
/*
|
|
* Drop down to be from 0..M68K_BDM_NUM_REGS_BDM.
|
|
*/
|
|
regno--;
|
|
|
|
if (M68K_BDM_REG_FLAGS (regno) & REG_NOT_ACCESSABLE) {
|
|
if (m68k_bdm_debug_level) {
|
|
printf_filtered ("m68k-bdm: store reg:%s(%i) is not accessable\n",
|
|
M68K_BDM_REG_NAME (regno), regno);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (M68K_BDM_REG_FLAGS (regno) & REG_READ_ONLY) {
|
|
if (m68k_bdm_debug_level) {
|
|
printf_filtered ("m68k-bdm: store reg:%s(%i) is read only\n",
|
|
M68K_BDM_REG_NAME (regno), regno);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (collect_register (regno, (char*) cbuf)) {
|
|
int ret;
|
|
|
|
unsigned long lu = 0;
|
|
unsigned long ll = 0;
|
|
|
|
lu = (cbuf[0] << 24) | (cbuf[1] << 16) | (cbuf[2] << 8) | cbuf[3];
|
|
ll = (cbuf[4] << 24) | (cbuf[5] << 16) | (cbuf[6] << 8) | cbuf[7];
|
|
|
|
if (m68k_bdm_debug_level) {
|
|
if (M68K_BDM_REG_TYPE (regno) == M68K_BDM_REG_TYPE_M68881_EXT)
|
|
printf_filtered ("m68k-bdm: store reg:%s(%i) = 0x%08lx%08lx\n",
|
|
M68K_BDM_REG_NAME (regno), regno, lu, ll);
|
|
else
|
|
printf_filtered ("m68k-bdm: store reg:%s(%i) = 0x%08lx\n",
|
|
M68K_BDM_REG_NAME (regno), regno, lu);
|
|
}
|
|
|
|
if (regno < 16) {
|
|
ret = bdmWriteRegister (regno, lu);
|
|
}
|
|
else {
|
|
if (regno < M68K_BDM_NUM_REGS_BDM) {
|
|
ret = m68k_bdm_write_sys_ctl_reg (M68K_BDM_REG_NAME (regno),
|
|
M68K_BDM_REG_CODE (regno),
|
|
lu);
|
|
if ((ret == 0) ||
|
|
(M68K_BDM_REG_TYPE (regno) == M68K_BDM_REG_TYPE_M68881_EXT))
|
|
ret = m68k_bdm_write_sys_ctl_reg (M68K_BDM_REG_NAME (regno),
|
|
M68K_BDM_REG_CODE (regno) + 1,
|
|
ll);
|
|
}
|
|
else {
|
|
error ("m68k-bdm: bad register number (%d)", regno);
|
|
return;
|
|
}
|
|
}
|
|
if (ret < 0)
|
|
m68k_bdm_report_error ();
|
|
}
|
|
else {
|
|
if (m68k_bdm_debug_level) {
|
|
printf_filtered ("m68k-bdm: store reg:%s(%i) is clean\n",
|
|
M68K_BDM_REG_NAME (regno), regno);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static int
|
|
m68k_bdm_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
|
|
{
|
|
int ret = 0;
|
|
if (bdmReadMemory (memaddr, myaddr, len) < 0) {
|
|
m68k_bdm_report_error ();
|
|
ret = EIO;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
m68k_bdm_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
|
|
{
|
|
int ret = 0;
|
|
if (bdmWriteMemory (memaddr, (unsigned char*) myaddr, len) < 0) {
|
|
m68k_bdm_report_error ();
|
|
ret = EIO;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static void
|
|
m68k_bdm_look_up_symbols (void)
|
|
{
|
|
}
|
|
|
|
static void
|
|
m68k_bdm_request_interrupt (void)
|
|
{
|
|
int save_m68k_bdm_use_error = m68k_bdm_use_error;
|
|
m68k_bdm_use_error = 0;
|
|
m68k_bdm_stop_chip ();
|
|
m68k_bdm_use_error = save_m68k_bdm_use_error;
|
|
}
|
|
|
|
static const char*
|
|
m68k_bdm_arch_string (void)
|
|
{
|
|
return m68k_bdm_cpu_label;
|
|
}
|
|
|
|
static const char *
|
|
m68k_bdm_xml (const char *annex)
|
|
{
|
|
extern const char *const xml_builtin[][2];
|
|
int xml = 0;
|
|
|
|
if (strcmp (annex, "target.xml") == 0) {
|
|
while (xml_builtin[xml][0]) {
|
|
if (strcmp (xml_builtin[xml][0], M68K_BDM_REG_XML ()) == 0)
|
|
return xml_builtin[xml][1];
|
|
xml++;
|
|
}
|
|
}
|
|
|
|
xml = 0;
|
|
|
|
while (xml_builtin[xml][0]) {
|
|
if (strcmp (annex, xml_builtin[xml][0]) == 0)
|
|
return xml_builtin[xml][1];
|
|
xml++;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static int
|
|
m68k_bdm_parse_reg_value (const char* command,
|
|
unsigned int* reg,
|
|
unsigned long* value)
|
|
{
|
|
char* s = strchr (command, ' ');
|
|
if (!s) {
|
|
monitor_output ("m68k-bdm: invalid command format: no reg found\n");
|
|
return 0;
|
|
}
|
|
*reg = strtoul (s, &s, 0);
|
|
if (value) {
|
|
if (!s) {
|
|
monitor_output ("m68k-bdm: invalid command format: no value found\n");
|
|
return 0;
|
|
}
|
|
*value = strtoul (s, 0, 0);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static void
|
|
m68k_bdm_cmd_help (void)
|
|
{
|
|
monitor_output ("m68k-bdm: monitor commands:\n");
|
|
monitor_output (" bdm-help\n");
|
|
monitor_output (" This help message.\n");
|
|
monitor_output (" bdm-debug <level>\n");
|
|
monitor_output (" Set the M68K BDM debug level.\n");
|
|
monitor_output (" bdm-lib-debug <level>\n");
|
|
monitor_output (" Set the BDM library debug level.\n");
|
|
monitor_output (" bdm-driver-debug <level>\n");
|
|
monitor_output (" Set the BDM driver debug level. This may result in a\n");
|
|
monitor_output (" remote BDm server logging to syslog if this is " \
|
|
"enabled.\n");
|
|
monitor_output (" bdm-ctl-get <reg>\n");
|
|
monitor_output (" Get the control register where <reg> is a register " \
|
|
"value\n");
|
|
monitor_output (" supported by the target. For example: bdm-ctl-get " \
|
|
"0x801\n");
|
|
monitor_output (" will return the VBR register for most Coldfire " \
|
|
"processors.\n");
|
|
monitor_output (" bdm-ctl-set <reg <value>>\n");
|
|
monitor_output (" Set the control reigster where <reg> is a register " \
|
|
"value\n");
|
|
monitor_output (" supported by the target. For example: bdm-ctl-set " \
|
|
"0x801 0\n");
|
|
monitor_output (" bdm-dbg-get <reg>\n");
|
|
monitor_output (" Get the debug register where <reg> is a register value\n");
|
|
monitor_output (" supported by the target. For example: bdm-dbg-get 0x1\n");
|
|
monitor_output (" will return the XCSR register on Coldfire with Debug B+.\n");
|
|
monitor_output (" bdm-dbg-set <reg> <value>\n");
|
|
monitor_output (" Set the debug reigster where <reg> is a register value\n");
|
|
monitor_output (" supported by the target. For example: bdm-dbg-set 0x1 0\n");
|
|
monitor_output (" bdm-reset\n");
|
|
monitor_output (" Reset the BDM pod\n");
|
|
monitor_output (" bdm-sleep\n");
|
|
monitor_output (" Sleep the require number of milliseconds.\n");
|
|
}
|
|
|
|
static int
|
|
m68k_bdm_commands (const char* command, int len)
|
|
{
|
|
if (M68K_BDM_STR_IS (command, "bdm-help"))
|
|
m68k_bdm_cmd_help ();
|
|
else if (M68K_BDM_STR_IS (command, "bdm-debug")) {
|
|
m68k_bdm_debug_level = strtoul (command + sizeof ("bdm-debug"), 0, 0);
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: set debug level: %d\n",
|
|
m68k_bdm_debug_level);
|
|
}
|
|
else if (M68K_BDM_STR_IS (command, "bdm-lib-debug")) {
|
|
int level = strtoul (command + sizeof ("bdm-lib-debug"), 0, 0);
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: set BDM lib debug level: %d\n",
|
|
level);
|
|
bdmSetDebugFlag (level);
|
|
}
|
|
else if (M68K_BDM_STR_IS (command, "bdm-driver-debug")) {
|
|
int level = strtoul (command + sizeof ("bdm-driver-debug"), 0, 0);
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: set driver debug level: %d\n",
|
|
level);
|
|
bdmSetDriverDebugFlag (level);
|
|
}
|
|
else if (M68K_BDM_STR_IS (command, "bdm-ctl-get")) {
|
|
unsigned int reg = 0;
|
|
unsigned long value = 0;
|
|
if (!m68k_bdm_parse_reg_value (command, ®, 0))
|
|
return 0;
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: get control reg: 0x%03x\n", reg);
|
|
if (bdmReadControlRegister (reg, &value) < 0)
|
|
monitor_output ("m68k-bdm: error: %s\n", bdmErrorString ());
|
|
else
|
|
monitor_output ("m68k-bdm: control reg: 0x%03x = %ld (0x%0lx)\n",
|
|
reg, value, value);
|
|
}
|
|
else if (M68K_BDM_STR_IS (command, "bdm-ctl-set")) {
|
|
unsigned int reg = 0;
|
|
unsigned long value = 0;
|
|
if (!m68k_bdm_parse_reg_value (command, ®, &value))
|
|
return 0;
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: set control reg: 0x%03x = %ld (0x%0lx)\n",
|
|
reg, value, value);
|
|
if (bdmWriteControlRegister (reg, value) < 0)
|
|
monitor_output ("m68k-bdm: error: %s\n", bdmErrorString ());
|
|
}
|
|
else if (M68K_BDM_STR_IS (command, "bdm-dbg-get")) {
|
|
unsigned int reg = 0;
|
|
unsigned long value = 0;
|
|
if (!m68k_bdm_parse_reg_value (command, ®, 0))
|
|
return 0;
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: get debug reg: 0x%03x\n", reg);
|
|
if (bdmReadDebugRegister (reg, &value) < 0)
|
|
monitor_output ("m68k-bdm: error: %s\n", bdmErrorString ());
|
|
else
|
|
monitor_output ("m68k-bdm: debug reg: 0x%03x = %ld (0x%0lx)\n",
|
|
reg, value, value);
|
|
}
|
|
else if (M68K_BDM_STR_IS (command, "bdm-dbg-set")) {
|
|
unsigned int reg = 0;
|
|
unsigned long value = 0;
|
|
if (!m68k_bdm_parse_reg_value (command, ®, &value))
|
|
return 0;
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: set debug reg: 0x%03x = %ld (0x%0lx)\n",
|
|
reg, value, value);
|
|
if (bdmWriteDebugRegister (reg, value) < 0)
|
|
monitor_output ("m68k-bdm: error: %s\n", bdmErrorString ());
|
|
}
|
|
else if (M68K_BDM_STR_IS (command, "bdm-reset")) {
|
|
if (m68k_bdm_debug_level)
|
|
printf_filtered ("m68k-bdm: reset the bdm\n");
|
|
m68k_bdm_reset();
|
|
}
|
|
else if (M68K_BDM_STR_IS (command, "bdm-sleep")) {
|
|
unsigned int msecs = 0;
|
|
msecs = strtoul (command + sizeof ("bdm-sleep"), 0, 0);
|
|
#if defined (__MINGW32__)
|
|
Sleep (msecs);
|
|
#else
|
|
{
|
|
struct timeval tv;
|
|
tv.tv_sec = msecs / 1000;
|
|
tv.tv_usec = (msecs % 1000) * 1000;
|
|
select (0, NULL, NULL, NULL, &tv);
|
|
}
|
|
#endif
|
|
} else {
|
|
monitor_output ("Unknown monitor command.\n\n");
|
|
m68k_bdm_cmd_help ();
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static struct target_ops m68k_bdm_target_ops = {
|
|
m68k_bdm_create_inferior,
|
|
m68k_bdm_attach,
|
|
m68k_bdm_close,
|
|
m68k_bdm_detach,
|
|
m68k_bdm_join,
|
|
m68k_bdm_thread_alive,
|
|
m68k_bdm_resume,
|
|
m68k_bdm_wait,
|
|
m68k_bdm_fetch_registers,
|
|
m68k_bdm_store_registers,
|
|
m68k_bdm_read_memory,
|
|
m68k_bdm_write_memory,
|
|
m68k_bdm_look_up_symbols,
|
|
m68k_bdm_request_interrupt,
|
|
NULL,
|
|
m68k_bdm_insert_point,
|
|
m68k_bdm_remove_point,
|
|
m68k_bdm_stopped_by_watchpoint,
|
|
m68k_bdm_stopped_data_address,
|
|
NULL,
|
|
NULL,
|
|
m68k_bdm_arch_string,
|
|
NULL,
|
|
m68k_bdm_xml,
|
|
m68k_bdm_commands
|
|
};
|
|
|
|
int using_threads;
|
|
|
|
void
|
|
initialize_low (void)
|
|
{
|
|
set_target_ops (&m68k_bdm_target_ops);
|
|
set_breakpoint_data (m68k_bdm_breakpoint_code, m68k_bdm_breakpoint_size);
|
|
m68k_bdm_use_error = 1;
|
|
}
|