| /* 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; |
| } |
| |
| /******************************************************************************/ |