| /* Target dependent code for ARC700, for GDB, the GNU debugger. |
| |
| Copyright 2005 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> |
| |
| 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 2 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, write to the Free Software |
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| */ |
| |
| #include <stdio.h> |
| #include <string.h> |
| #include "defs.h" |
| #include "inferior.h" |
| #include "target.h" |
| #include "breakpoint.h" |
| |
| #include "arc-tdep.h" |
| |
| #include <unistd.h> |
| #include <stdlib.h> |
| |
| #include <sys/io.h> |
| #include <sys/types.h> |
| |
| #include <assert.h> |
| |
| #include "arc-jtag.h" |
| #include "arc-jtag-ops.h" |
| #include "gdbcore.h" |
| #include "gdbarch.h" |
| #include "regcache.h" |
| #include "command.h" |
| #include "gdbcmd.h" |
| #include <signal.h> |
| |
| /* Flag to print debug messages from here. */ |
| /* FIXMEA: |
| static int debug_arc_jtag_target_message; |
| */ |
| |
| #define ENTERMSG \ |
| do {\ |
| if(debug_arc_jtag_target_message) \ |
| printf_filtered ("--- entered %s:%s()\n", __FILE__, __FUNCTION__); \ |
| } while(0) |
| |
| #define ENTERARGS(fmt, args...) \ |
| do { \ |
| if(debug_arc_jtag_target_message) \ |
| printf_filtered ("--- entered %s:%s(" fmt ")\n", __FILE__, __FUNCTION__, args);\ |
| } while(0) |
| |
| #define LEAVEMSG \ |
| do { \ |
| if(debug_arc_jtag_target_message) \ |
| printf_filtered ("--- exited %s:%s()\n", __FILE__, __FUNCTION__); \ |
| } while(0) |
| |
| /* The number of times a memory read/write operation should be attempted |
| before returning an error. |
| */ |
| #define MEMORY_TRANSFER_ATTEMPTS 10 |
| |
| /* defined in arc-jtag-ops.c */ |
| extern unsigned int arcjtag_retry_count; |
| |
| struct target_ops arc_debug_ops; |
| extern struct jtag_ops arc_jtag_ops; |
| |
| static void arc_debug_interrupt (int signo); |
| static void arc_debug_interrupt_twice (int signo); |
| static void arc_print_processor_variant_info (void); |
| static int arc_debug_write_aux_register (int hwregno, int *buf); |
| static int arc_debug_read_aux_register (int hwregno, int *buf); |
| static int arc_debug_read_core_register (int hwregno, int *buf); |
| |
| |
| /* Register Mapping information between GDB regnums |
| and actual hardware register numbers. |
| */ |
| |
| struct arc_reg_info |
| { |
| char *name ; |
| enum arc_hw_regnums hw_regno; |
| char *description; |
| #ifdef ARC4_JTAG |
| enum arc4_jtag_regnums gdbregno; |
| #else |
| enum arc700_jtag_regnums gdbregno; |
| #endif |
| enum ARCProcessorVersion arcVersionSupported; |
| }; |
| |
| #define RBCR(name, hwregno , desc, gdbregno, version) { #name, hwregno , desc , gdbregno , version } , |
| |
| #undef RAUX |
| struct arc_reg_info arc_bcr_reg_info [] = |
| { |
| #include "arc-regnums-defs.h" |
| }; |
| |
| #undef RAUX |
| #undef RBCR |
| #define RAUX(name, hwregno , desc, gdbregno, version) { #name , hwregno , desc , gdbregno , version } , |
| struct arc_reg_info arc_aux_reg_map[] = |
| { |
| #include "arc-regnums-defs.h" |
| }; |
| |
| |
| |
| static void |
| arc_update_architecture(void) |
| { |
| unsigned int idinfo; |
| unsigned short tmp; |
| struct gdbarch_tdep * tdep = gdbarch_tdep (current_gdbarch); |
| |
| if (IS_ARC700) { |
| tdep->arc_processor_variant_info->arcprocessorversion = ARC700; |
| set_gdbarch_decr_pc_after_break (current_gdbarch,0); |
| } |
| else if(IS_ARC600) { |
| tdep->arc_processor_variant_info->arcprocessorversion = ARC600; |
| set_gdbarch_decr_pc_after_break (current_gdbarch,2); |
| } |
| else if(IS_A5) { |
| warning ("A5 debugging is unsupported and may be buggy."); |
| tdep->arc_processor_variant_info->arcprocessorversion = A5; |
| } |
| else { |
| tdep->arc_processor_variant_info->arcprocessorversion = A4; |
| set_gdbarch_decr_pc_after_break (current_gdbarch,0); |
| } |
| } |
| |
| /* Get us out of user mode. */ |
| static unsigned int |
| clear_status32_user_bit () |
| { |
| int rd; |
| #ifndef ARC4_JTAG |
| if(arc_jtag_ops.jtag_read_aux_reg(ARC_HW_STATUS32_REGNUM, &rd) == JTAG_READ_FAILURE) |
| error("Failure reading auxillary register 0x%x:status32 register", ARC_HW_STATUS32_REGNUM); |
| |
| if(arc_jtag_ops.jtag_write_aux_reg(ARC_HW_STATUS32_REGNUM, rd & ~0x80) == JTAG_READ_FAILURE) |
| error("Failure writing to auxillary register 0x%x:status32 register", ARC_HW_STATUS32_REGNUM); |
| #endif |
| return rd; |
| } |
| |
| /* Restore a saved status32; use with clear_status32_user_bit(). */ |
| static void |
| restore_status32_user_bit (unsigned int status32) |
| { |
| #ifndef ARC4_JTAG |
| if(arc_jtag_ops.jtag_write_aux_reg(ARC_HW_STATUS32_REGNUM, status32) == JTAG_READ_FAILURE) |
| error("Failure writing to auxillary register 0x%x:status32 register", ARC_HW_STATUS32_REGNUM); |
| #endif |
| } |
| |
| /* UB bit in the debug register. It allows brk_s to work in user mode. */ |
| static void |
| set_debug_user_bit () |
| { |
| if(is_arc700 ()) |
| { |
| /* set UB = 1 */ |
| unsigned int debug; |
| if (arc_jtag_ops.jtag_read_aux_reg (ARC_HW_DEBUG_REGNUM, &debug) == JTAG_READ_FAILURE) |
| error("Failure reading auxillary register 0x%x:debug register",ARC_HW_DEBUG_REGNUM); |
| debug |= 0x10000000; |
| arc_jtag_ops.jtag_write_aux_reg (ARC_HW_DEBUG_REGNUM, debug); |
| } |
| } |
| |
| |
| |
| static void |
| invalidateCaches (void) |
| { |
| if(arc_jtag_ops.jtag_write_aux_reg ( ARC_HW_ICACHE_IVIC , 1)==JTAG_WRITE_FAILURE) |
| error("Failure writing 0x1 to auxillary register 0x%x:Icache invalidate\n",ARC_HW_ICACHE_IVIC); |
| if(arc_jtag_ops.jtag_write_aux_reg ( ARC_HW_DCACHE_IVIC , 1)==JTAG_WRITE_FAILURE) |
| error("Failure writing 0x1 to auxillary register 0x%x:Dcache invalidate\n",ARC_HW_DCACHE_IVIC); |
| } |
| |
| static void |
| disableCaches (void) |
| { |
| /* Disabling Icache */ |
| if(arc_jtag_ops.jtag_write_aux_reg( ARC_HW_ICACHE_CONTROL ,0x1)==JTAG_WRITE_FAILURE) |
| error("Failure writing 0x1 to auxillary register 0x%x:Icache control register\n",ARC_HW_ICACHE_CONTROL); |
| /* Disabling Dcache */ |
| if(arc_jtag_ops.jtag_write_aux_reg( ARC_HW_DCACHE_CONTROL ,0x1)==JTAG_WRITE_FAILURE) |
| error("Failure writing 0x1 to auxillary register 0x%x:Dcache control register\n",ARC_HW_DCACHE_CONTROL); |
| } |
| |
| |
| /* Function: arc_debug_open |
| * Parameters : |
| * 1. args : |
| * 2. from_tty: |
| * Returns : void |
| * Description: |
| 1. Connect to the jtag target . |
| 2. Read the number of action points supported. |
| 3. Read the configuration of action points. |
| 4. Set up internal data structures for number of hardware |
| breakpoints and watchpoints. |
| 5. Set the UB bit to 1 for ARC700 and not for ARC600. |
| * |
| */ |
| |
| void |
| arc_debug_open (char *args, int from_tty) |
| { |
| ENTERARGS("%s", args); |
| target_preopen(from_tty); |
| |
| reopen_exec_file (); |
| reread_symbols (); |
| |
| unpush_target (&arc_debug_ops); |
| arc_jtag_ops.jtag_open(); |
| push_target (&arc_debug_ops); |
| |
| /* Call arc_update_architecture if opened successfully. */ |
| arc_update_architecture(); |
| /* Fixme :: Should these be in create_inferior or |
| some place else ?. We would not like these here |
| when attach starts working. |
| */ |
| disableCaches(); |
| #ifdef ARC4_JTAG |
| if(arc_jtag_ops.jtag_write_aux_reg (ARC_HW_STATUS_REGNUM, 0x02000000)==JTAG_WRITE_FAILURE) |
| error("Failure writing 0x0200 0000 to auxillary register 0x%x:status register\n",ARC_HW_STATUS_REGNUM); |
| |
| if (from_tty) |
| printf_filtered ("Connected to the arcjtag target.\n"); |
| |
| #else |
| if(arc_jtag_ops.jtag_write_aux_reg (ARC_HW_STATUS32_REGNUM, 0x1)==JTAG_WRITE_FAILURE) |
| |
| error("Failure writing 0x1 to auxillary register 0x%x:status32 register\n",ARC_HW_STATUS32_REGNUM); |
| |
| /* allow breakpoints in user mode. */ |
| set_debug_user_bit (); |
| |
| |
| if (from_tty) |
| printf_filtered ("Connected to the arcjtag target.\n"); |
| #endif |
| } |
| |
| void arc_debug_close() |
| { |
| arc_jtag_ops.jtag_close(); |
| } |
| |
| /* Function: arc_debug_attach |
| * Parameters : |
| * 1. char *x: |
| * 2. int i: |
| * Returns : void |
| * Description: |
| * 1. attach without resetting the board |
| * 2. get all Board configuration registers of interest. |
| * if ARC700 set the UB bit to 1. (This is invalid in the |
| * ARC600). |
| */ |
| |
| |
| void |
| arc_debug_attach (char *x, int i) |
| { |
| |
| ENTERMSG; |
| } |
| |
| |
| /* Function: arc_debug_attach |
| * Parameters : |
| * 1. char *x: |
| * 2. int i: |
| * Returns : void |
| * Description: |
| * 1. Detach without resetting the board. |
| */ |
| void |
| arc_debug_detach (char *x, int i) |
| { |
| |
| ENTERMSG; |
| |
| /* Let it continue. */ |
| target_resume (inferior_ptid, 0, 0); |
| } |
| |
| |
| /* Function: arc_debug_resume |
| * Parameters : |
| * 1. ptid_t ptid: |
| * 2. int step: 1 - single step , 0 run freely. |
| * 3. enum target_signal signal; |
| * Returns : void |
| * Description: |
| * 1. What about Pipecleaning? |
| * 2. Write 0 to the HALT bit in status32. |
| * 3. Send a signal (ignore) in this case. |
| * 4. if(step) use hardware single step on the ARC700. |
| * done by setting the IS bit in the debug register |
| * and clearing the halt bit in status32. |
| * |
| */ |
| |
| void |
| arc_debug_resume (ptid_t ptid, int step, enum target_signal signal) |
| { |
| |
| ENTERARGS("%d,%d,%d", ptid.pid, step, signal); |
| /* Make the inferior resume execution, sending a signal if necessary */ |
| unsigned int rd; |
| |
| /* Because breakpoints may have been set/removed. */ |
| invalidateCaches (); |
| |
| /* This bit is required if breakpoints are to be allowed in user mode. We |
| set it in target_open, but the operating system might clear it. So we |
| set it every time we resume. */ |
| set_debug_user_bit (); |
| |
| if(step) |
| { |
| |
| /* reading debug reg */ |
| if(arc_jtag_ops.jtag_read_aux_reg(ARC_HW_DEBUG_REGNUM,&rd)==JTAG_READ_FAILURE) |
| error("Failure reading auxillary register 0x%x:debug register",ARC_HW_DEBUG_REGNUM); |
| #ifdef ARC4_JTAG |
| rd |= 0x801; /*Setting the IS and the SS bit in the status register |
| for the A4 core to allow it to single step. */ |
| #else |
| /* Mask for Single Stepping changes for ARC600 and ARC700. */ |
| if(is_arc700()) |
| rd |= 0x800; |
| else |
| if(is_arc600()) |
| rd |= 0x801; |
| #endif |
| |
| /* Writing to IS bit in DEBUG register for |
| hardware single instruction stepping. */ |
| if(arc_jtag_ops.jtag_write_aux_reg(ARC_HW_DEBUG_REGNUM ,rd)==JTAG_WRITE_FAILURE) |
| error("Failure writing 0x%x to auxillary register 0x%x:debug register\n",rd,ARC_HW_DEBUG_REGNUM); |
| } |
| else |
| { |
| /* Restarting the processor by clearing the 'H' bit in the status register*/ |
| #ifdef ARC4_JTAG |
| /* reading the status reg */ |
| if(arc_jtag_ops.jtag_read_aux_reg(ARC_HW_STATUS_REGNUM,&rd)==JTAG_READ_FAILURE) |
| error("Failure reading auxillary register 0x%x:status register",ARC_HW_STATUS_REGNUM); |
| |
| rd = rd & ~(0x02000000); |
| |
| /* starting the halted processor */ |
| if(arc_jtag_ops.jtag_write_aux_reg(ARC_HW_STATUS_REGNUM,rd)==JTAG_WRITE_FAILURE) |
| error("Failure writing 0x%x to auxillary register 0x%x:status register\n",rd,ARC_HW_STATUS_REGNUM); |
| #else |
| /* reading the status32 reg */ |
| if(arc_jtag_ops.jtag_read_aux_reg(ARC_HW_STATUS32_REGNUM,&rd)==JTAG_READ_FAILURE) |
| error("Failure reading auxillary register 0x%x:status32 register",ARC_HW_STATUS32_REGNUM); |
| |
| rd = rd & ~(0x1); |
| |
| /* starting the halted processor */ |
| if(arc_jtag_ops.jtag_write_aux_reg(ARC_HW_STATUS32_REGNUM,rd)==JTAG_WRITE_FAILURE) |
| error("Failure writing 0x%x to auxillary register 0x%x:status32 register\n",rd,ARC_HW_STATUS32_REGNUM); |
| #endif |
| } |
| } |
| |
| /* For the ^C signal handler. */ |
| static void (*ofunc) (int); |
| |
| /* The command line interface's stop routine. This function is installed as |
| a signal handler for SIGINT. The first time a user requests a stop, we |
| call target_stop to send a break or ^C. If there is no response from the |
| target (it didn't stop when the user requested it), we ask the user if |
| he'd like to detach from the target. */ |
| static void |
| arc_debug_interrupt (int signo) |
| { |
| /* If we get the signal twice, do something more drastic. */ |
| signal (signo, arc_debug_interrupt_twice); |
| |
| target_stop (); |
| } |
| |
| /* The user typed ^C twice. */ |
| static void |
| arc_debug_interrupt_twice (int signo) |
| { |
| signal (signo, ofunc); |
| |
| if (query ("Interrupted while waiting for the program.\n\ |
| Give up (and stop debugging it)? ")) |
| { |
| target_mourn_inferior (); |
| throw_exception (RETURN_QUIT); |
| } |
| |
| signal (signo, arc_debug_interrupt); |
| } |
| |
| /* Function: arc_debug_wait |
| * Parameters : |
| * 1. ptid_t ptid: |
| * 2. struct target_waitstatus *status: Indicates status at end |
| of wait for F.E. |
| * Returns : void |
| * Description: |
| * Poll status32 for the value of H bit. |
| * After H bit is set in status32. |
| * Wait till LD(load pending bit) in the DEBUG register |
| * is cleared. |
| * SH bit is set if flag instruction was used to halt the processor. |
| * BH bit is set if the ARCompact processor stopped due to |
| * a brk_s instruction. Set the target_waitstatus (signal) to SIGTRAP |
| * only in such a situation. |
| * |
| */ |
| |
| ptid_t |
| arc_debug_wait (ptid_t ptid, struct target_waitstatus *status) |
| { |
| unsigned int debug; |
| ENTERMSG; |
| |
| /* signal handler for Control-C. */ |
| ofunc = signal (SIGINT, arc_debug_interrupt); |
| |
| arc_jtag_ops.jtag_wait(); |
| /* put the old function back. */ |
| signal (SIGINT, ofunc); |
| |
| /* If the SH ("self halt") bit is set, we stopped because of the flag |
| instruction, which is used by programs to exit. */ |
| if (arc_jtag_ops.jtag_read_aux_reg (ARC_HW_DEBUG_REGNUM, |
| &debug) == JTAG_READ_FAILURE) |
| { |
| error ("Failure reading from debug register"); |
| } |
| |
| /* SH bit of debug register */ |
| if (debug & ARC_DEBUG_REG_SH_BIT) |
| { |
| int exitcode; |
| status->kind = TARGET_WAITKIND_EXITED; |
| |
| /* Exit code of the program. */ |
| if (arc_jtag_ops.jtag_read_core_reg (0, &exitcode) == JTAG_READ_FAILURE) |
| { |
| warning ("Failure reading from register r0, assuming exit code = 0"); |
| status->value.integer = 0; |
| } |
| status->value.integer = exitcode; |
| } |
| else |
| { |
| status->kind = TARGET_WAITKIND_STOPPED; |
| status->value.sig = TARGET_SIGNAL_TRAP; |
| } |
| |
| #ifndef ARC4_JTAG |
| /* 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 ()) |
| { |
| unsigned int pc, lp_start, lp_end, lp_count; |
| arc_debug_read_core_register (ARC_LP_COUNT_REGNUM, &lp_count); |
| if (lp_count != 0) |
| { |
| arc_debug_read_aux_register (ARC_HW_PC_REGNUM, &pc); |
| arc_debug_read_aux_register (ARC_HW_LP_START_REGNUM, &lp_start); |
| |
| if (pc == lp_start) |
| { |
| extern struct breakpoint *breakpoint_chain; |
| struct breakpoint *b; |
| arc_debug_read_aux_register (ARC_HW_LP_END_REGNUM, &lp_end); |
| |
| for (b = breakpoint_chain; b; 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, or just try both |
| possible sizes. */ |
| if ((b->enable_state == bp_enabled && !b->pending) && |
| b->loc->address == lp_end-4 || b->loc->address == lp_end-2) |
| { |
| warning ("Did you set a breakpoint on the last instruction of \n\ |
| a Zero Overhead Loop ? Such breakpoints do not work properly."); |
| } |
| } |
| } |
| } |
| } |
| #endif |
| return inferior_ptid; |
| } |
| |
| static unsigned int |
| arc_get_hw_regnum_mapping ( int regno ) |
| { |
| int i; |
| |
| if (regno >= ARC_STATUS_REGNUM |
| #ifdef ARC4_JTAG |
| && regno <= ARC_DEBUG_REGNUM |
| #else |
| && regno <= ARC_AUX_IRQ_PENDING_REGNUM |
| #endif |
| ) |
| return arc_aux_reg_map[regno - ARC_STATUS_REGNUM].hw_regno; |
| |
| for ( i = 0 ; i < (sizeof(arc_bcr_reg_info) / sizeof (struct arc_reg_info)) ; i++) |
| { |
| if (regno == arc_bcr_reg_info[i].gdbregno) |
| return arc_bcr_reg_info[i].hw_regno; |
| } |
| |
| return -1; |
| } |
| |
| |
| /* Function: arc_debug_fetch_regs. |
| * Parameters : |
| * 1. int regnum: Register number. If register number is -1.Fetch |
| * all the registers.Read all core registers here. |
| * Returns : void |
| * Description: |
| * Set up regcache_raw_supply(current_regcache,regno) |
| * |
| */ |
| void |
| arc_debug_fetch_regs (int regno) |
| { |
| /* Read all core registers */ |
| ENTERARGS("%d",regno); |
| |
| int dummyvalue = 0xABCDABCD; |
| unsigned int hw_regno; |
| unsigned int read_buf; |
| |
| if( regno < ARC_NR_CORE_REGS ) |
| { |
| hw_regno = regno; |
| if(arc_jtag_ops.jtag_read_core_reg(regno,&read_buf)==JTAG_READ_FAILURE) |
| error("Failure reading from core register 0x%x\n",regno); |
| } |
| else |
| { |
| #ifndef ARC4_JTAG |
| if( regno > ARC_NR_REGS) |
| error("Invalid Register Number\n"); |
| #endif |
| |
| hw_regno = arc_get_hw_regnum_mapping (regno); |
| if(arc_jtag_ops.jtag_read_aux_reg(hw_regno,&read_buf)==JTAG_READ_FAILURE) |
| error("Failure reading auxillary register 0x%x",hw_regno); |
| } |
| |
| if(debug_arc_jtag_target_message) |
| { |
| printf_filtered("HW_Regno=0x%x",hw_regno); |
| printf_filtered("Read Regno 0x%x the value 0x%x\n",hw_regno,read_buf); |
| } |
| regcache_raw_supply(current_regcache,regno,&read_buf); |
| |
| LEAVEMSG; |
| } |
| |
| |
| /* Function: arc_debug_fetch_regs. |
| * Parameters : |
| * 1. int regnum: Register number. If register number is -1.Fetch |
| * all the registers.Read all core registers here. |
| * Returns : void |
| * Description: |
| * Use deprecated register information for this or regcache_read_unsigned . |
| * FIXME: would need to change to use regcache_raw_supply instead. |
| */ |
| |
| |
| void |
| arc_debug_store_regs (int regno) |
| { |
| /* write_all core registers */ |
| ENTERARGS("%d", regno); |
| unsigned int hw_regno; |
| unsigned int write_buf; |
| |
| if(debug_arc_jtag_target_message) |
| printf_filtered("\n%d",regno); |
| |
| regcache_raw_collect(current_regcache,regno,&write_buf); |
| if( regno < ARC_NR_CORE_REGS ) |
| { |
| if(arc_jtag_ops.jtag_write_core_reg(regno,write_buf)==JTAG_WRITE_FAILURE) |
| error("Failure writing 0x%x to core register 0x%x",write_buf,regno); |
| } |
| else |
| { |
| #ifndef ARC4_JTAG |
| if (regno > ARC_NR_REGS) |
| error ("Invalid register number \n"); |
| #endif |
| |
| hw_regno = arc_get_hw_regnum_mapping (regno); |
| |
| if(debug_arc_jtag_target_message) |
| printf_filtered("Writing to regno 0x%x the value 0x%x", |
| hw_regno,write_buf); |
| if(arc_jtag_ops.jtag_write_aux_reg(hw_regno,write_buf)==JTAG_WRITE_FAILURE) |
| error("Failure writing 0x%x to auxillary register 0x%x\n",write_buf,hw_regno); |
| } |
| |
| } |
| |
| |
| /* Function: arc_debug_prepare_to_store. |
| * Parameters : |
| * 1. int regnum: Register number. If register number is -1.Fetch |
| * all the registers.Read all core registers here. |
| * Returns : void |
| * Description: |
| * Use deprecated register information for this. |
| * FIXME: would need to change to use regcache_raw_supply instead. |
| */ |
| |
| /* This gets called just before store_regs */ |
| void |
| arc_debug_prepare_to_store (void) |
| { |
| /* does nothing . Why is this around ? */ |
| ENTERMSG; |
| } |
| |
| /* Read or write memory */ |
| |
| |
| |
| /* Function: arc_debug_xfer_memory. |
| * Parameters : |
| * 1. int regnum: Register number. If register number is -1.Fetch |
| * all the registers.Read all core registers here. |
| * Returns : void |
| * Description: |
| * This has been superceded by target_xfer_memory_partial. |
| * |
| */ |
| int |
| arc_debug_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write, |
| struct mem_attrib *attrib, struct target_ops *target) |
| { |
| /* There is no xfer_memory . Its been deprecated in 6.3 .Replace |
| * this by target_xfer_memory_partial . |
| */ |
| ENTERARGS("memaddr=%lx, myaddr=%lx, len=%d, write=%d", |
| memaddr, (unsigned long)myaddr, len, write); |
| |
| return len; /* success */ |
| } |
| |
| |
| |
| |
| LONGEST |
| arc_debug_xfer_partial (struct target_ops *ops, |
| enum target_object object, |
| const char *annex, |
| void *readbuf, |
| const void *writebuf, |
| ULONGEST offset, |
| LONGEST len) |
| { |
| |
| int i=0, read_num=0, temp_len=0; |
| unsigned int small_buf; |
| char query_type; |
| ULONGEST temp_offset=0; |
| if(debug_arc_jtag_target_message) |
| printf("..Entered arc_debug_xfer_partial()...with offset 0x%x\n",(unsigned int)offset); |
| /* Handle memory */ |
| if (object == TARGET_OBJECT_MEMORY) |
| { |
| int saved_status32; |
| int xfered=0; |
| int attempts; |
| errno = 0; |
| |
| /* Get out of user mode so that we can read/write anything anywhere. */ |
| saved_status32 = clear_status32_user_bit (); |
| |
| if (writebuf != NULL) |
| { |
| char *buffer=(char *)xmalloc(4); |
| char *temp_buf = (char *)writebuf; |
| |
| /* Address alignment to integral multiple of four */ |
| temp_offset = offset; |
| temp_len = temp_offset % 4; |
| |
| i = 0; |
| if(temp_len) |
| { |
| temp_offset = offset - temp_len; |
| if(debug_arc_jtag_target_message) |
| { |
| printf("---- Aligning-----------\n"); |
| printf("calling write_chunk at 0x%x where \ |
| offset = 0x%x\n", |
| (unsigned int)temp_offset,(unsigned int)offset); |
| } |
| |
| attempts = 0; |
| do{ |
| if (attempts++ == MEMORY_TRANSFER_ATTEMPTS) |
| return 0; |
| xfered = arc_jtag_ops.jtag_memory_chunk_read(temp_offset, |
| (unsigned int *)buffer,4); |
| }while(xfered != 4); |
| |
| for(i=0;i<len && i<(4-temp_len);i++) |
| |
| buffer[i+temp_len]=temp_buf[i]; |
| |
| attempts = 0; |
| do{ |
| if (attempts++ == MEMORY_TRANSFER_ATTEMPTS) |
| return 0; |
| xfered = arc_jtag_ops.jtag_memory_chunk_write(temp_offset, |
| (unsigned int *)buffer,4); |
| }while(xfered != 4); |
| |
| |
| temp_buf = (char *)writebuf + i; |
| temp_offset = offset + i; |
| len = len - i; |
| } |
| if(len>0) |
| len =arc_jtag_ops.jtag_memory_chunk_write(temp_offset, |
| (unsigned int *)temp_buf,len); |
| if(debug_arc_jtag_target_message) |
| printf("...leaving arc_debug_xfer_partial() write.. \ |
| with return value %d",(int)len); |
| |
| restore_status32_user_bit (saved_status32); |
| return (len + i); |
| } |
| else |
| { |
| char *buffer=(char *)xmalloc(4); |
| char *temp_buf = (char *)readbuf; |
| /* Address alignment to integral multiple of four */ |
| temp_offset= offset; |
| temp_len= temp_offset % 4 ; |
| |
| i = 0; |
| if(temp_len) |
| { |
| temp_offset = offset - temp_len; |
| if(debug_arc_jtag_target_message) |
| { |
| printf("---- Aligning-----------\n"); |
| printf("calling read_chunk at 0x%x where offset =0x%x \n", |
| (unsigned int)temp_offset,(unsigned int)offset); |
| } |
| |
| attempts = 0; |
| do{ |
| if (attempts++ == MEMORY_TRANSFER_ATTEMPTS) |
| return 0; |
| xfered = arc_jtag_ops.jtag_memory_chunk_read(temp_offset,(unsigned int *)buffer,4); |
| }while(xfered != 4); |
| |
| for(i=0;i<len && i<(4-temp_len);i++) |
| temp_buf[i]=buffer[i+temp_len]; |
| |
| temp_buf = (char *)readbuf + i; |
| temp_offset = offset + i; |
| len = len - i; |
| } |
| if(len>0) |
| len = arc_jtag_ops.jtag_memory_chunk_read(temp_offset,(unsigned int *)temp_buf,len); |
| if(debug_arc_jtag_target_message) |
| { |
| printf("\nlen=%d",(int)len + temp_len); |
| printf("...leaving arc_debug_xfer_partial() read.. \ |
| with return value %d", |
| (int)len + temp_len); |
| } |
| |
| restore_status32_user_bit (saved_status32); |
| return (len + i); |
| |
| } |
| |
| } |
| |
| /* ARC auxillary registers: they are 32bits wide and are in a 32 bit |
| address space, although only part of the address space is used. */ |
| else if (object == ARC_TARGET_OBJECT_AUXREGS) |
| { |
| unsigned int regno; |
| |
| if (readbuf) |
| { |
| for (regno = offset; regno < offset+len; ++regno) |
| { |
| unsigned int rd; |
| |
| if (arc_jtag_ops.jtag_read_aux_reg (regno, &rd) == JTAG_READ_FAILURE) |
| { |
| return (regno - offset); |
| } |
| ((int *)readbuf)[regno - offset] = rd; |
| } |
| } |
| else if (writebuf) |
| { |
| for (regno = offset; regno < offset+len; ++regno) |
| { |
| if (arc_jtag_ops.jtag_write_aux_reg (regno, ((int*)writebuf)[regno - offset]) == |
| JTAG_WRITE_FAILURE) |
| { |
| return (regno - offset); |
| } |
| } |
| } |
| |
| /* success */ |
| return (LONGEST)len; |
| } |
| else |
| { |
| printf("\nRequested target_object not yet supported with arc-jtag"); |
| } |
| |
| return -1; |
| |
| } |
| |
| |
| |
| |
| void |
| arc_debug_files_info (struct target_ops *target) |
| { |
| /* Do nothing. Just say its a remote target */ |
| ENTERMSG; |
| } |
| |
| |
| /* Function: arc_debug_insert_breakpoint |
| * Parameters : |
| * 1. CORE_ADDR addr: Address for breakpoint. |
| * 2. char * contents: Contents for the breakpoint. |
| * Returns : int |
| * Description: |
| * See if you can insert a hardware breakpoint using the actionpoints |
| * interface. Use brk_s if architecture is ARC700 and you need to use |
| * a software breakpoint.The gdbarch breakpoint should be initialized to |
| * the right value if used with target_arc_debug. |
| * |
| */ |
| |
| |
| int |
| arc_debug_insert_breakpoint (CORE_ADDR addr, char *contents) |
| { |
| |
| ENTERARGS("%x", (unsigned int)addr); |
| #ifndef ARC4_JTAG |
| unsigned int bp = 0x20207fff; /*FIXMEA: what does 0x2020 stand for ?*/ |
| #else |
| unsigned int bp = 0x1ffffe00; |
| #endif |
| unsigned int r; |
| int instr_size; |
| const unsigned char *breakpt_instr; |
| breakpt_instr=BREAKPOINT_FROM_PC(&addr,&instr_size); |
| |
| /* save the existing value */ |
| /* r==0 means the read succeeded */ |
| if(debug_arc_jtag_target_message) |
| printf_filtered ("instrcution size = %d and instruction 0x%x", |
| instr_size, *(unsigned int *)breakpt_instr); |
| r = target_read_memory (addr, contents, instr_size); |
| /* put the breakpoint */ |
| if(r==0) |
| r = target_write_memory (addr, (char *)&bp, instr_size); |
| return r; |
| } |
| |
| |
| /* Function: arc_debug_remove_breakpoint. |
| * Parameters : |
| * 1. CORE_ADDR addr: Address. |
| * 2. char * contents : contents. |
| * Returns : int. |
| * Description: |
| * Write the old contents back for the breakpoint. |
| * |
| */ |
| |
| int |
| arc_debug_remove_breakpoint (CORE_ADDR addr, char *contents) |
| { |
| ENTERARGS("%x, %lx", (unsigned int)addr, *(unsigned long *)contents); |
| |
| /* write the old value back */ |
| #ifdef ARC4_JTAG |
| return target_write_memory (addr, contents, 4); |
| #else |
| return target_write_memory (addr, contents, 2); |
| #endif |
| } |
| |
| |
| |
| /* Function: arc_debug_kill |
| * Parameters : void. |
| |
| * Returns : void. |
| * Description: Heavy duty arsenal.Kill the process. |
| * Maybe we do a board reset and kill it. Write 1 to Halt |
| * in Status32. |
| */ |
| |
| void |
| arc_debug_kill (void) |
| { |
| ENTERMSG; |
| |
| /* Do stuff */ |
| |
| target_mourn_inferior (); |
| } |
| |
| /* Function: arc_debug_load |
| * Parameters : |
| * 1. char * args: Arguments. |
| * 2. int from_tty: Which terminal. |
| * Returns : void. |
| * Description: Load the program into jtag. |
| */ |
| |
| void |
| arc_debug_load (char *args, int from_tty) |
| { |
| /* Write to RAM of the ARC700 board by running through the sections .*/ |
| asection *bss_section; |
| CORE_ADDR bss_addr; |
| bfd_size_type bss_size; |
| char *zero_buf; |
| int target_errno; |
| |
| ENTERARGS("%s", args); |
| |
| generic_load(args, from_tty); |
| |
| /* Zero the bss, if it exists. */ |
| bss_section = bfd_get_section_by_name (exec_bfd, ".bss"); |
| if (bss_section) |
| { |
| bss_addr = bfd_section_lma (exec_bfd, bss_section); |
| bss_size = bfd_get_section_size (bss_section); |
| zero_buf = (char *)xcalloc (bss_size, 1); |
| |
| if (debug_arc_jtag_target_message) |
| printf_filtered("%s: bss at %x, size = %x\n", __FUNCTION__, (unsigned int)bss_addr,(unsigned int)bss_size); |
| |
| target_errno = target_write_memory (bss_addr, zero_buf, bss_size); |
| free (zero_buf); |
| if (target_errno) |
| { |
| error ("load: error zeroing bss: %s\n", strerror(target_errno)); |
| } |
| } |
| else |
| { |
| if (debug_arc_jtag_target_message) |
| printf_filtered("%s: no bss\n", __FUNCTION__); |
| } |
| |
| clear_symtab_users(); |
| } |
| |
| /* Function: arc_debug_create_inferior |
| * Parameters : |
| * 1. char * exec_file: |
| * 2. char * args: |
| * 3. char ** env; |
| * Returns : void. |
| * Description: Set up sanity values for arc_debug_create_inferior. More thought |
| * needed for this. |
| */ |
| |
| |
| void |
| arc_debug_create_inferior (char *exec_file, char *args, char **env,int dummy) |
| { |
| ENTERARGS("%s,%s", exec_file, args); |
| |
| /* If no exec file handed to us, get it from the exec-file command |
| -- with a good, common error message if none is specified. */ |
| if (exec_file == 0) |
| exec_file = get_exec_file (1); |
| |
| /* We dont really have a PID or anything, but GDB uses this value to check |
| if the program is running. */ |
| inferior_ptid.pid = 42; |
| |
| clear_proceed_status(); |
| /* -1 means resume from current place |
| TARGET_SIGNAL_0 means dont give it any signal |
| Last arg should be true if you want to single step */ |
| //proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0); |
| proceed (bfd_get_start_address (exec_bfd), TARGET_SIGNAL_0, 0); |
| } |
| |
| |
| /* Function: arc_debug_mourn_inferior |
| * Parameters :void. |
| * Returns : void. |
| * Description: Set up sanity values for arc_debug_create_inferior. More thought |
| * needed for this. |
| */ |
| |
| void |
| arc_debug_mourn_inferior (void) |
| { |
| ENTERMSG; |
| |
| unpush_target (&arc_debug_ops); |
| |
| generic_mourn_inferior (); |
| } |
| |
| |
| /* Function: arc_debug_mourn_inferior |
| * Parameters :ptid_t ptid. |
| * Returns : 1 always. |
| * Description: Checks for return values . |
| */ |
| |
| |
| int |
| arc_debug_thread_alive (ptid_t ptid) |
| { |
| ENTERMSG; |
| return 1; |
| } |
| |
| |
| /* Function: arc_debug_stop |
| * Parameters: void |
| * Returns: void. |
| * Description: Stop the Processor. We stop by writing FH bit to Debug Register . |
| * write 1 to the FH bit in the Debug register after |
| * polling for the DEBUG register to have no loads pending . |
| */ |
| void |
| arc_debug_stop (void) |
| { |
| |
| ENTERMSG; |
| int val = 0x2; |
| /* Stop using the FH bit in the debug register. */ |
| arc_debug_write_aux_register (ARC_HW_DEBUG_REGNUM, &val); |
| |
| } |
| |
| /* Read core register. Return 0 on success. */ |
| static int |
| arc_debug_read_core_register (int hwregno, int *buf) |
| { |
| int rd; |
| if(arc_jtag_ops.jtag_read_core_reg(hwregno,&rd)==JTAG_READ_FAILURE) |
| error("Failure reading auxillary register 0x%x",hwregno); |
| *buf = rd; |
| return 0; |
| } |
| |
| /* Read aux register. Return 0 on success. */ |
| static int |
| arc_debug_read_aux_register (int hwregno, int *buf) |
| { |
| int rd; |
| if(arc_jtag_ops.jtag_read_aux_reg(hwregno,&rd)==JTAG_READ_FAILURE) |
| error("Failure reading auxillary register 0x%x",hwregno); |
| *buf = rd; |
| return 0; |
| } |
| |
| /* Write aux register. Return 0 on success. */ |
| static int |
| arc_debug_write_aux_register (int hwregno, int *buf) |
| { |
| if(arc_jtag_ops.jtag_write_aux_reg(hwregno, *buf)==JTAG_WRITE_FAILURE) |
| error("Failure writing 0x%x to auxillary register 0x%x\n",*buf,hwregno); |
| return 0; |
| } |
| |
| /* Helper routine for commands added. */ |
| /* Print Processor Variant Info. */ |
| static void |
| arc_print_processor_variant_info (void) |
| { |
| struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); |
| |
| #ifdef ARC4_JTAG |
| if (tdep->arc_processor_variant_info && |
| tdep->arc_processor_variant_info->arcprocessorversion == A4) |
| { |
| printf_filtered ("A4\n"); |
| } |
| #else |
| if (tdep->arc_processor_variant_info) |
| { |
| if(tdep->arc_processor_variant_info->arcprocessorversion == ARC700) |
| printf_filtered ("ARC700\n"); |
| else |
| printf_filtered ("ARC600\n"); |
| } |
| #endif |
| else |
| { |
| printf_filtered ("ARC Processor Information not available \n"); |
| } |
| |
| } |
| |
| |
| static void |
| arc_print_bcr_regs (void) |
| { |
| int i = 0; |
| unsigned int bcrval = 0; |
| for ( i = 0 ; i < (sizeof(arc_bcr_reg_info) / sizeof (struct arc_reg_info)) ; i++) |
| { |
| if(arc_jtag_ops.jtag_read_aux_reg (arc_bcr_reg_info[i].hw_regno, &bcrval)==JTAG_READ_FAILURE) |
| error("Failure reading auxillary register 0x%x",arc_bcr_reg_info[i].hw_regno); |
| printf_filtered ("[%02x] %-15s : 0x%02x\n",arc_bcr_reg_info[i].hw_regno, |
| arc_bcr_reg_info[i].name, bcrval ); |
| } |
| |
| } |
| |
| static void |
| arc_debug_jtag_reset_board (void) |
| { |
| arc_jtag_ops.jtag_reset_board(); |
| } |
| |
| |
| /* Function: init_arc_debug_ops |
| * Parameters: void |
| * Returns: void. |
| * Description: Initialize the jtag operations. |
| */ |
| |
| void |
| init_arc_debug_ops (void) |
| { |
| ENTERMSG; |
| #ifdef ARC4_JTAG |
| arc_debug_ops.to_shortname = "arcjtag"; |
| arc_debug_ops.to_longname = "Target for debugging an A4 board with JTAG."; |
| arc_debug_ops.to_doc = "Debug a remote A4 board via a JTAG"; /* to_doc */ |
| #else |
| arc_debug_ops.to_shortname = "arcjtag"; |
| arc_debug_ops.to_longname = "Target for debugging an ARC700 board with JTAG."; |
| arc_debug_ops.to_doc = "Debug a remote ARC700 board via a JTAG"; /* to_doc */ |
| #endif |
| |
| |
| arc_debug_ops.to_open = arc_debug_open; |
| arc_debug_ops.to_close = arc_debug_close; |
| arc_debug_ops.to_attach = arc_debug_attach; |
| arc_debug_ops.to_detach = arc_debug_detach; |
| arc_debug_ops.to_resume = arc_debug_resume; |
| arc_debug_ops.to_wait = arc_debug_wait; |
| |
| arc_debug_ops.to_fetch_registers = arc_debug_fetch_regs; |
| arc_debug_ops.to_store_registers = arc_debug_store_regs; |
| arc_debug_ops.to_prepare_to_store = arc_debug_prepare_to_store; |
| //arc_debug_ops.to_xfer_memory = arc_debug_xfer_memory; |
| arc_debug_ops.to_xfer_partial = arc_debug_xfer_partial; |
| arc_debug_ops.to_files_info = arc_debug_files_info; |
| arc_debug_ops.to_insert_breakpoint = arc_debug_insert_breakpoint; |
| arc_debug_ops.to_remove_breakpoint = arc_debug_remove_breakpoint; |
| arc_debug_ops.to_kill = arc_debug_kill; |
| arc_debug_ops.to_load = arc_debug_load; |
| |
| arc_debug_ops.to_create_inferior = arc_debug_create_inferior; |
| |
| arc_debug_ops.to_mourn_inferior = arc_debug_mourn_inferior; |
| arc_debug_ops.to_thread_alive = arc_debug_thread_alive; |
| arc_debug_ops.to_stop = arc_debug_stop; |
| |
| arc_debug_ops.to_terminal_inferior = NULL; |
| |
| |
| arc_debug_ops.to_stratum = process_stratum; |
| |
| arc_debug_ops.to_has_all_memory = 1; |
| arc_debug_ops.to_has_memory = 1; |
| arc_debug_ops.to_has_stack = 1; |
| arc_debug_ops.to_has_registers = 1; |
| arc_debug_ops.to_has_execution = 1; |
| |
| arc_debug_ops.to_magic = OPS_MAGIC; |
| } |
| |
| |
| |
| void |
| _initialize_arc_debug (void) |
| { |
| ENTERMSG; |
| init_arc_debug_ops (); |
| add_target (&arc_debug_ops); |
| add_setshow_boolean_cmd("arcjtag-debug-target",no_class, |
| &debug_arc_jtag_target_message, |
| "Set whether to print arc jtag debug messages.\n", |
| "Show whether to print arc jtag debug messages.\n", |
| "If set the jtag debug messages from the target are \ |
| printed.\n", |
| "Whether to print debug jtag messages is %s.\n", |
| NULL,NULL,&setlist,&showlist); |
| |
| add_setshow_boolean_cmd("arcjtag-debug-statemachine",no_class, |
| &(arc_jtag_ops.arc_jtag_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", |
| "Whether to print JTAG state machine debug \ |
| messages is %s\n", |
| NULL,NULL,&setlist,&showlist); |
| |
| add_setshow_uinteger_cmd("arcjtag-retry-count",no_class, &arcjtag_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", |
| "The number of times a JTAG operation is attempted \ |
| before returning a failure is %s.\n", |
| NULL, NULL, &setlist, &showlist); |
| |
| add_cmd ("arc-configuration", class_info, arc_print_processor_variant_info, |
| "Show ARC configuration information." , &infolist); |
| |
| add_cmd ("arc-bcr-registers", class_info, arc_print_bcr_regs, |
| "Show BCR Registers in the ARC Processor Variant", &infolist); |
| |
| add_cmd ("arc-reset-board", class_obscure, arc_debug_jtag_reset_board, |
| "Reset the board.", &cmdlist); |
| |
| } |