blob: 02c8b6e7963ac1d03aecdca884569123951354c3 [file] [log] [blame]
/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
Copyright 2005, 2008, 2009 Free Software Foundation, Inc.
Contributed by Codito Technologies Pvt. Ltd. (www.codito.com)
Authors:
Sameer Dhavale <sameer.dhavale@codito.com>
Ramana Radhakrishnan <ramana.radhakrishnan@codito.com>
Richard Stuckey <richard.stuckey@arc.com>
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/>. */
/******************************************************************************/
/* */
/* Outline: */
/* This module creates an instance of a gdb 'target_ops' structure which */
/* contains information and operations for debugging a remote ARC target */
/* with JTAG. */
/* */
/* It also registers a number of ARC-specific commands with gdb. */
/* */
/* Usage: */
/* The module exports a function _initialize_arc_jtag: the call to this */
/* function is generated by the gdb build mechanism, so this function */
/* should not be explicitly called. */
/* */
/******************************************************************************/
/* system header files */
/* gdb header files */
#include "defs.h"
#include "inferior.h"
#include "gdbcmd.h"
#include "objfiles.h"
#include "libiberty.h"
#include "gdb_assert.h"
/* ARC header files */
#include "config/arc/tm-embed.h"
#include "arc-jtag.h"
#include "arc-gpio.h"
#include "arc-tdep.h"
#include "arc-board.h"
#include "arc-jtag-ops.h"
#include "arc-elf32-tdep.h"
#include "arc-architecture.h"
#include "arc-registers.h"
#include "arc-jtag-actionpoints.h"
/* -------------------------------------------------------------------------- */
/* local types */
/* -------------------------------------------------------------------------- */
typedef enum
{
CLEAR_USER_BIT,
RESTORE_USER_BIT
} Status32Action;
/* -------------------------------------------------------------------------- */
/* local data */
/* -------------------------------------------------------------------------- */
#define ARC_CONFIGURATION_COMMAND "arc-configuration"
#define ARC_RESET_BOARD_COMMAND "arc-reset-board"
#define ARC_LIST_ACTIONPOINTS_COMMAND "arc-list-actionpoints"
#define ARC_FSM_DEBUG_COMMAND "arcjtag-debug-statemachine"
#define ARC_JTAG_RETRY_COMMAND "arcjtag-retry-count"
#define ARC_CONFIGURATION_COMMAND_USAGE "Usage: info " ARC_CONFIGURATION_COMMAND "\n"
#define ARC_RESET_BOARD_COMMAND_USAGE "Usage: " ARC_RESET_BOARD_COMMAND "\n"
#define ARC_LIST_ACTIONPOINTS_COMMAND_USAGE "Usage: " ARC_LIST_ACTIONPOINTS_COMMAND "\n"
/* The gdb target operations structure for this target. */
static struct target_ops jtag_target_ops;
/* A set of pointers to operations for reading/writing registers/memory in the
JTAG target. */
static TargetOperations operations;
/* The h/w register numbers of various auxiliary registers needed for
controlling the target processor. */
static ARC_RegisterNumber lp_start_regnum;
static ARC_RegisterNumber lp_end_regnum;
static ARC_RegisterNumber icache_ivic_regnum;
static ARC_RegisterNumber icache_control_regnum;
static ARC_RegisterNumber dcache_ivdc_regnum;
static ARC_RegisterNumber dcache_control_regnum;
/* -------------------------------------------------------------------------- */
/* external data */
/* -------------------------------------------------------------------------- */
/* This declaration should be in the file breakpoint.h (a gdb core file). */
extern struct breakpoint *breakpoint_chain;
/* -------------------------------------------------------------------------- */
/* local macros */
/* -------------------------------------------------------------------------- */
#define IS_ARC700 (arc_get_architecture(arc_read_jtag_aux_register) == ARC700)
#define IS_ARC600 (arc_get_architecture(arc_read_jtag_aux_register) == ARC600)
/* -------------------------------------------------------------------------- */
/* local functions */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* 1) functions for reading/writing registers */
/* -------------------------------------------------------------------------- */
/* Set UB bit in the DEBUG register: this allows brk_s instruction to work in
User mode.
Returns TRUE if the operation is successful. */
static Boolean
set_debug_user_bit (ARC_RegisterContents extra_bits)
{
/* The DEBUG User bit exists only in the ARC700 variant. */
if (IS_ARC700)
extra_bits |= DEBUG_USER;
/* If we have extra bits to be set in the DEBUG register. */
if (extra_bits != 0)
{
ARC_RegisterContents debug;
if (arc_read_jtag_aux_register(arc_debug_regnum, &debug, TRUE))
{
/* Set UB = 1. */
ARC_RegisterContents new_debug = debug | extra_bits;
/* Do the write only if it will change the register contents. */
if (new_debug != debug)
return arc_write_jtag_aux_register(arc_debug_regnum, new_debug, TRUE);
}
else
return FALSE;
}
return TRUE;
}
/* Clear or restore the User bit in the STATUS32 auxiliary register. */
static void
change_status32 (Status32Action action)
{
static ARC_RegisterContents status32 = 0;
if (action == CLEAR_USER_BIT)
{
/* Get processor out of user mode. */
if (arc_read_jtag_aux_register(arc_status32_regnum, &status32, FALSE))
{
/* If the User bit is actually set. */
if (status32 & STATUS32_USER)
if (!arc_write_jtag_aux_register(arc_status32_regnum,
status32 & ~STATUS32_USER, FALSE))
warning(_("can not clear User bit in STATUS32 auxiliary register"));
}
else
warning(_("can not read STATUS32 auxiliary register"));
}
else
{
/* If the User bit was actually cleared. */
if (status32 & STATUS32_USER)
if (!arc_write_jtag_aux_register(arc_status32_regnum, status32, FALSE))
warning(_("can not restore User bit in STATUS32 auxiliary register"));
}
}
/* -------------------------------------------------------------------------- */
/* 2) functions for reading/writing mmeory */
/* -------------------------------------------------------------------------- */
/* These functions should NOT be used within this module: they are intended
purely for use by the arc-memory module for reading/writing multiple words
of data at word-aligned addresses. */
static unsigned int
read_words (ARC_Address address,
ARC_Byte *data,
unsigned int words)
{
DEBUG("reading %u words from 0x%08X on target board\n", words, address);
gdb_assert(IS_WORD_ALIGNED(address));
return arc_jtag_ops.memory_read_chunk(address, data, words);
}
static unsigned int
write_words (ARC_Address address,
ARC_Byte *data,
unsigned int words)
{
gdb_assert(IS_WORD_ALIGNED(address));
DEBUG("writing %u words to 0x%08X on target board\n", words, address);
return arc_jtag_ops.memory_write_chunk(address, data, words);
}
static unsigned int
write_pattern (ARC_Address address,
ARC_Word pattern,
unsigned int words)
{
gdb_assert(IS_WORD_ALIGNED(address));
DEBUG("writing pattern 0x%08X repeated %u times to 0x%08X on target board\n", pattern, words, address);
return arc_jtag_ops.memory_write_pattern(address, pattern, words);
}
/* -------------------------------------------------------------------------- */
/* 3) functions for processor cache management */
/* -------------------------------------------------------------------------- */
/* Invalidate the target processor's caches. */
static void
invalidate_caches (void)
{
/* N.B. when invalidating the data caches, we must first set the DC_CTRL.IM
bit to 1 to ensure that any "dirty" lines in the cache get flushed
to main memory. */
(void) arc_write_jtag_aux_register(dcache_control_regnum, DC_CTRL_IM, TRUE);
(void) arc_write_jtag_aux_register(icache_ivic_regnum, IC_IVIC_IV, TRUE);
(void) arc_write_jtag_aux_register(dcache_ivdc_regnum, DC_IVDC_IV, TRUE);
}
/* Disable the target processor's caches. */
static void
disable_caches (void)
{
(void) arc_write_jtag_aux_register(icache_control_regnum, IC_CTRL_DC, TRUE);
(void) arc_write_jtag_aux_register(dcache_control_regnum, DC_CTRL_DC, TRUE);
}
/* -------------------------------------------------------------------------- */
/* 4) functions for JTAG interface management */
/* -------------------------------------------------------------------------- */
/* Open the JTAG interface to the debug target. */
static Boolean
open_JTAG_interface (int from_tty)
{
/* This is somewhat inelegant, but commands read from scripts in the gdb
testsuite are regarded as though they were being input interactively
(i.e. from_tty is 1), and interactive queries may be made (such as
asking the user whether the program currently being debugged should be
killed first) - and these queries hang the tests!
So, if the environment variable is set, assume that the gdb test suite is
being run, so that no such queries will be made.
It is not possible to make this check in the top-level command handler
loop, as the output from some other commands (e.g. 'file') depend on the
from_tty parameter passed to them, and the gdb test scripts expect to get
the interactive version of the output! */
target_preopen(from_tty && (getenv("ARC_GDB_TEST") == NULL));
gdb_assert(arc_jtag_ops.open != NULL);
return arc_jtag_ops.open(arc_aux_find_register_number("MEMSUBSYS", ARC_HW_MEMSUBSYS_REGNUM));
}
/* Close the JTAG interface to the debug target.
Parameter:
resume: TRUE if program execution on the target should be allowed to resume
*/
static void
close_JTAG_interface (Boolean resume)
{
/* If we have a target connected. */
if (arc_jtag_ops.status == JTAG_OPENED)
{
arc_elf32_close(resume);
/* And close the connection. */
arc_jtag_ops.close();
}
}
/* -------------------------------------------------------------------------- */
/* 5) functions for starting/stopping the processor */
/* -------------------------------------------------------------------------- */
/* Start the processor by clearing the 'H' bit in the STATUS32 register. */
static void
start_processor (void)
{
ARC_RegisterContents status32;
if (!arc_read_jtag_aux_register (arc_status32_regnum, &status32, FALSE) ||
!arc_write_jtag_aux_register(arc_status32_regnum, status32 & ~STATUS32_HALT, FALSE))
warning(_("can not clear Halt bit in STATUS32 auxiliary register - can not start processor"));
}
/* Stop the processor by setting the 'FH' bit in the DEBUG register. */
static void
stop_processor (void)
{
if (!arc_write_jtag_aux_register(arc_debug_regnum, DEBUG_FORCE_HALT, FALSE))
warning(_("can not set Force Halt bit in DEBUG auxiliary register - can not halt processor"));
}
/* Try to halt the processor (if it is running) upon connection to the debug
target. Return TRUE if the processor is successfuly halted. */
static Boolean
halt_processor_on_connection (void)
{
Boolean warn_on_read_failure = TRUE;
Boolean inform_running = TRUE;
Boolean halt_attempted = FALSE;
unsigned int tries = 0;
/* Unfortunately, if the gpio driver module has been installed on the host
machine, the gpio read/write operations appear to work even if the host
is NOT physically connected to the JTAG target!
There does not appear to be any way of detecting that situation - all we
can do is bale out if we have not succeded in reading the STATUS32 register
after the required number of retries! */
do
{
ARC_RegisterContents status = 0;
/* Read the STATUS32 register here to check if the halt bit is set. */
if (arc_read_jtag_aux_register(arc_status32_regnum, &status, warn_on_read_failure))
{
if (status & STATUS32_HALT)
{
printf_filtered(_("Processor is halted.\n"));
return TRUE;
}
if (inform_running)
{
/* We inform the user that the processor is running only once
(to avoid swamping the user with messages!). */
printf_filtered(_("Processor is running. Trying to halt it...\n"));
inform_running = FALSE;
}
stop_processor();
halt_attempted = TRUE;
}
else
{
/* We give a warning only on the first read failure (otherwise the
user can get swamped with warnings!). */
warn_on_read_failure = FALSE;
}
/* Just in case we actually did fail to read/write the port. */
if (gpio_port_error)
{
warning(_("error in accessing parallel port via "
GPIO_DEVICE
" - check connection to target board."));
return FALSE;
}
}
while (++tries <= arc_jtag_ops.retry_count);
if (halt_attempted)
printf_filtered(_("Can not halt processor!\n"));
else
printf_filtered(_("Can not connect to processor!\n"));
return FALSE;
}
/* -------------------------------------------------------------------------- */
/* 6) local functions called from outside this module (from gdb) */
/* -------------------------------------------------------------------------- */
/* Connect to the JTAG target.
Parameters:
args : user arguments to the 'target' command
from_tty: non-zero if the 'target' command was issued at the terminal
The arguments may be:
noreset | <xbf file>
If a XBF file is specified, the target board FPGA is blasted as part of the
connection process. */
static void
arc_jtag_open (char *args, int from_tty)
{
/* By default, reset the board, in case it has been left in a funny state by
the last connection. */
Boolean reset_required = TRUE;
char *xbf_file = NULL;
FPGA_Status fpga;
ENTERARGS("\"%s\" (%d)", (args) ? args : "", from_tty);
if (args)
{
if (strcmp(args, "noreset") == 0)
reset_required = FALSE;
else
xbf_file = args;
}
/* Is the target board FPGA already configured? */
fpga = arc_is_FPGA_configured();
switch (fpga)
{
case INACCESSIBLE:
/* A warning has already been given. */
return;
case UNCONFIGURED:
if (xbf_file == NULL)
{
warning(_("target FPGA is not configured; XBF file must be specified"));
return;
}
break;
case CONFIGURED:
break;
}
/* As far as we know, there is no program loaded on the target. */
arc_program_is_loaded = FALSE;
/* Find the h/w register numbers of various auxiliary registers that we need
for debugging.
N.B. the gdb 'attach' command can attach only to an arcjtag target that
has been created (by this function) within the *same* debugging
session, i.e. the sequence of commands issued by the user is of the
form:
target arcjtag ... detach ... attach
This means that we do not need to worry about finding these numbers
again on an 'attach', as they should be the same (they should really
be the same for *any* target, anyway - we are simply being paranoid
in looking them up, rather than having their numbers hard-coded, in
any case!).
Of course, there are really pathological cases such as the user
blasting the (ARCangel) target with an XBF giving a different
processor configuration, or even physically disconnecting the target
from the host machine and connecting a different target, between
issuing the 'detach' and the 'attach' commands (and that could change
the target's actionpoint configuration, if nothing else!) - but if
the user wants to do that then that is his problem! */
arc_elf32_find_register_numbers();
lp_start_regnum = arc_aux_find_register_number("LP_START", ARC_HW_LP_START_REGNUM);
lp_end_regnum = arc_aux_find_register_number("LP_END", ARC_HW_LP_END_REGNUM);
icache_ivic_regnum = arc_aux_find_register_number("IC_IVIC", ARC_HW_IC_IVIC_REGNUM);
icache_control_regnum = arc_aux_find_register_number("IC_CTRL", ARC_HW_IC_CTRL_REGNUM);
dcache_ivdc_regnum = arc_aux_find_register_number("DC_IVDC", ARC_HW_DC_IVDC_REGNUM);
dcache_control_regnum = arc_aux_find_register_number("DC_CTRL", ARC_HW_DC_CTRL_REGNUM);
/* Just to be sure that it is not in the target stack... */
(void) unpush_target (&jtag_target_ops);
/* Now try to open the JTAG interface. */
if (open_JTAG_interface(from_tty))
{
/* If a reset is required, do it now, in case it is necessary to reset
the target clock sources to their defaults before trying to access
the target's auxiliary registers! */
if (reset_required)
{
arc_reset_board();
arc_jtag_ops.reset_board();
}
if (fpga == CONFIGURED)
{
/* If we are going to blast the board, don't bother halting the
processor first. */
if ((xbf_file == NULL) && !halt_processor_on_connection())
{
/* We could not halt the processor. */
close_JTAG_interface(FALSE);
return;
}
}
/* If we have been given an XBF file. */
if (xbf_file)
{
/* Try to blast the board.
N.B. if the blasting operation fails for any reason,
arc_blast_board calls error and does not return! */
arc_blast_board(xbf_file, from_tty);
}
/* Get out of user mode so that we can access anything anywhere. */
change_status32(CLEAR_USER_BIT);
/* We do not know whether the target processor supports actionpoints until
after we have connected to it, as we have to read the AP_BUILD
configuration register to find that out. */
(void) arc_initialize_actionpoint_ops(&jtag_target_ops);
(void) push_target (&jtag_target_ops);
if (!reset_required)
{
/* If we have been explicitly told NOT to reset the board, it is
most likely because we have connected to a target upon which a
program is running and we want to debug that program - so assume
we have a program ready for execution on the target. */
target_mark_running(&jtag_target_ops);
arc_program_is_loaded = TRUE;
/* Set to_has_execution back to 0; this stops the user getting the
A program is being debugged already.
Are you sure you want to change the file? (y or n) n
message on issuing the 'file' command after the connection. */
current_target.to_has_execution = 0;
}
if (from_tty)
printf_filtered (_("Connected to the " ARC_TARGET_NAME " target.\n"));
}
else
error(_("Can not connect to target"));
}
/* Close the connection to the target. */
static void
arc_jtag_close (int quitting)
{
ENTERMSG;
close_JTAG_interface(FALSE);
}
/* Attach to the debug target without resetting the board.
Parameters:
args : user arguments to the 'attach' command (ignored)
from_tty: non-zero if the 'attach' command was issued at the terminal
*/
static void
arc_jtag_attach (char *args, int from_tty)
{
ENTERARGS("\"%s\" (%d)", args, from_tty);
/* Try to open the JTAG interface. */
if (open_JTAG_interface(from_tty))
{
/* Try to halt the processor (if it is running). */
if (halt_processor_on_connection())
{
/* Check that the processor architecture is correct. */
ARCHITECTURE_CHECK(current_gdbarch,
(current_objfile) ? current_objfile->obfd : NULL);
if (from_tty)
printf_filtered (_("Connected to the " ARC_TARGET_NAME " target.\n"));
}
}
else
error(_("Can not connect to target"));
}
/* Detach from the debug target without resetting the board.
Parameters:
args : user arguments to the 'detach' command (ignored)
from_tty: non-zero if the 'detach' command was issued at the terminal
*/
static void
arc_jtag_detach (char *args, int from_tty)
{
ENTERMSG;
close_JTAG_interface(TRUE);
}
/* Cause the inferior on the debug target to resume execution, sending a signal
if necessary.
Parameters:
ptid : the thread id of the thread to be resumed (ignored)
step : 1 means single step, 0 run freely.
signal: the number of the signal to be sent
N.B. signals are not supported. */
static void
arc_jtag_resume (ptid_t ptid, int step, enum target_signal signal)
{
ENTERARGS("%d, %d, %d", ptid.pid, step, signal);
if (signal != TARGET_SIGNAL_0)
error(_("Signals are not supported by the " ARC_TARGET_NAME " target"));
/* If we cleared the User bit in the STATUS32 bit the last time that
execution halted, restore it now. */
change_status32(RESTORE_USER_BIT);
/* Software breakpoints may have been set/removed, and data in main memory
may have been altered, so invalidate (and flush!) the instruction and
data caches before restarting!
N.B. arc_jtag_open disabled the caches, so what is the point of doing this?
Also, invalidating a disabled cache when DC_CTRL.IM = 1 seems to have
the effect of overwriting valid data!!!!! */
// invalidate_caches ();
/* The DEBUG User bit must be set if breakpoints are to be allowed in user
mode. We could set it in target_open, but something (the user?) might clear it.
So we set it every time we resume (if stepping, we set the extra bit(s) we
need in the DEBUG register in the same operation). */
if (step)
{
ARC_RegisterContents mask = 0;
DEBUG("setting DEBUG.IS bit for single-step\n");
/* The mask for single-stepping differs between ARC600 and ARC700. */
if (IS_ARC700)
mask = DEBUG_INSTRUCTION_STEP;
else
if (IS_ARC600)
mask = DEBUG_INSTRUCTION_STEP | DEBUG_SINGLE_STEP;
/* Allow breakpoints in User mode, and set the IS bit in the DEBUG
register for hardware single instruction stepping. */
if (!set_debug_user_bit (mask))
error(_("Can not single-step one instruction"));
}
else
{
/* Allow breakpoints in User mode (no extra bits required). */
(void) set_debug_user_bit (0);
start_processor();
}
LEAVEMSG;
}
/* Wait for execution on the target to halt (for whatever reason).
Parameters :
ptid : ignored
status: set to indicate status at end of the wait
*/
static ptid_t
arc_jtag_wait (ptid_t ptid, struct target_waitstatus *status)
{
ENTERMSG;
/* Execute the program on the target processor. */
arc_elf32_execute(status,
NULL,
start_processor,
stop_processor);
/* The target has now halted. */
if (status->kind == TARGET_WAITKIND_EXITED)
target_mark_exited (&jtag_target_ops);
/* Get out of user mode so that we can access anything anywhere. */
change_status32(CLEAR_USER_BIT);
/* Inform the actionpoints module that the target has halted. */
arc_target_halted();
/* Bug #1311 (ARC600): Setting a breakpoint on the last instruction of a
ZOL causes GDB to stop at LP_START. Detect this condition and warn the
user. */
if (IS_ARC600)
{
ARC_RegisterContents pc, lp_start, lp_end, lp_count;
if (arc_read_jtag_core_register(ARC_LP_COUNT_REGNUM, &lp_count, TRUE) && (lp_count != 0) &&
arc_read_jtag_aux_register (arc_pc_regnum, &pc, TRUE) &&
arc_read_jtag_aux_register (lp_start_regnum, &lp_start, TRUE) && (pc == lp_start) &&
arc_read_jtag_aux_register (lp_end_regnum, &lp_end, TRUE))
{
struct breakpoint *b;
for (b = breakpoint_chain; b != NULL; b = b->next)
{
/* lp_end is the address of the last instruction + the size of
the last instruction. We could use the disassembler and find
out the size, but it's easier just to try both possible sizes. */
if ((b->enable_state == bp_enabled) &&
(b->loc->address == lp_end - 4 || b->loc->address == lp_end - 2))
{
warning(_("did you set a breakpoint on the last instruction of a"
"Zero Overhead Loop? Such breakpoints do not work properly."));
}
}
}
}
LEAVEMSG;
return inferior_ptid;
}
/* This gets called just before store_regs. */
static void
arc_jtag_prepare_to_store (struct regcache *regcache)
{
ENTERMSG;
}
static void
arc_jtag_files_info (struct target_ops *target)
{
/* Do nothing. */
ENTERMSG;
}
/* Heavy duty arsenal. Kill the process.
Maybe we should do a board reset and kill it. */
static void
arc_jtag_kill (void)
{
ENTERMSG;
target_mourn_inferior ();
}
/* Create the inferior that will be executed upon the target.
Parameters :
exec_file: the executable file containing the program to be executed
args : the command line arguments to be passed to the program
env : the environment (name/value pairs) for the program
from_tty : ignored
*/
static void
arc_jtag_create_inferior (char *exec_file, char *args, char **env, int from_tty)
{
arc_elf32_create_inferior(exec_file, args, env, &jtag_target_ops);
/* Why are the caches disabled anyway? Particularly as arc_jtag_resume
invalidates them before each restart? */
disable_caches();
}
/* Mourn the inferior. */
static void
arc_jtag_mourn_inferior (void)
{
ENTERMSG;
// (void) unpush_target (&jtag_target_ops);
generic_mourn_inferior ();
current_target.to_has_execution = 0;
}
/* Check whether the given thread is alive. */
static int
arc_jtag_thread_alive (ptid_t ptid)
{
ENTERMSG;
/* We only have one thread. */
return 1;
}
/* Check whether our debug target is runnable: return 1 if it is, 0 otherwise. */
static int
arc_jtag_can_run (void)
{
/* If we are connected to the JTAG i/f, and a program is loaded. */
return (arc_jtag_ops.status == JTAG_OPENED) && arc_program_is_loaded;
}
/* We do not support asynchronous execution of the target program (i.e. commands
like 'run' or 'continue' or 'step' can not be executed in background mode
by appending a '&' to them) so we do not need to implement the target stop
operation (called by the 'interrupt' command); interrupting a running program
is handled by the Ctrl-C mechanism. */
#if 0
static void
arc_jtag_stop (void)
{
ENTERMSG;
}
#endif
/* -------------------------------------------------------------------------- */
/* 7) local functions implementing commands */
/* -------------------------------------------------------------------------- */
/* Print processor-variant information. */
static void
arc_print_processor_variant_info (char *arg, int from_tty)
{
printf_filtered
(_("%s\n"),
arc_version_image(arc_get_architecture(arc_read_jtag_aux_register)));
}
/* Reset the target board. */
static void
arc_jtag_reset_board (char *arg, int from_tty)
{
/* Make sure the GPIO interface is open. */
if (gpio_open())
{
printf_filtered(_("Attempting to reset target board...\n"));
if (arc_jtag_ops.status == JTAG_OPENED)
{
/* Try to force the processor to halt. */
stop_processor();
}
/* Try to reset the board. */
arc_reset_board();
arc_jtag_ops.reset_board();
if (arc_jtag_ops.status == JTAG_OPENED)
{
/* The ARC actionpoint registers are cleared upon reset, so it is
necessary to restore any actionpoints that were set. */
if (!arc_restore_actionpoints_after_reset())
warning(_("can not restore hardware actionpoints"));
}
}
}
/* List the ARC target processor actionpoints. */
static void
arc_list_actionpoints (char *arg, int from_tty)
{
/* gdb manages breakpoints by deleting them from the target as soon as it
has halted, then re-inserting them again immediately before execution is
resumed (no, I don't know why either, unless it is to make generating a
disassembly display easier by removing all the s/w b/ps from the code) -
so in order to display what actionpoints are currently in use, we must
temporarily re-insert the breakpoints! */
insert_breakpoints();
arc_display_actionpoints();
(void) remove_breakpoints();
}
/* -------------------------------------------------------------------------- */
/* 8) initialization functions */
/* -------------------------------------------------------------------------- */
/* Initialize the JTAG target operations. */
static void
initialize_jtag_target_ops (void)
{
ENTERMSG;
jtag_target_ops.to_data = &operations;
jtag_target_ops.to_shortname = ARC_TARGET_NAME;
jtag_target_ops.to_longname = "Remote JTAG debug target (ARC Processors)";
jtag_target_ops.to_doc = "Remote JTAG debug target (ARC Processors)";
jtag_target_ops.to_open = arc_jtag_open;
jtag_target_ops.to_close = arc_jtag_close;
jtag_target_ops.to_attach = arc_jtag_attach;
jtag_target_ops.to_detach = arc_jtag_detach;
jtag_target_ops.to_resume = arc_jtag_resume;
jtag_target_ops.to_wait = arc_jtag_wait;
jtag_target_ops.to_fetch_registers = arc_elf32_fetch_registers;
jtag_target_ops.to_store_registers = arc_elf32_store_registers;
jtag_target_ops.to_prepare_to_store = arc_jtag_prepare_to_store;
jtag_target_ops.to_xfer_partial = arc_elf32_xfer_partial;
jtag_target_ops.to_files_info = arc_jtag_files_info;
jtag_target_ops.to_insert_breakpoint = arc_elf32_insert_breakpoint;
jtag_target_ops.to_remove_breakpoint = arc_elf32_remove_breakpoint;
jtag_target_ops.to_kill = arc_jtag_kill;
jtag_target_ops.to_load = arc_elf32_load_program;
jtag_target_ops.to_create_inferior = arc_jtag_create_inferior;
jtag_target_ops.to_mourn_inferior = arc_jtag_mourn_inferior;
jtag_target_ops.to_thread_alive = arc_jtag_thread_alive;
// jtag_target_ops.to_stop = arc_jtag_stop;
jtag_target_ops.to_can_run = arc_jtag_can_run;
jtag_target_ops.to_terminal_inferior = NULL;
jtag_target_ops.to_stratum = process_stratum;
jtag_target_ops.to_has_all_memory = 1;
jtag_target_ops.to_has_memory = 1;
jtag_target_ops.to_has_stack = 0; /* Defer setting this until the program has been loaded. */
jtag_target_ops.to_has_registers = 1;
jtag_target_ops.to_has_execution = 0; /* Defer setting this until the program has been started. */
jtag_target_ops.to_magic = OPS_MAGIC;
}
/* -------------------------------------------------------------------------- */
/* externally visible functions */
/* -------------------------------------------------------------------------- */
/* Initialize the module. This function is called from the gdb core on start-up. */
void
_initialize_arc_jtag (void)
{
ENTERMSG;
operations.read_core_register = arc_read_jtag_core_register;
operations.write_core_register = arc_write_jtag_core_register;
operations.read_auxiliary_register = arc_read_jtag_aux_register;
operations.write_auxiliary_register = arc_write_jtag_aux_register;
operations.read_memory = read_words;
operations.write_memory = write_words;
operations.fill_memory = write_pattern;
initialize_jtag_target_ops ();
add_target (&jtag_target_ops);
/* Register ARC-specific commands with gdb. */
add_setshow_boolean_cmd(ARC_FSM_DEBUG_COMMAND,
no_class,
&arc_jtag_ops.state_machine_debug,
_("Set whether to print JTAG state machine debug messages.\n"),
_("Show whether to print JTAG state machine debug messages.\n"),
_("If set the JTAG state machine messages are printed.\n"),
NULL,
NULL,
&setlist,
&showlist);
add_setshow_uinteger_cmd(ARC_JTAG_RETRY_COMMAND,
no_class,
&arc_jtag_ops.retry_count,
_("Set the number of attempts to be made for a JTAG operation.\n"),
_("Show the number of attempts to be made for a JTAG operation.\n"),
_("Indicates the number of times a JTAG operation is attempted before returning a failure.\n"),
NULL,
NULL,
&setlist,
&showlist);
(void) add_cmd(ARC_CONFIGURATION_COMMAND,
class_info,
arc_print_processor_variant_info,
_("Show ARC configuration information.\n"
ARC_CONFIGURATION_COMMAND_USAGE),
&infolist);
(void) add_cmd(ARC_RESET_BOARD_COMMAND,
class_obscure,
arc_jtag_reset_board,
_("Reset the board.\n"
ARC_RESET_BOARD_COMMAND_USAGE),
&cmdlist);
(void) add_cmd(ARC_LIST_ACTIONPOINTS_COMMAND,
class_obscure,
arc_list_actionpoints,
_("List the processor actionpoints.\n"
ARC_LIST_ACTIONPOINTS_COMMAND_USAGE),
&cmdlist);
}
/* N.B. the core and auxiliary register contents read from or written to the
target via the arc-jtag-ops module are ALWAYS in little-endian format,
regardless of the endianness of the target processor. Given that the
values passed to/from the functions below are in host byte order, and
the host is little-endian (since the ARC gdb is currently built only
on an X86 Linux host), this means that no byte-swapping is required
here. This will require changing if the debugger is ever built upon a
big-endian host (such as a Sun). */
/* Read a core register on the target.
Parameters:
hw_regno : the ARC hardware number of the register
value : set to the contents of the register
warn_on_failure: TRUE if a warning should be issued if the read fails
Result: TRUE if the register contents are read. */
Boolean
arc_read_jtag_core_register (ARC_RegisterNumber hw_regno,
ARC_RegisterContents *contents,
Boolean warn_on_failure)
{
if (arc_jtag_ops.read_core_reg(hw_regno, contents) == JTAG_SUCCESS)
{
DEBUG("Read value 0x%08X from core register %d\n", *contents, hw_regno);
return TRUE;
}
if (warn_on_failure)
arc_elf32_core_warning(ERROR_ON_READING_REGISTER, hw_regno);
return FALSE;
}
/* Write a core register on the target.
Parameters:
hw_regno : the ARC hardware number of the register
value : set to the contents of the register
warn_on_failure: TRUE if a warning should be issued if the write fails
Result: TRUE if the register contents are written. */
Boolean
arc_write_jtag_core_register (ARC_RegisterNumber hw_regno,
ARC_RegisterContents contents,
Boolean warn_on_failure)
{
if (arc_jtag_ops.write_core_reg(hw_regno, contents) == JTAG_SUCCESS)
{
DEBUG("Written value 0x%08X to core register %d\n", contents, hw_regno);
return TRUE;
}
if (warn_on_failure)
arc_elf32_core_warning(ERROR_ON_WRITING_REGISTER, hw_regno);
return FALSE;
}
/* Read an auxiliary register on the target.
Parameters:
hw_regno : the ARC hardware number of the register
value : set to the contents of the register
warn_on_failure: TRUE if a warning should be issued if the read fails
Result: TRUE if the register contents are read. */
Boolean
arc_read_jtag_aux_register (ARC_RegisterNumber hw_regno,
ARC_RegisterContents *contents,
Boolean warn_on_failure)
{
if (arc_jtag_ops.read_aux_reg(hw_regno, contents) == JTAG_SUCCESS)
{
DEBUG("Read value 0x%08X from auxiliary register %d\n", *contents, hw_regno);
return TRUE;
}
if (warn_on_failure)
arc_elf32_aux_warning(ERROR_ON_READING_REGISTER, hw_regno);
return FALSE;
}
/* Write an auxiliary register on the target.
Parameters:
hw_regno : the ARC hardware number of the register
value : the contents of the register
warn_on_failure: TRUE if a warning should be issued if the write fails
Result: TRUE if the register contents are written. */
Boolean
arc_write_jtag_aux_register (ARC_RegisterNumber hw_regno,
ARC_RegisterContents contents,
Boolean warn_on_failure)
{
ARC_AuxRegisterDefinition *def = arc_find_aux_register_by_hw_number(hw_regno);
if (def)
contents = arc_write_value(def, contents);
if (arc_jtag_ops.write_aux_reg(hw_regno, contents) == JTAG_SUCCESS)
{
DEBUG("Written value 0x%08X to auxiliary register %d\n", contents, hw_regno);
return TRUE;
}
if (warn_on_failure)
arc_elf32_aux_warning(ERROR_ON_WRITING_REGISTER, hw_regno);
return FALSE;
}
/******************************************************************************/