| /* Target dependent code for ARC processor family, for GDB, the GNU debugger. |
| |
| Copyright 2005, 2008, 2009 Free Software Foundation, Inc. |
| |
| Contributed by ARC International (www.arc.com) |
| |
| Author: |
| Sameer Dhavale <sameer.dhavale@codito.com> |
| Soam Vasani <soam.vasani@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 implements debug access to an ARC processor via its JTAG */ |
| /* interface. */ |
| /* */ |
| /* See */ |
| /* ARCompact Instruction Set Architecture */ |
| /* Programmer's Reference (5115-018) */ |
| /* */ |
| /* for a description of ARC processor architecture (in particular */ |
| /* the auxiliary registers and the halting procedure); */ |
| /* */ |
| /* ARC 700 External Interfaces */ |
| /* Reference (5117-013) */ |
| /* */ |
| /* for a description of the JTAG interface (in particular the Test */ |
| /* Access Port Controller (TAPC) state machine). */ |
| /* */ |
| /* The JTAG interface is accessed by three parallel ports: control, data */ |
| /* and status. Data is read from or written to these ports one byte at a */ |
| /* at a time, using a GPIO (General Purpose Input/Output) driver. */ |
| /* */ |
| /* The TDI and TMS signals are written to the data port. */ |
| /* The TCK signal is written to the control port. */ |
| /* The TDO signal is read from the status port. */ |
| /* */ |
| /* Host/Target Byte Order: */ |
| /* The core and auxiliary register contents read from or written to the */ |
| /* JTAG interface are ALWAYS in little-endian format, regardless of the */ |
| /* endianness of the target processor. */ |
| /* */ |
| /******************************************************************************/ |
| |
| /* system header files */ |
| #include <stdio.h> |
| #include <string.h> |
| #include <errno.h> |
| #include <unistd.h> |
| #include <byteswap.h> |
| |
| /* gdb header files */ |
| #include "defs.h" |
| #include "gdb_assert.h" |
| |
| /* ARC header files */ |
| #include "arc-gpio.h" |
| #include "arc-jtag.h" |
| #include "arc-jtag-ops.h" |
| #include "arc-support.h" |
| |
| |
| /* -------------------------------------------------------------------------- */ |
| /* conditional compilation flags */ |
| /* -------------------------------------------------------------------------- */ |
| |
| /* We would really like to optimise the use of the JTAG Data Register by |
| loading a word into it only if that word differs from the last word loaded; |
| but there seems to be undocumented behaviour of the JTAG mechanism in that |
| the Data Register is altered after a write operation! See ARC Bug #93814. */ |
| #define JTAG_DATA_REGISTER_IS_CORRUPTED_BY_WRITE |
| |
| /* Define this if you wish to check the whether the contents of the JTAG Data |
| Register are corrupted by write operations. */ |
| //#define CHECK_JTAG_DATA_REGISTER |
| |
| /* Define this if you wish to perform low-level debugging of the JTAG state |
| machine emulated in this module (this should not be necessary). */ |
| //#define STATE_MACHINE_DEBUG |
| |
| |
| /* -------------------------------------------------------------------------- */ |
| /* local types */ |
| /* -------------------------------------------------------------------------- */ |
| |
| /* Sizes of quantities. */ |
| #define BITS_IN_COMMAND_CODE 4 |
| #define BITS_IN_REGISTER_CODE 4 |
| |
| |
| typedef unsigned int Bit; /* Only LSB of word is used. */ |
| typedef unsigned int JTAG_RegisterContents; |
| |
| |
| typedef enum |
| { |
| MSB_FIRST, |
| MSB_LAST |
| } Order; |
| |
| |
| typedef enum |
| { |
| Memory, |
| Register |
| } JTAG_TransactionType; |
| |
| |
| typedef enum |
| { |
| STALLED, |
| FAILURE, |
| READY, |
| NOT_READY |
| } JTAG_TransactionStatus; |
| |
| |
| /* Only these JTAG registers are currently used. */ |
| typedef enum |
| { |
| JTAG_STATUS_REGISTER = 0x8, |
| JTAG_TRANSACTION_COMMAND_REGISTER = 0x9, |
| JTAG_ADDRESS_REGISTER = 0xA, |
| JTAG_DATA_REGISTER = 0xB, |
| } JTAG_Register; |
| |
| |
| #ifdef STATE_MACHINE_DEBUG |
| typedef enum |
| { |
| UNDEFINED, |
| TEST_LOGIC_RESET, |
| RUN_TEST_IDLE, |
| SELECT_DR_SCAN, |
| CAPTURE_DR, |
| SHIFT_DR, |
| EXIT1_DR, |
| PAUSE_DR, |
| EXIT2_DR, |
| UPDATE_DR, |
| SELECT_IR_SCAN, |
| CAPTURE_IR, |
| SHIFT_IR, |
| EXIT1_IR, |
| PAUSE_IR, |
| EXIT2_IR, |
| UPDATE_IR, |
| NUMBER_OF_STATES /* An end-marker, not a state. */ |
| } JTAG_ControllerState; |
| #endif |
| |
| |
| /* -------------------------------------------------------------------------- */ |
| /* local data */ |
| /* -------------------------------------------------------------------------- */ |
| |
| /* -------------------------------------- */ |
| /* For ARC JTAG Cable */ |
| /* */ |
| /* Pin no. Signal Port Bit */ |
| /* */ |
| /* - TRST */ |
| /* 8 TMS Data 6 */ |
| /* 1 TCK Control 0 */ |
| /* 9 TDI Data 7 */ |
| /* 13 TDO Status 4 */ |
| /* -------------------------------------- */ |
| |
| /* Bit masks for signals written to parallel ports. */ |
| |
| #define JTAG_TRST 0 /* not there */ |
| #define JTAG_TMS (1 << 6) /* on Data port */ |
| #define JTAG_TCK (1 << 0) /* on Control port (driven low) */ |
| #define JTAG_TDI (1 << 7) /* on Data port */ |
| #define JTAG_TDO (1 << 4) /* on Status port */ |
| |
| |
| /* Commands which can be written to the JTAG Transaction Command Register. */ |
| #define WRITE_MEMORY_LOCATION 0x0 |
| #define WRITE_CORE_REGISTER 0x1 |
| #define WRITE_AUX_REGISTER 0x2 |
| #define NOP 0x3 |
| #define READ_MEMORY_LOCATION 0x4 |
| #define READ_CORE_REGISTER 0x5 |
| #define READ_AUX_REGISTER 0x6 |
| |
| |
| /* Gives the endianness of the target processor. */ |
| static Boolean target_is_big_endian; |
| |
| /* These accumulate the bit masks to be written to the data and control ports. */ |
| static Byte data_port_value, control_port_value; |
| |
| /* Variables for tracking the contents of the JTAG Address and Transaction |
| Command registers. */ |
| static JTAG_RegisterContents address_register_contents; |
| static JTAG_RegisterContents command_register_contents; |
| static Boolean address_register_contents_known; |
| static Boolean command_register_contents_known; |
| |
| |
| #ifdef STATE_MACHINE_DEBUG |
| /* This table encodes all possible transitions of the JTAG Test Access Port |
| (TAP) Controller State Machine: for each state, the transition to one of two |
| possible next states is determined by whether a 0 bit or a 1 bit is written |
| as the JTAG TMS interface signal. */ |
| static const JTAG_ControllerState transitions[NUMBER_OF_STATES][2] = |
| { |
| /* 0 1 */ |
| /* UNDEFINED */ { UNDEFINED, UNDEFINED }, |
| /* TEST_LOGIC_RESET */ { RUN_TEST_IDLE, TEST_LOGIC_RESET }, |
| /* RUN_TEST_IDLE */ { RUN_TEST_IDLE, SELECT_DR_SCAN }, |
| /* SELECT_DR_SCAN */ { CAPTURE_DR, SELECT_IR_SCAN }, |
| /* CAPTURE_DR */ { SHIFT_DR, EXIT1_DR }, |
| /* SHIFT_DR */ { SHIFT_DR, EXIT1_DR }, |
| /* EXIT1_DR */ { PAUSE_DR, UPDATE_DR }, |
| /* PAUSE_DR */ { PAUSE_DR, EXIT2_DR }, |
| /* EXIT2_DR */ { SHIFT_DR, UPDATE_DR }, |
| /* UPDATE_DR */ { RUN_TEST_IDLE, SELECT_DR_SCAN }, |
| /* SELECT_IR_SCAN */ { CAPTURE_IR, TEST_LOGIC_RESET }, |
| /* CAPTURE_IR */ { SHIFT_IR, EXIT1_IR }, |
| /* SHIFT_IR */ { SHIFT_IR, EXIT1_IR }, |
| /* EXIT1_IR */ { PAUSE_IR, UPDATE_IR }, |
| /* PAUSE_IR */ { PAUSE_IR, EXIT2_IR }, |
| /* EXIT2_IR */ { SHIFT_IR, UPDATE_IR }, |
| /* UPDATE_IR */ { RUN_TEST_IDLE, SELECT_DR_SCAN }, |
| }; |
| |
| /* The current state of the TAP Controller State Machine. */ |
| static JTAG_ControllerState current_state = UNDEFINED; |
| #endif |
| |
| |
| /* -------------------------------------------------------------------------- */ |
| /* externally visible data */ |
| /* -------------------------------------------------------------------------- */ |
| |
| /* This structure holds the operations and data exported by this module. */ |
| JTAG_Operations arc_jtag_ops; |
| |
| |
| /* -------------------------------------------------------------------------- */ |
| /* local macros */ |
| /* -------------------------------------------------------------------------- */ |
| |
| #ifdef DEBUG |
| #undef DEBUG |
| #endif |
| |
| #define DEBUG(...) \ |
| if (arc_jtag_ops.state_machine_debug) fprintf_unfiltered(gdb_stdlog, __VA_ARGS__) |
| |
| |
| #ifdef STATE_MACHINE_DEBUG |
| #define SET_STATE(s) set_state(s) |
| #define NEXT_STATE(b) next_state(b) |
| #define CHANGE_STATE(x, s) change_state(x, s) |
| #define STATE_IS(s) gdb_assert(current_state == s) |
| #define STATE_IS_EITHER(s1, s2) gdb_assert(current_state == s1 || \ |
| current_state == s2) |
| #define STATE_IS_ONE_OF(s1, s2, s3) gdb_assert(current_state == s1 || \ |
| current_state == s2 || \ |
| current_state == s3) |
| #else |
| #define SET_STATE(s) |
| #define NEXT_STATE(b) |
| #define CHANGE_STATE(x, s) tapc_TMS(x) |
| #define STATE_IS(s) |
| #define STATE_IS_EITHER(s1, s2) |
| #define STATE_IS_ONE_OF(s1, s2, s3) |
| #endif |
| |
| |
| #define IS_WORD_ALIGNED(addr) ((addr) % BYTES_IN_WORD == 0) |
| #define BYTE(val) (Byte) ((val) & 0xFF) |
| |
| /* This is more efficient than memcpy(to, from, BYTES_IN_WORD). */ |
| #define COPY_WORD(to, from) { ((Byte*) to)[0] = ((Byte*) from)[0]; \ |
| ((Byte*) to)[1] = ((Byte*) from)[1]; \ |
| ((Byte*) to)[2] = ((Byte*) from)[2]; \ |
| ((Byte*) to)[3] = ((Byte*) from)[3]; } |
| |
| |
| /* -------------------------------------------------------------------------- */ |
| /* forward declarations */ |
| /* -------------------------------------------------------------------------- */ |
| |
| static void tapc_TMS (Bit x); |
| static void set_interface (JTAG_Status status); |
| static void interface_is_closed (void); |
| static JTAG_RegisterContents read_jtag_reg (JTAG_Register regnum, |
| unsigned int num_data_bits); |
| |
| |
| /* -------------------------------------------------------------------------- */ |
| /* local functions */ |
| /* -------------------------------------------------------------------------- */ |
| |
| /* -------------------------------------------------------------------------- */ |
| /* 1) debug functions */ |
| /* -------------------------------------------------------------------------- */ |
| |
| /* Debug function. */ |
| |
| static const char* |
| JTAG_register_name (JTAG_Register r) |
| { |
| switch (r) |
| { |
| case JTAG_STATUS_REGISTER : return "Status"; |
| case JTAG_TRANSACTION_COMMAND_REGISTER : return "Transaction Command"; |
| case JTAG_ADDRESS_REGISTER : return "Address"; |
| case JTAG_DATA_REGISTER : return "Data"; |
| default: internal_error(__FILE__, __LINE__, _("invalid JTAG register %d"), r); |
| } |
| } |
| |
| |
| /* Debug function. */ |
| |
| static const char* |
| JTAG_TransactionStatus_Image (JTAG_TransactionStatus value) |
| { |
| switch (value) |
| { |
| case STALLED : return "STALLED"; |
| case FAILURE : return "FAILURE"; |
| case READY : return "READY"; |
| case NOT_READY: return "NOT READY"; |
| default: internal_error(__FILE__, __LINE__, _("invalid JTAG transaction status %d"), value); |
| } |
| } |
| |
| |
| #ifdef STATE_MACHINE_DEBUG |
| /* Debug function. */ |
| |
| static const char* |
| JTAG_ControllerState_Image (JTAG_ControllerState state) |
| { |
| switch (state) |
| { |
| case UNDEFINED : return "<undefined> "; |
| case TEST_LOGIC_RESET: return "Test-Logic-Reset"; |
| case RUN_TEST_IDLE : return "Run-Test/Idle "; |
| case SELECT_DR_SCAN : return "Select-DR-Scan "; |
| case CAPTURE_DR : return "Capture-DR "; |
| case SHIFT_DR : return "Shift-DR "; |
| case EXIT1_DR : return "Exit1-DR "; |
| case PAUSE_DR : return "Pause-DR "; |
| case EXIT2_DR : return "Exit2-DR "; |
| case UPDATE_DR : return "Update-DR "; |
| case SELECT_IR_SCAN : return "Select-IR-Scan "; |
| case CAPTURE_IR : return "Capture-IR "; |
| case SHIFT_IR : return "Shift-IR "; |
| case EXIT1_IR : return "Exit1-IR "; |
| case PAUSE_IR : return "Pause-IR "; |
| case EXIT2_IR : return "Exit2-IR "; |
| case UPDATE_IR : return "Update-IR "; |
| default : return "<invalid> "; |
| } |
| } |
| #endif |
| |
| |
| #ifdef CHECK_JTAG_DATA_REGISTER |
| /* Read back the contents of the JTAG Data Register, and check that the value |
| is what is expected, i.e. the last value that was written to that register. */ |
| |
| static void |
| check_Data_Register (ARC_Word expected) |
| { |
| /* Read the data from the JTAG Data Register. */ |
| ARC_Word actual = (ARC_Word) read_jtag_reg(JTAG_DATA_REGISTER, BITS_IN_WORD); |
| |
| /* Is the data still in the register? */ |
| if (actual != expected) |
| warning(_("JTAG Data Register: expected = %08X, actual = %08X\n"), expected, actual); |
| else |
| printf_unfiltered(_("word %08X is still in JTAG Data Register\n"), expected); |
| } |
| #endif |
| |
| |
| /* -------------------------------------------------------------------------- */ |
| /* 2) helper functions for setting TMS / TCK / TDI */ |
| /* -------------------------------------------------------------------------- */ |
| |
| /* These functions set the accumulated values to be written out to the ports. |
| The final values are written only by doing the pulse, e.g. if TDI and TMS |
| are set/unset by subsequent calls, the last GPIO write operation performed |
| by those calls before the pulse writes the accumulated bit mask value to |
| the port (overwriting the values written by the preceding calls), and it |
| is this bit mask that is significant when the JTAG is clocked. */ |
| |
| static void |
| tapc_set_TMS (Bit x) |
| { |
| Byte current_value = data_port_value; |
| |
| if (x) |
| data_port_value |= JTAG_TMS; |
| else |
| data_port_value &= ~JTAG_TMS; |
| |
| if (data_port_value != current_value) |
| gpio_write(DATA_PORT, data_port_value); |
| } |
| |
| |
| static void |
| tapc_set_TDI (Bit x) |
| { |
| Byte current_value = data_port_value; |
| |
| if (x) |
| data_port_value |= JTAG_TDI; |
| else |
| data_port_value &= ~JTAG_TDI; |
| |
| if (data_port_value != current_value) |
| gpio_write(DATA_PORT, data_port_value); |
| } |
| |
| |
| static void |
| tapc_set_TCK (Bit x) |
| { |
| /* The clock is active low. */ |
| if (x) |
| control_port_value &= ~JTAG_TCK; |
| else |
| control_port_value |= JTAG_TCK; |
| |
| gpio_write(CONTROL_PORT, control_port_value); |
| } |
| |
| |
| /* -------------------------------------------------------------------------- */ |
| /* 3) JTAG state machine handlers */ |
| /* -------------------------------------------------------------------------- */ |
| |
| #ifdef STATE_MACHINE_DEBUG |
| /* Debug function. Perform a state change to the given state. */ |
| |
| static void |
| set_state (JTAG_ControllerState new_state) |
| { |
| DEBUG("TAPC state: %s ====> %s\n", |
| JTAG_ControllerState_Image(current_state), |
| JTAG_ControllerState_Image(new_state)); |
| |
| current_state = new_state; |
| |
| gdb_assert(current_state != UNDEFINED); |
| } |
| |
| |
| /* Debug function. Perform a state change from the current state according to |
| the transition specified by the given bit. */ |
| |
| static void |
| next_state (Bit x) |
| { |
| current_state = (transitions[current_state][x]); |
| } |
| |
| |
| /* Debug function. Perform a state change from the current state according to |
| the transition specified by the given bit, and check that the new state is |
| as expected. */ |
| |
| static void |
| change_state (Bit x, JTAG_ControllerState new_state) |
| { |
| tapc_TMS(x); |
| |
| gdb_assert(current_state == new_state); |
| } |
| #endif /* STATE_MACHINE_DEBUG */ |
| |
| |
| /* Clock the JTAG on the ARC platform. */ |
| |
| static void |
| tapc_pulse (void) |
| { |
| /* TCK control bit is active low. */ |
| gdb_assert((control_port_value & JTAG_TCK) != (Byte) 0); /* Clock should be zero on entry. */ |
| |
| gpio_write(CONTROL_PORT, control_port_value & ~JTAG_TCK); |
| gpio_write(CONTROL_PORT, control_port_value); |
| } |
| |
| |
| /* Reset the TAP Controller on the JTAG. */ |
| |
| static void |
| tapc_reset (void) |
| { |
| ENTERMSG; |
| |
| /* The Test Clock signal is active low (i.e. the signal is active when the |
| corresponding bit written to the control bit is 0; so initialize the bit |
| in the control port value to 1 so that the signal is initially not active. */ |
| control_port_value = (Byte) JTAG_TCK; |
| data_port_value = (Byte) 0; |
| |
| /* From any state, this many TCK pulses should get the controller into state |
| Test-Logic-Reset. */ |
| tapc_set_TMS(1); |
| tapc_set_TCK(0); /* We want the rising edge. */ |
| tapc_pulse(); |
| tapc_pulse(); |
| tapc_pulse(); |
| tapc_pulse(); |
| tapc_pulse(); |
| tapc_pulse(); |
| |
| SET_STATE(TEST_LOGIC_RESET); |
| |
| DEBUG("TAPC has been reset\n"); |
| |
| /* The reset has re-initialized all the JTAG registers. */ |
| address_register_contents_known = FALSE; |
| command_register_contents_known = FALSE; |
| |
| CHANGE_STATE(0, RUN_TEST_IDLE); |
| |
| LEAVEMSG; |
| } |
| |
| |
| /* Set the TMS to the value of the bit and clock the JTAG. |
| This will cause the TAP Controller State Machine to move to another state. */ |
| |
| static void |
| tapc_TMS (Bit x) |
| { |
| tapc_set_TMS(x); |
| tapc_pulse(); |
| NEXT_STATE(x); |
| } |
| |
| |
| /* Read a bit from the TDO of the JTAG. */ |
| |
| static Bit |
| tapc_readTDO (void) |
| { |
| Byte byte = gpio_read(STATUS_PORT); |
| |
| /* Read from the status port. */ |
| return ((byte & JTAG_TDO) != (Byte) 0) ? (Bit) 1 : (Bit) 0; |
| } |
| |
| |
| /* -------------------------------------------------------------------------- */ |
| /* 4) interface functions that use the JTAG state machine handler functions */ |
| /* -------------------------------------------------------------------------- */ |
| |
| /* Shift one bit out on the JTAG TDO and one bit in on the JTAG TDI. */ |
| |
| static Bit |
| tapc_shift_bit (Bit out) |
| { |
| Bit in = tapc_readTDO(); |
| |
| tapc_set_TDI(out); |
| tapc_pulse(); |
| |
| // DEBUG("%u (out) >>> %u (in)\n", out, in); |
| |
| return in; |
| } |
| |
| |
| /* Shift N bits from to_write into TDI, and out from TDO into to_read. |
| |
| If order == MSB_LAST, shift LSB first, starting from to_write[0], to_write[1], |
| etc. |
| |
| If order == MSB_FIRST, shift to_write[N-1] MSB first, then to_write[N-2] etc. |
| |
| Must be called in Shift DR/IR state. |
| Leaves in Exit1-DR/IR state. */ |
| |
| static void |
| tapc_shift_N_bits (unsigned int n, |
| Byte *to_write, |
| Byte *to_read, |
| Order order) |
| { |
| unsigned int nbytes = (n - 1) / BITS_IN_BYTE + 1; |
| unsigned int nbits = BITS_IN_BYTE; |
| unsigned int i, j; |
| |
| ENTERARGS("shift %u bits", n); |
| |
| STATE_IS_EITHER(SHIFT_DR, SHIFT_IR); |
| |
| for (i = 0; i < nbytes; i++) |
| { |
| Boolean is_last_byte = (i == nbytes - 1); |
| Byte inbyte = (Byte) 0; |
| Byte outbyte; |
| |
| if (order == MSB_FIRST) |
| outbyte = to_write[nbytes - 1 - i]; |
| else |
| outbyte = to_write[i]; |
| |
| if (is_last_byte) |
| { |
| /* How many significant bits are in this byte? */ |
| nbits = ((n - 1) % BITS_IN_BYTE) + 1; |
| } |
| |
| /* gdb_assert (nbits <= BITS_IN_BYTE); */ |
| |
| for (j = 0; j < nbits; j++) |
| { |
| Bit outbit, inbit; |
| |
| // DEBUG("byte %u, bit %u\n", i, j); |
| |
| /* Get the next bit to be output from the current byte. */ |
| if (order == MSB_FIRST) |
| { |
| /* Get MSB from byte. */ |
| outbit = (Bit) ((outbyte >> BITS_IN_BYTE) & 1); |
| outbyte <<= 1; |
| } |
| else |
| { |
| /* Get LSB from byte. */ |
| outbit = (Bit) (outbyte & 1); |
| outbyte >>= 1; |
| } |
| |
| /* The last bit of the last byte. */ |
| if (is_last_byte && (j == nbits - 1)) |
| { |
| /* Change to Exit1-DR/IR state before the last bit is shifted: |
| this is necessary because the TAP Controller performs the |
| last sample of TDI when exiting the Shift-DR/IR state. */ |
| tapc_set_TMS(1); |
| NEXT_STATE(1); |
| } |
| |
| /* Shift one bit in from the JTAG TDO and one bit out to the JTAG TDI. */ |
| inbit = tapc_shift_bit(outbit); |
| |
| /* Add the bit read into the input byte. |
| N.B. the shift amount will always be positive, as 0 <= j < BITS_IN_BYTE */ |
| if (order == MSB_FIRST) |
| inbyte |= (Byte) (inbit << (BITS_IN_BYTE - 1 - j)); |
| else |
| inbyte |= (Byte) (inbit << j); |
| } |
| |
| if (order == MSB_FIRST) |
| to_read[nbytes - 1 - i] = inbyte; |
| else |
| to_read[i] = inbyte; |
| } |
| |
| STATE_IS_EITHER(EXIT1_DR, EXIT1_IR); |
| |
| LEAVEMSG; |
| } |
| |
| |
| /* Read the JTAG Status Register. |
| This indicates the status of the JTAG transaction that has been attempted. */ |
| |
| static JTAG_TransactionStatus |
| read_jtag_status_register( void) |
| { |
| JTAG_RegisterContents rd, wr; |
| Bit bit; |
| |
| ENTERMSG; |
| |
| STATE_IS_EITHER(RUN_TEST_IDLE, UPDATE_DR); |
| |
| CHANGE_STATE(1, SELECT_DR_SCAN); |
| CHANGE_STATE(1, SELECT_IR_SCAN); |
| CHANGE_STATE(0, CAPTURE_IR); |
| CHANGE_STATE(0, SHIFT_IR); |
| |
| wr = JTAG_STATUS_REGISTER; |
| |
| tapc_shift_N_bits(BITS_IN_REGISTER_CODE, (Byte*) &wr, (Byte*) &rd, MSB_LAST); |
| |
| CHANGE_STATE(1, UPDATE_IR); |
| // CHANGE_STATE(0, RUN_TEST_IDLE); |
| CHANGE_STATE(1, SELECT_DR_SCAN); |
| CHANGE_STATE(0, CAPTURE_DR); |
| CHANGE_STATE(0, SHIFT_DR); |
| |
| /* The JTAG Status Register is read-only, and any bits shifted in are |
| ignored - hence the parameter to tapc_shift_bit is irrelevant here. */ |
| |
| /* Read Stalled bit; if it is zero then keep reading. */ |
| bit = tapc_shift_bit(0); |
| if (bit) |
| return STALLED; |
| |
| /* Read Failed bit; if it is zero then keep reading. */ |
| bit = tapc_shift_bit(0); |
| if (bit) |
| return FAILURE; |
| |
| /* Read Ready bit. */ |
| bit = tapc_shift_bit(0); |
| if (bit) |
| return READY; |
| |
| /* The last bit (PC_SEL) is optional. */ |
| |
| return NOT_READY; |
| } |
| |
| |
| /* Write a value to a JTAG register. |
| enter in Update-DR/IR state or Run-Test/Idle. |
| exit in Update-DR */ |
| |
| static void |
| write_jtag_reg (JTAG_Register regnum, |
| JTAG_RegisterContents data, |
| unsigned int num_data_bits) |
| { |
| Byte num = (Byte) regnum; |
| JTAG_RegisterContents rd = 0; |
| |
| ENTERARGS("regnum %d <== 0x%08X (:%d)", regnum, data, num_data_bits); |
| |
| STATE_IS_ONE_OF(UPDATE_DR, UPDATE_IR, RUN_TEST_IDLE); |
| |
| // CHANGE_STATE(0, RUN_TEST_IDLE); |
| CHANGE_STATE(1, SELECT_DR_SCAN); |
| CHANGE_STATE(1, SELECT_IR_SCAN); |
| CHANGE_STATE(0, CAPTURE_IR); |
| CHANGE_STATE(0, SHIFT_IR); |
| |
| tapc_shift_N_bits(BITS_IN_REGISTER_CODE, &num, (Byte*) &rd, MSB_LAST); |
| |
| CHANGE_STATE(1, UPDATE_IR); |
| CHANGE_STATE(1, SELECT_DR_SCAN); |
| CHANGE_STATE(0, CAPTURE_DR); |
| CHANGE_STATE(0, SHIFT_DR); |
| |
| tapc_shift_N_bits(num_data_bits, (Byte*) &data, (Byte*) &rd, MSB_LAST); |
| |
| CHANGE_STATE(1, UPDATE_DR); |
| |
| DEBUG("written 0x%08X to JTAG %s register\n", data, JTAG_register_name(regnum)); |
| |
| LEAVEMSG; |
| } |
| |
| |
| /* Read a value from a JTAG register. |
| enter in Update-DR/IR state |
| exit in Update-DR */ |
| |
| static JTAG_RegisterContents |
| read_jtag_reg (JTAG_Register regnum, unsigned int num_data_bits) |
| { |
| Byte num = (Byte) regnum; |
| JTAG_RegisterContents wr = 0, rd = 0; |
| |
| ENTERARGS("regnum %u, %u bits", regnum, num_data_bits); |
| |
| STATE_IS_EITHER(UPDATE_DR, UPDATE_IR); |
| |
| // CHANGE_STATE(0, RUN_TEST_IDLE); |
| CHANGE_STATE(1, SELECT_DR_SCAN); |
| CHANGE_STATE(1, SELECT_IR_SCAN); |
| CHANGE_STATE(0, CAPTURE_IR); |
| CHANGE_STATE(0, SHIFT_IR); |
| |
| tapc_shift_N_bits(BITS_IN_REGISTER_CODE, &num, (Byte*) &rd, MSB_LAST); |
| |
| CHANGE_STATE(1, UPDATE_IR); |
| |
| /* JTAG registers can be read without going to Run-Test/Idle state. |
| |
| Doing CHANGE_STATE(0) would take us to Run-Test/Idle state. This would |
| make JTAG perform the transaction in the Transaction Command Register. |
| We don't want that! */ |
| // CHANGE_STATE(0, RUN_TEST_IDLE); |
| CHANGE_STATE(1, SELECT_DR_SCAN); |
| CHANGE_STATE(0, CAPTURE_DR); |
| CHANGE_STATE(0, SHIFT_DR); |
| |
| tapc_shift_N_bits(num_data_bits, (Byte*) &wr, (Byte*) &rd, MSB_LAST); |
| |
| CHANGE_STATE(1, UPDATE_DR); |
| |
| DEBUG("read 0x%08X from JTAG %s register\n", rd, JTAG_register_name(regnum)); |
| return rd; |
| } |
| |
| |
| /* -------------------------------------------------------------------------- */ |
| /* 5) JTAG transaction functions */ |
| /* -------------------------------------------------------------------------- */ |
| |
| /* Start a JTAG transaction. |
| |
| Parameters: |
| command: the JTAG command to be performed |
| address: the address (memory address or register number) for the command |
| */ |
| |
| static void |
| start_jtag_transaction (JTAG_RegisterContents command, |
| JTAG_RegisterContents address) |
| { |
| ENTERARGS("command = %d, address = 0x%x", command, address); |
| |
| STATE_IS_ONE_OF(UPDATE_DR, UPDATE_IR, RUN_TEST_IDLE); |
| |
| /* N.B. do NOT reset the TAP Controller at the start of each transaction, as |
| that would re-initialize the JTAG registers to their default values |
| (whatever those might be), so invalidating the optimisation of the |
| use of the Address and Transaction Command registers performed by |
| this module. */ |
| |
| if (command == READ_MEMORY_LOCATION || command == WRITE_MEMORY_LOCATION) |
| { |
| gdb_assert(IS_WORD_ALIGNED(address)); |
| } |
| |
| /* Load the command that is required into the JTAG Transaction Command |
| Register, and the address into the JTAG Address Register; by keeping |
| track of the values that these registers contain, we can avoid re-loading |
| them unnecessarily, which can save time when transferring a stream of data. */ |
| |
| if (!command_register_contents_known || |
| (command_register_contents != command)) |
| { |
| write_jtag_reg(JTAG_TRANSACTION_COMMAND_REGISTER, command, BITS_IN_COMMAND_CODE); |
| |
| command_register_contents_known = TRUE; |
| command_register_contents = command; |
| } |
| |
| if (!address_register_contents_known || |
| (address_register_contents != address)) |
| { |
| write_jtag_reg(JTAG_ADDRESS_REGISTER, address, BITS_IN_WORD); |
| |
| address_register_contents_known = TRUE; |
| address_register_contents = address; |
| } |
| |
| LEAVEMSG; |
| } |
| |
| |
| /* Perform the given JTAG transaction (a mmeory or register operation). |
| If the transaction fails, this function returns the given error. */ |
| |
| static JTAG_OperationStatus |
| perform_jtag_transaction (JTAG_TransactionType transaction, |
| JTAG_OperationStatus error) |
| { |
| JTAG_OperationStatus result = error; |
| unsigned int tries = 0; |
| |
| ENTERARGS("transaction: %u", transaction); |
| |
| /* This causes the TAP Controller to perform the transaction, according to |
| the contents of the JTAG Transaction Command, Address and Data registers. */ |
| CHANGE_STATE(0, RUN_TEST_IDLE); |
| |
| /* Poll the JTAG Status Register. */ |
| do |
| { |
| JTAG_TransactionStatus status = read_jtag_status_register(); |
| |
| DEBUG("status: %s\n", JTAG_TransactionStatus_Image(status)); |
| |
| /* The read has left the TAP Controller FSM in state Shift-DR. */ |
| STATE_IS(SHIFT_DR); |
| |
| CHANGE_STATE(1, EXIT1_DR); |
| CHANGE_STATE(1, UPDATE_DR); |
| |
| /* If the transaction is complete. */ |
| if (status == READY) |
| { |
| /* The value in the JTAG Address Register is incremented by four |
| (a memory access) or one (a register access) when a read/write |
| transaction has completed. */ |
| address_register_contents += (transaction == Memory) ? BYTES_IN_WORD : 1; |
| |
| result = JTAG_SUCCESS; |
| break; |
| } |
| |
| if (status == FAILURE) |
| break; |
| |
| /* Pause and re-try. */ |
| usleep(1); |
| } |
| while (++tries <= arc_jtag_ops.retry_count); |
| |
| LEAVEMSG; |
| return result; |
| } |
| |
| |
| /* -------------------------------------------------------------------------- */ |
| /* 6) read/write helper functions */ |
| /* -------------------------------------------------------------------------- */ |
| |
| /* These functions aid in reading/writing registers/memory. */ |
| |
| /* Read a processor register (core or auxiliary). */ |
| |
| static JTAG_OperationStatus |
| read_processor_register (ARC_RegisterNumber regnum, |
| JTAG_RegisterContents command, |
| ARC_RegisterContents *contents) |
| { |
| JTAG_OperationStatus status; |
| |
| /* Load the number of the register that is to be read into the JTAG Address |
| Register. */ |
| start_jtag_transaction(command, regnum); |
| |
| status = perform_jtag_transaction(Register, JTAG_READ_FAILURE); |
| |
| if (status == JTAG_SUCCESS) |
| { |
| /* Read the register contents from the JTAG Data Register. */ |
| *contents = (ARC_RegisterContents) read_jtag_reg(JTAG_DATA_REGISTER, BITS_IN_REGISTER); |
| } |
| |
| return status; |
| } |
| |
| |
| /* Write a processor register (core or auxiliary). */ |
| |
| static JTAG_OperationStatus |
| write_processor_register (ARC_RegisterNumber regnum, |
| JTAG_RegisterContents command, |
| ARC_RegisterContents contents) |
| { |
| /* Load the number of the register that is to be written into the JTAG |
| Address Register. */ |
| start_jtag_transaction(command, regnum); |
| |
| /* Load the new register contents into the JTAG Data Register. */ |
| write_jtag_reg(JTAG_DATA_REGISTER, contents, BITS_IN_REGISTER); |
| |
| return perform_jtag_transaction(Register, JTAG_WRITE_FAILURE); |
| } |
| |
| |
| /* Write a processor core register. */ |
| |
| static JTAG_OperationStatus |
| jtag_write_core_reg (ARC_RegisterNumber regnum, ARC_RegisterContents contents) |
| { |
| ENTERARGS("regnum %d", regnum); |
| |
| return write_processor_register(regnum, WRITE_CORE_REGISTER, contents); |
| } |
| |
| |
| /* Read a processor auxiliary register. */ |
| |
| static JTAG_OperationStatus |
| jtag_read_aux_reg (ARC_RegisterNumber regnum, ARC_RegisterContents *contents) |
| { |
| ENTERARGS("regnum %d", regnum); |
| |
| return read_processor_register(regnum, READ_AUX_REGISTER, contents); |
| } |
| |
| |
| /* Write a processor auxiliary register. */ |
| |
| static JTAG_OperationStatus |
| jtag_write_aux_reg (ARC_RegisterNumber regnum, ARC_RegisterContents contents) |
| { |
| ENTERARGS("regnum %d", regnum); |
| |
| return write_processor_register(regnum, WRITE_AUX_REGISTER, contents); |
| } |
| |
| |
| /* Read a word of data from memory; the given address must be word-aligned. |
| Returns number of bytes read. */ |
| |
| static unsigned int |
| jtag_read_word (ARC_Address addr, ARC_Word *data) |
| { |
| JTAG_OperationStatus status; |
| |
| ENTERARGS("addr 0x%08X", addr); |
| |
| gdb_assert(IS_WORD_ALIGNED(addr)); |
| |
| /* Load the address of the memory word that is to be read into the JTAG |
| Address Register. */ |
| start_jtag_transaction(READ_MEMORY_LOCATION, addr); |
| |
| status = perform_jtag_transaction(Memory, JTAG_READ_FAILURE); |
| |
| if (status == JTAG_SUCCESS) |
| { |
| /* Read the data from the JTAG Data Register. */ |
| ARC_Word word = (ARC_Word) read_jtag_reg(JTAG_DATA_REGISTER, BITS_IN_WORD); |
| |
| /* N.B. this assumes that the host is little-endian! */ |
| if (target_is_big_endian) |
| word = __bswap_32(word); |
| |
| DEBUG("read 0x%08X\n", word); |
| |
| *data = word; |
| |
| return BYTES_IN_WORD; |
| } |
| |
| /* Failed: no data read. */ |
| return 0; |
| } |
| |
| |
| /* Write a word of data to memory; the given address must be word-aligned. |
| Returns number of bytes written. */ |
| |
| static unsigned int |
| jtag_write_word (ARC_Address addr, ARC_Word data) |
| { |
| ENTERARGS("addr 0x%08X, data 0x%08X", addr, data); |
| |
| gdb_assert(IS_WORD_ALIGNED(addr)); |
| |
| /* Load the address of the memory word that is to be written into the JTAG |
| Address Register. */ |
| start_jtag_transaction(WRITE_MEMORY_LOCATION, addr); |
| |
| /* N.B. this assumes that the host is little-endian! */ |
| if (target_is_big_endian) |
| data = __bswap_32(data); |
| |
| /* Load the data to be written into the JTAG Data Register. */ |
| write_jtag_reg(JTAG_DATA_REGISTER, data, BITS_IN_WORD); |
| |
| if (perform_jtag_transaction(Memory, JTAG_WRITE_FAILURE) == JTAG_SUCCESS) |
| return BYTES_IN_WORD; |
| |
| /* Failed: no data written. */ |
| return 0; |
| } |
| |
| |
| /* Read a number of words of data from target memory starting at the given address. |
| Returns number of bytes read. */ |
| |
| static unsigned int |
| jtag_read_chunk (ARC_Address address, ARC_Byte *data, unsigned int words) |
| { |
| unsigned int total_read = 0; |
| |
| ENTERARGS("address 0x%08X, words %u", address, words); |
| |
| /* Load the start address of the memory chunk that is to be read |
| into the JTAG Address Register. */ |
| start_jtag_transaction(READ_MEMORY_LOCATION, address); |
| |
| /* Read all the words of data. */ |
| while (words--) |
| { |
| ARC_Word word; |
| |
| /* Read the next word of data - this increments the address in |
| the JTAG Address Register by the word size, so the register |
| does not have to be re-loaded with the next address. */ |
| if (perform_jtag_transaction(Memory, JTAG_READ_FAILURE) != JTAG_SUCCESS) |
| { |
| DEBUG("FAIL: read %u bytes\n", total_read); |
| |
| /* Failed - just return amount of data read so far. */ |
| return total_read; |
| } |
| |
| /* Read the word of data from the JTAG Data Register. */ |
| word = (ARC_Word) read_jtag_reg(JTAG_DATA_REGISTER, BITS_IN_WORD); |
| |
| /* N.B. this assumes that the host is little-endian! */ |
| if (target_is_big_endian) |
| word = __bswap_32(word); |
| |
| /* Copy it into the buffer (byte-by-byte copy means that alignment does not matter). */ |
| COPY_WORD(data, &word); |
| |
| total_read += BYTES_IN_WORD; |
| data += BYTES_IN_WORD; |
| } |
| |
| return total_read; |
| } |
| |
| |
| /* Write a number of words of data to target memory starting at the given address. |
| Returns number of bytes written. */ |
| |
| static unsigned int |
| jtag_write_chunk (ARC_Address address, ARC_Byte *data, unsigned int words) |
| { |
| unsigned int total_written = 0; |
| |
| #ifndef JTAG_DATA_REGISTER_IS_CORRUPTED_BY_WRITE |
| ARC_Word last_word; |
| |
| /* Initialise last_word with a value that is different from the |
| first word to be written. */ |
| COPY_WORD(&last_word, data); |
| last_word++; |
| #endif |
| |
| ENTERARGS("address 0x%08X, words %u", address, words); |
| |
| /* Load the start address of the memory chunk that is to be written |
| into the JTAG Address Register. */ |
| start_jtag_transaction(WRITE_MEMORY_LOCATION, address); |
| |
| /* write all the words of data */ |
| while (words--) |
| { |
| ARC_Word word; |
| |
| /* Copy the next word of data from the buffer |
| (byte-by-byte copy means that alignment does not matter). */ |
| COPY_WORD(&word, data); |
| |
| /* N.B. this assumes that the host is little-endian! */ |
| if (target_is_big_endian) |
| word = __bswap_32(word); |
| |
| #ifndef JTAG_DATA_REGISTER_IS_CORRUPTED_BY_WRITE |
| if (word != last_word) |
| { |
| #endif |
| write_jtag_reg(JTAG_DATA_REGISTER, word, BITS_IN_WORD); |
| |
| #ifdef CHECK_JTAG_DATA_REGISTER |
| check_Data_Register(word); |
| #endif |
| |
| #ifndef JTAG_DATA_REGISTER_IS_CORRUPTED_BY_WRITE |
| last_word = word; |
| } |
| #endif |
| |
| data += BYTES_IN_WORD; |
| |
| /* Write the word - this increments the address in the JTAG |
| Address Register by the word size, so the register does not |
| have to be re-loaded with the next address. */ |
| if (perform_jtag_transaction(Memory, JTAG_WRITE_FAILURE) != JTAG_SUCCESS) |
| { |
| DEBUG("FAIL: written %u bytes\n", total_written); |
| |
| /* Failed - just return amount of data written so far. */ |
| return total_written; |
| } |
| |
| total_written += BYTES_IN_WORD; |
| } |
| |
| return total_written; |
| } |
| |
| |
| /* Write a number of copies of a word-sized pattern of data to memory starting |
| at the given address. |
| Returns number of bytes written. */ |
| |
| static unsigned int |
| jtag_write_pattern (ARC_Address address, ARC_Word pattern, unsigned int words) |
| { |
| unsigned int total_written = 0; |
| |
| ENTERARGS("address 0x%08X, pattern 0x%08X, words %u", address, pattern, words); |
| |
| /* Load the start address of the memory chunk that is to be written |
| into the JTAG Address Register. */ |
| start_jtag_transaction(WRITE_MEMORY_LOCATION, address); |
| |
| /* N.B. this assumes that the host is little-endian! */ |
| if (target_is_big_endian) |
| pattern = __bswap_32(pattern); |
| |
| #ifndef JTAG_DATA_REGISTER_IS_CORRUPTED_BY_WRITE |
| /* Load the pattern into the JTAG Data Register. */ |
| write_jtag_reg(JTAG_DATA_REGISTER, pattern, BITS_IN_WORD); |
| #endif |
| |
| /* Write all the complete words of data. */ |
| while (words--) |
| { |
| #ifdef JTAG_DATA_REGISTER_IS_CORRUPTED_BY_WRITE |
| /* Load the pattern into the JTAG Data Register. */ |
| write_jtag_reg(JTAG_DATA_REGISTER, pattern, BITS_IN_WORD); |
| #endif |
| |
| #ifdef CHECK_JTAG_DATA_REGISTER |
| check_Data_Register(pattern); |
| #endif |
| |
| /* Write the word - this increments the address in the JTAG |
| Address Register by the word size, so the register does not |
| have to be re-loaded with the next address. */ |
| if (perform_jtag_transaction(Memory, JTAG_WRITE_FAILURE) != JTAG_SUCCESS) |
| { |
| DEBUG("FAIL: written %u bytes\n", total_written); |
| |
| /* Failed - just return amount of data written so far. */ |
| return total_written; |
| } |
| |
| total_written += BYTES_IN_WORD; |
| } |
| |
| return total_written; |
| } |
| |
| |
| /* -------------------------------------------------------------------------- */ |
| /* 7) main operations */ |
| /* -------------------------------------------------------------------------- */ |
| |
| /* These are the functions that are called from outside this module via the |
| pointers in the arc_jtag_ops global object. |
| N.B. none of these functions are called from within this module. */ |
| |
| |
| /* Read a processor core register. */ |
| |
| static JTAG_OperationStatus |
| jtag_read_core_reg (ARC_RegisterNumber regnum, ARC_RegisterContents *contents) |
| { |
| ENTERARGS("regnum %d", regnum); |
| |
| return read_processor_register(regnum, READ_CORE_REGISTER, contents); |
| } |
| |
| |
| /* Try to open the JTAG interface. |
| Returns TRUE for success. */ |
| |
| static Boolean |
| jtag_open (ARC_RegisterNumber mem_subsys) |
| { |
| ENTERMSG; |
| |
| if (arc_jtag_ops.status == JTAG_CLOSED) |
| { |
| JTAG_OperationStatus status; |
| |
| /* Make sure that the GPIO driver is open. */ |
| if (!gpio_open()) |
| return FALSE; |
| |
| set_interface(JTAG_OPENED); |
| |
| tapc_reset(); |
| |
| /* Load the number of the MEMSUBSYS BCR that is to be read into the JTAG |
| Address Register. */ |
| start_jtag_transaction(READ_AUX_REGISTER, mem_subsys); |
| |
| status = perform_jtag_transaction(Register, JTAG_READ_FAILURE); |
| |
| if (status == JTAG_SUCCESS) |
| { |
| /* Read the register contents from the JTAG Data Register. */ |
| ARC_RegisterContents contents = |
| (ARC_RegisterContents) read_jtag_reg(JTAG_DATA_REGISTER, BITS_IN_REGISTER); |
| |
| DEBUG("MEMSUBSYS BCR: 0x%08X\n", contents); |
| |
| target_is_big_endian = ((contents & 4) != 0); |
| } |
| else |
| { |
| warning(_("can not discover endianness of target\n")); |
| return FALSE; |
| } |
| |
| DEBUG("arcjtag opened\n"); |
| } |
| |
| LEAVEMSG; |
| |
| return TRUE; |
| } |
| |
| |
| /* Close the JTAG interface. */ |
| |
| static void |
| jtag_close (void) |
| { |
| ENTERMSG; |
| |
| if (arc_jtag_ops.status == JTAG_OPENED) |
| { |
| tapc_reset(); |
| |
| /* Close the file descriptor opened for communication with gpio driver. */ |
| gpio_close(); |
| |
| set_interface(JTAG_CLOSED); |
| |
| #ifdef STATE_MACHINE_DEBUG |
| current_state = UNDEFINED; |
| #endif |
| |
| DEBUG("arcjtag closed\n"); |
| } |
| |
| LEAVEMSG; |
| } |
| |
| |
| /* Reset the target JTAG controller. */ |
| |
| static void |
| jtag_reset (void) |
| { |
| ENTERMSG; |
| tapc_reset(); |
| LEAVEMSG; |
| } |
| |
| |
| /* Reset the target board. */ |
| |
| static void |
| jtag_reset_board (void) |
| { |
| ENTERMSG; |
| |
| /* Make sure that the GPIO driver is open. */ |
| if (gpio_open()) |
| { |
| /* Writing 9 did not work. But that's what the manual says. Hmmm. */ |
| // gpio_write (CONTROL_PORT, 9); |
| |
| /* What is this for? */ |
| gpio_write(CONTROL_PORT, (Byte) JTAG_TCK); |
| gpio_write(CONTROL_PORT, (Byte) 0xD); |
| gpio_write(CONTROL_PORT, (Byte) JTAG_TCK); |
| gpio_write(DATA_PORT, (Byte) 0); |
| gpio_write(DATA_PORT, (Byte) JTAG_TMS); |
| gpio_write(DATA_PORT, (Byte) 0); |
| |
| tapc_reset(); |
| } |
| |
| LEAVEMSG; |
| } |
| |
| |
| /* Check that the JTAG interface is open. |
| If it is closed, 'error' is called. */ |
| |
| static void jtag_check_open (void) |
| { |
| if (arc_jtag_ops.status == JTAG_CLOSED) |
| interface_is_closed(); |
| } |
| |
| |
| /* -------------------------------------------------------------------------- */ |
| /* 8) interface management */ |
| /* -------------------------------------------------------------------------- */ |
| |
| /* Report that the JTAG interface is closed. */ |
| |
| static void |
| interface_is_closed (void) |
| { |
| error(_("JTAG connection is closed. " |
| "Use command 'target " ARC_TARGET_NAME "' first.")); |
| } |
| |
| |
| /* Set up the function pointers in the arc_jtag_ops structure according to |
| whether the JTAG interface is open or closed. Note that if the interface is |
| closed, all the pointers point to the 'interface_is_closed' function - so any |
| attempt to invoke one of those operations results in an error; but if the |
| interface is open, they point to the appropriate operations (which may be |
| called without incurring the overhead of a check on the interface status). */ |
| |
| static void |
| set_interface (JTAG_Status status) |
| { |
| arc_jtag_ops.status = status; |
| |
| if (status == JTAG_OPENED) |
| { |
| arc_jtag_ops.memory_read_word = jtag_read_word; |
| arc_jtag_ops.memory_write_word = jtag_write_word; |
| arc_jtag_ops.memory_read_chunk = jtag_read_chunk; |
| arc_jtag_ops.memory_write_chunk = jtag_write_chunk; |
| arc_jtag_ops.memory_write_pattern = jtag_write_pattern; |
| arc_jtag_ops.read_aux_reg = jtag_read_aux_reg; |
| arc_jtag_ops.write_aux_reg = jtag_write_aux_reg; |
| arc_jtag_ops.read_core_reg = jtag_read_core_reg; |
| arc_jtag_ops.write_core_reg = jtag_write_core_reg; |
| arc_jtag_ops.reset = jtag_reset; |
| } |
| else |
| { |
| typedef unsigned int (*Read_Word) (ARC_Address, ARC_Word*); |
| typedef unsigned int (*Write_Word) (ARC_Address, ARC_Word); |
| typedef unsigned int (*Transfer_Chunk) (ARC_Address, ARC_Byte*, unsigned int); |
| typedef unsigned int (*Write_Pattern) (ARC_Address, ARC_Word, unsigned int); |
| typedef JTAG_OperationStatus (*Read_Register) (ARC_RegisterNumber, ARC_RegisterContents*); |
| typedef JTAG_OperationStatus (*Write_Register) (ARC_RegisterNumber, ARC_RegisterContents); |
| |
| /* The type casts avoid "assignment from incompatible pointer type" warnings |
| at compile-time. */ |
| arc_jtag_ops.memory_read_word = (Read_Word) interface_is_closed; |
| arc_jtag_ops.memory_write_word = (Write_Word) interface_is_closed; |
| arc_jtag_ops.memory_read_chunk = (Transfer_Chunk) interface_is_closed; |
| arc_jtag_ops.memory_write_chunk = (Transfer_Chunk) interface_is_closed; |
| arc_jtag_ops.memory_write_pattern = (Write_Pattern) interface_is_closed; |
| arc_jtag_ops.read_aux_reg = (Read_Register) interface_is_closed; |
| arc_jtag_ops.write_aux_reg = (Write_Register) interface_is_closed; |
| arc_jtag_ops.read_core_reg = (Read_Register) interface_is_closed; |
| arc_jtag_ops.write_core_reg = (Write_Register) interface_is_closed; |
| arc_jtag_ops.reset = interface_is_closed; |
| } |
| } |
| |
| |
| /* -------------------------------------------------------------------------- */ |
| /* externally visible functions */ |
| /* -------------------------------------------------------------------------- */ |
| |
| /* Initialize the module. This function is called from the gdb core on start-up. */ |
| |
| void |
| _initialize_arc_jtag_ops (void) |
| { |
| ENTERMSG; |
| |
| /* Initialize the arc_jtag_ops global variable. */ |
| |
| arc_jtag_ops.state_machine_debug = FALSE; |
| arc_jtag_ops.retry_count = 50; |
| |
| /* We want to be able to reset the board, and check whether it is connected, |
| regardless of the connection state. */ |
| arc_jtag_ops.open = jtag_open; |
| arc_jtag_ops.close = jtag_close; |
| arc_jtag_ops.check_open = jtag_check_open; |
| arc_jtag_ops.reset_board = jtag_reset_board; |
| |
| /* The JTAG interface is initially closed. */ |
| set_interface(JTAG_CLOSED); |
| } |
| |
| /******************************************************************************/ |