- merged XScale branch back into trunk
authordrath <drath@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Wed, 28 Mar 2007 16:31:55 +0000 (16:31 +0000)
committerdrath <drath@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Wed, 28 Mar 2007 16:31:55 +0000 (16:31 +0000)
- fixed some compiler warnigns in amt_jtagaccel.c, bitbang.c, parport.c
- free working area and register stuff if str7x block write algorithm failed
- check PC after exiting a target algorithm in armv4_5.c

git-svn-id: svn://svn.berlios.de/openocd/trunk@135 b42882b7-edfa-0310-969c-e2dbd0fdcd60

21 files changed:
src/flash/str7x.c
src/helper/fileio.c
src/jtag/amt_jtagaccel.c
src/jtag/bitbang.c
src/jtag/parport.c
src/openocd.c
src/target/Makefile.am
src/target/arm_disassembler.c
src/target/arm_disassembler.h
src/target/arm_simulator.c [new file with mode: 0644]
src/target/arm_simulator.h [new file with mode: 0644]
src/target/armv4_5.c
src/target/armv4_5.h
src/target/target.c
src/target/target.h
src/target/xscale.c [new file with mode: 0644]
src/target/xscale.h [new file with mode: 0644]
src/target/xscale/build.sh [new file with mode: 0644]
src/target/xscale/debug_handler.S [new file with mode: 0644]
src/target/xscale/debug_handler.cmd [new file with mode: 0644]
src/target/xscale/protocol.h [new file with mode: 0644]

index 62acba38744bba69f9b80428af79d5573e981c64..0fa2f6ce924e5b6631988e25483765af99c370ed 100644 (file)
@@ -451,7 +451,7 @@ int str7x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 cou
        u32 address = bank->base + offset;
        reg_param_t reg_params[5];
        armv4_5_algorithm_t armv4_5_info;
-       int retval;
+       int retval = ERROR_OK;
        
        u32 str7x_flash_write_code[] = {
                                        /* write:                               */
@@ -537,12 +537,13 @@ int str7x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 cou
                if ((retval = target->type->run_algorithm(target, 0, NULL, 5, reg_params, str7x_info->write_algorithm->address, str7x_info->write_algorithm->address + (19 * 4), 10000, &armv4_5_info)) != ERROR_OK)
                {
                        ERROR("error executing str7x flash write algorithm");
-                       return ERROR_FLASH_OPERATION_FAILED;
+                       break;
                }
        
                if (buf_get_u32(reg_params[4].value, 0, 32) != 0x00)
                {
-                       return ERROR_FLASH_OPERATION_FAILED;
+                       retval = ERROR_FLASH_OPERATION_FAILED;
+                       break;
                }
                
                buffer += thisrun_count * 8;
@@ -558,7 +559,7 @@ int str7x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 cou
        destroy_reg_param(&reg_params[3]);
        destroy_reg_param(&reg_params[4]);
        
-       return ERROR_OK;
+       return retval;
 }
 
 int str7x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
index 756e0f460cbf20de7abd5553520d8c118551972f..648f18794c9e17a4fc2940364f52927fe954f2d7 100644 (file)
@@ -242,22 +242,23 @@ int fileio_open(fileio_t *fileio, char *url, enum fileio_access access,
        enum fileio_pri_type pri_type, void *pri_info, enum fileio_sec_type sec_type)
 {
        int retval = ERROR_OK;
-       
-       if ((!url) || (strlen(url) < 3))
+       char *resource_identifier = NULL;
+
+       /* try to identify file location */
+       if ((resource_identifier = strstr(url, "bootp://")) && (resource_identifier == url))
        {
-               snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "invalid file url");
-               return ERROR_INVALID_ARGUMENTS;
+               ERROR("bootp resource location isn't supported yet");
+               return ERROR_FILEIO_RESOURCE_TYPE_UNKNOWN;
        }
-       
-       if ((url[0] == '/') || (isalpha(url[0])) || ((url[1] == ':') && (url[2] == '\\')))
+       else if ((resource_identifier = strstr(url, "tftp://")) && (resource_identifier == url))
        {
-               fileio->location = FILEIO_LOCAL;
+               ERROR("tftp resource location isn't supported yet");
+               return ERROR_FILEIO_RESOURCE_TYPE_UNKNOWN;
        }
        else
        {
-               ERROR("couldn't identify resource location from URL '%s'", url);
-               snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "couldn't identify resource location from URL '%s'", url);
-               return ERROR_FILEIO_LOCATION_UNKNOWN;
+               /* default to local files */
+               fileio->location = FILEIO_LOCAL;
        }
        
        fileio->access = access;
index dca5c334af60f1ff51c38940cab9213f5864f192..ac2635207f701b1be9c3292ca6761f1ae63e26fd 100644 (file)
@@ -385,7 +385,7 @@ int amt_jtagaccel_execute_queue(void)
                                break;
                        case JTAG_SLEEP:
 #ifdef _DEBUG_JTAG_IO_
-                               DEBUG("sleep", cmd->cmd.sleep->us);
+                               DEBUG("sleep %i", cmd->cmd.sleep->us);
 #endif
                                jtag_sleep(cmd->cmd.sleep->us);
                                break;
index 2065f62ab07439aa6b6074101a1d535343a00fe1..61248364952e2fcb9643f1aa63e3a2b845ae2dc1 100644 (file)
@@ -248,7 +248,7 @@ int bitbang_execute_queue(void)
                                break;
                        case JTAG_SLEEP:
 #ifdef _DEBUG_JTAG_IO_
-                               DEBUG("sleep", cmd->cmd.sleep->us);
+                               DEBUG("sleep %i", cmd->cmd.sleep->us);
 #endif
                                jtag_sleep(cmd->cmd.sleep->us);
                                break;
index 6386940e8c581d326f7f62c4af57b94d152655b5..a46d611fd9ea0319e5deab7365a65cb8963a9f33 100644 (file)
@@ -375,7 +375,7 @@ int parport_init(void)
        dataport = parport_port;
        statusport = parport_port + 1;
        
-       DEBUG("requesting privileges for parallel port 0x%x...", dataport);
+       DEBUG("requesting privileges for parallel port 0x%lx...", dataport);
 #if PARPORT_USE_GIVEIO == 1
        if (parport_get_giveio_access() != 0)
 #else /* PARPORT_USE_GIVEIO */
index 4fbaf467e83f3ce939116c02f161eb09a31d7ee3..0b6d1bc06c99c9bcb19956d24a9361e01653bcc7 100644 (file)
@@ -18,7 +18,7 @@
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
 
-#define OPENOCD_VERSION "Open On-Chip Debugger (2007-03-15 14:30 CET)"
+#define OPENOCD_VERSION "Open On-Chip Debugger (2007-03-28 18:30 CEST)"
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
index 3e2b39d33d57645566daa432314c33dc755eb494..cf1955a05c59945873ae4a7013ee7de2f57776b8 100644 (file)
@@ -3,7 +3,7 @@ METASOURCES = AUTO
 noinst_LIBRARIES = libtarget.a
 libtarget_a_SOURCES = target.c register.c breakpoints.c armv4_5.c embeddedice.c etm.c arm7tdmi.c arm9tdmi.c \
        arm_jtag.c arm7_9_common.c algorithm.c arm920t.c arm720t.c armv4_5_mmu.c armv4_5_cache.c arm_disassembler.c \
-       arm966e.c arm926ejs.c etb.c
+       arm966e.c arm926ejs.c etb.c xscale.c arm_simulator.c
 noinst_HEADERS = target.h register.h armv4_5.h embeddedice.h etm.h arm7tdmi.h arm9tdmi.h \
                arm_jtag.h arm7_9_common.h arm920t.h arm720t.h armv4_5_mmu.h armv4_5_cache.h breakpoints.h algorithm.h \
-               arm_disassembler.h arm966e.h arm926ejs.h etb.h
+               arm_disassembler.h arm966e.h arm926ejs.h etb.h xscale.h arm_simulator.h
index f9e0227af8e952997a6dbad4d50bab738e559b5c..dd77928252fd41131eac1b197d08f357f52f1b14 100644 (file)
@@ -835,6 +835,9 @@ int evaluate_misc_instr(u32 opcode, u32 address, arm_instruction_t *instruction)
                
                snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tBLX%s r%i",
                                 address, opcode, COND(opcode), Rm);
+                                
+               instruction->info.b_bl_bx_blx.reg_operand = Rm;
+               instruction->info.b_bl_bx_blx.target_address = -1;
        }
        
        /* Enhanced DSP add/subtracts */
@@ -1078,6 +1081,18 @@ int evaluate_data_proc(u32 opcode, u32 address, arm_instruction_t *instruction)
                        instruction->info.data_proc.shifter_operand.immediate_shift.shift_imm = shift_imm;
                        instruction->info.data_proc.shifter_operand.immediate_shift.shift = shift;
                
+                       /* LSR encodes a shift by 32 bit as 0x0 */
+                       if ((shift == 0x1) && (shift_imm == 0x0))
+                               shift_imm = 0x20;
+               
+                       /* ASR encodes a shift by 32 bit as 0x0 */
+                       if ((shift == 0x2) && (shift_imm == 0x0))
+                               shift_imm = 0x20;
+
+                       /* ROR by 32 bit is actually a RRX */
+                       if ((shift == 0x3) && (shift_imm == 0x0))
+                               shift = 0x4;
+                       
                        if ((shift_imm == 0x0) && (shift == 0x0))
                        {
                                snprintf(shifter_operand, 32, "r%i", Rm);
@@ -1090,22 +1105,19 @@ int evaluate_data_proc(u32 opcode, u32 address, arm_instruction_t *instruction)
                                }
                                else if (shift == 0x1) /* LSR */
                                {
-                                       if (shift_imm == 0x0)
-                                               shift_imm = 0x32;
                                        snprintf(shifter_operand, 32, "r%i, LSR #0x%x", Rm, shift_imm);
                                }
                                else if (shift == 0x2) /* ASR */
                                {
-                                       if (shift_imm == 0x0)
-                                               shift_imm = 0x32;
                                        snprintf(shifter_operand, 32, "r%i, ASR #0x%x", Rm, shift_imm);
                                }
-                               else if (shift == 0x3) /* ROR or RRX */
+                               else if (shift == 0x3) /* ROR */
+                               {
+                                       snprintf(shifter_operand, 32, "r%i, ROR #0x%x", Rm, shift_imm);
+                               }
+                               else if (shift == 0x4) /* RRX */
                                {
-                                       if (shift_imm == 0x0) /* RRX */
-                                               snprintf(shifter_operand, 32, "r%i, RRX", Rm);
-                                       else
-                                               snprintf(shifter_operand, 32, "r%i, ROR #0x%x", Rm, shift_imm);
+                                       snprintf(shifter_operand, 32, "r%i, RRX", Rm);
                                }
                        }
                }
@@ -1130,7 +1142,7 @@ int evaluate_data_proc(u32 opcode, u32 address, arm_instruction_t *instruction)
                        {
                                snprintf(shifter_operand, 32, "r%i, ASR r%i", Rm, Rs);
                        }
-                       else if (shift == 0x3) /* ROR or RRX */
+                       else if (shift == 0x3) /* ROR */
                        {
                                snprintf(shifter_operand, 32, "r%i, ROR r%i", Rm, Rs);
                        }
@@ -1159,7 +1171,7 @@ int evaluate_data_proc(u32 opcode, u32 address, arm_instruction_t *instruction)
        return ERROR_OK;
 }
                
-int evaluate_opcode(u32 opcode, u32 address, arm_instruction_t *instruction)
+int arm_evaluate_opcode(u32 opcode, u32 address, arm_instruction_t *instruction)
 {
        /* clear fields, to avoid confusion */
        memset(instruction, 0, sizeof(arm_instruction_t));
@@ -1302,3 +1314,4 @@ int evaluate_opcode(u32 opcode, u32 address, arm_instruction_t *instruction)
        ERROR("should never reach this point");
        return -1;
 }
+
index c6dc6967d809daca2dbb70dd3e66aec22f50476b..b55c885507bae16611fdeb489a868f5cc27a9c90 100644 (file)
@@ -126,28 +126,30 @@ typedef struct arm_b_bl_bx_blx_instr_s
        u32 target_address;
 } arm_b_bl_bx_blx_instr_t;
 
+union arm_shifter_operand
+{
+       struct {
+               u32 immediate;
+       } immediate;
+       struct {
+               u8 Rm;
+               u8 shift;
+               u8 shift_imm;
+       } immediate_shift;
+       struct {
+               u8 Rm;
+               u8 shift;
+               u8 Rs;
+       } register_shift;
+};
+
 typedef struct arm_data_proc_instr_s
 {
        int variant; /* 0: immediate, 1: immediate_shift, 2: register_shift */
        u8 S;
        u8 Rn;
        u8 Rd;
-       union
-       {
-               struct {
-                       u8 immediate;
-               } immediate;
-               struct {
-                       u8 Rm;
-                       u8 shift;
-                       u8 shift_imm;
-               } immediate_shift;
-               struct {
-                       u8 Rm;
-                       u8 shift;
-                       u8 Rs;
-               } register_shift;
-       } shifter_operand;
+       union arm_shifter_operand shifter_operand;
 } arm_data_proc_instr_t;
 
 typedef struct arm_load_store_instr_s
@@ -192,7 +194,7 @@ typedef struct arm_instruction_s
 
 } arm_instruction_t;
 
-extern int evaluate_opcode(u32 opcode, u32 address, arm_instruction_t *instruction);
+extern int arm_evaluate_opcode(u32 opcode, u32 address, arm_instruction_t *instruction);
 
 #define COND(opcode) (arm_condition_strings[(opcode & 0xf0000000)>>28])
 
diff --git a/src/target/arm_simulator.c b/src/target/arm_simulator.c
new file mode 100644 (file)
index 0000000..fd0b309
--- /dev/null
@@ -0,0 +1,684 @@
+/***************************************************************************
+ *   Copyright (C) 2006 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "target.h"
+#include "armv4_5.h"
+#include "arm_disassembler.h"
+#include "arm_simulator.h"
+#include "log.h"
+#include "binarybuffer.h"
+
+#include <string.h>
+
+u32 arm_shift(u8 shift, u32 Rm, u32 shift_amount, u8 *carry)
+{
+       u32 return_value;
+       shift_amount &= 0xff;
+       
+       if (shift == 0x0) /* LSL */
+       {
+               if ((shift_amount > 0) && (shift_amount <= 32))
+               {
+                       return_value = Rm << shift_amount;
+                       *carry = Rm >> (32 - shift_amount);
+               }
+               else if (shift_amount > 32)
+               {
+                       return_value = 0x0;
+                       *carry = 0x0;
+               }
+               else /* (shift_amount == 0) */
+               {
+                       return_value = Rm;
+               }
+       }
+       else if (shift == 0x1) /* LSR */
+       {
+               if ((shift_amount > 0) && (shift_amount <= 32))
+               {
+                       return_value = Rm >> shift_amount;
+                       *carry = (Rm >> (shift_amount - 1)) & 1;
+               }
+               else if (shift_amount > 32)
+               {
+                       return_value = 0x0;
+                       *carry = 0x0;
+               }
+               else /* (shift_amount == 0) */
+               {
+                       return_value = Rm;
+               }
+       }
+       else if (shift == 0x2) /* ASR */
+       {
+               if ((shift_amount > 0) && (shift_amount <= 32))
+               {
+                       /* right shifts of unsigned values are guaranteed to be logical (shift in zeroes)
+                        * simulate an arithmetic shift (shift in signed-bit) by adding the signed-bit manually */
+                       return_value = Rm >> shift_amount;
+                       if (Rm & 0x80000000)
+                               return_value |= 0xffffffff << (32 - shift_amount);
+               }
+               else if (shift_amount > 32)
+               {
+                       if (Rm & 0x80000000)
+                       {
+                               return_value = 0xffffffff;
+                               *carry = 0x1;
+                       }
+                       else
+                       {
+                               return_value = 0x0;
+                               *carry = 0x0;
+                       }
+               }
+               else /* (shift_amount == 0) */
+               {
+                       return_value = Rm;
+               }
+       }
+       else if (shift == 0x3) /* ROR */
+       {
+               if (shift_amount == 0)
+               {
+                       return_value = Rm;
+               }
+               else
+               {
+                       shift_amount = shift_amount % 32;
+                       return_value = (Rm >> shift_amount) | (Rm << (32 - shift_amount));
+                       *carry = (return_value >> 31) & 0x1;
+               }
+       }
+       else if (shift == 0x4) /* RRX */
+       {
+               return_value = Rm >> 1;
+               if (*carry)
+                       Rm |= 0x80000000;
+               *carry = Rm & 0x1;
+       }
+       
+       return return_value;
+}
+
+u32 arm_shifter_operand(armv4_5_common_t *armv4_5, int variant, union arm_shifter_operand shifter_operand, u8 *shifter_carry_out)
+{
+       u32 return_value;
+       int instruction_size;
+       
+       if (armv4_5->core_state == ARMV4_5_STATE_ARM)
+               instruction_size = 4;
+       else
+               instruction_size = 2;
+       
+       *shifter_carry_out = buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 29, 1);
+       
+       if (variant == 0) /* 32-bit immediate */
+       {
+               return_value = shifter_operand.immediate.immediate;
+       }
+       else if (variant == 1) /* immediate shift */
+       {
+               u32 Rm = buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, shifter_operand.immediate_shift.Rm).value, 0, 32);
+               
+               /* adjust RM in case the PC is being read */
+               if (shifter_operand.immediate_shift.Rm == 15)
+                       Rm += 2 * instruction_size;
+               
+               return_value = arm_shift(shifter_operand.immediate_shift.shift, Rm, shifter_operand.immediate_shift.shift_imm, shifter_carry_out);
+       }
+       else if (variant == 2) /* register shift */
+       {
+               u32 Rm = buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, shifter_operand.register_shift.Rm).value, 0, 32);
+               u32 Rs = buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, shifter_operand.register_shift.Rs).value, 0, 32);
+               
+               /* adjust RM in case the PC is being read */
+               if (shifter_operand.register_shift.Rm == 15)
+                       Rm += 2 * instruction_size;
+                       
+               return_value = arm_shift(shifter_operand.immediate_shift.shift, Rm, Rs, shifter_carry_out);
+       }
+       else
+       {
+               ERROR("BUG: shifter_operand.variant not 0, 1 or 2");
+               return_value = 0xffffffff;
+       }
+       
+       return return_value;
+}
+
+int pass_condition(u32 cpsr, u32 opcode)
+{
+       switch ((opcode & 0xf0000000) >> 28)
+       {
+               case 0x0:       /* EQ */
+                       if (cpsr & 0x40000000)
+                               return 1;
+                       else
+                               return 0;
+               case 0x1:       /* NE */
+                       if (!(cpsr & 0x40000000))
+                               return 1;
+                       else
+                               return 0;
+               case 0x2:       /* CS */
+                       if (cpsr & 0x20000000)
+                               return 1;
+                       else
+                               return 0;
+               case 0x3:       /* CC */
+                       if (!(cpsr & 0x20000000))
+                               return 1;
+                       else
+                               return 0;
+               case 0x4:       /* MI */
+                       if (cpsr & 0x80000000)
+                               return 1;
+                       else
+                               return 0;
+               case 0x5:       /* PL */
+                       if (!(cpsr & 0x80000000))
+                               return 1;
+                       else
+                               return 0;
+               case 0x6:       /* VS */
+                       if (cpsr & 0x10000000)
+                               return 1;
+                       else
+                               return 0;
+               case 0x7:       /* VC */
+                       if (!(cpsr & 0x10000000))
+                               return 1;
+                       else
+                               return 0;
+               case 0x8:       /* HI */
+                       if ((cpsr & 0x20000000) && !(cpsr & 0x40000000))
+                               return 1;
+                       else
+                               return 0;
+               case 0x9:       /* LS */
+                       if (!(cpsr & 0x20000000) || (cpsr & 0x40000000))
+                               return 1;
+                       else
+                               return 0;
+               case 0xa:       /* GE */
+                       if (((cpsr & 0x80000000) && (cpsr & 0x10000000))
+                               || (!(cpsr & 0x80000000) && !(cpsr & 0x10000000)))
+                               return 1;
+                       else
+                               return 0;
+               case 0xb:       /* LT */
+                       if (((cpsr & 0x80000000) && !(cpsr & 0x10000000))
+                               || (!(cpsr & 0x80000000) && (cpsr & 0x10000000)))
+                               return 1;
+                       else
+                               return 0;
+               case 0xc:       /* GT */
+                       if (!(cpsr & 0x40000000) &&
+                               (((cpsr & 0x80000000) && (cpsr & 0x10000000))
+                               || (!(cpsr & 0x80000000) && !(cpsr & 0x10000000))))
+                               return 1;
+                       else
+                               return 0;
+               case 0xd:       /* LE */
+                       if ((cpsr & 0x40000000) &&
+                               (((cpsr & 0x80000000) && !(cpsr & 0x10000000))
+                               || (!(cpsr & 0x80000000) && (cpsr & 0x10000000))))
+                               return 1;
+                       else
+                               return 0;
+               case 0xe:
+               case 0xf:
+                       return 1;
+                               
+       }
+       
+       ERROR("BUG: should never get here");
+       return 0;
+}
+
+/* simulate a single step (if possible)
+ * if the dry_run_pc argument is provided, no state is changed,
+ * but the new pc is stored in the variable pointed at by the argument
+ */
+int arm_simulate_step(target_t *target, u32 *dry_run_pc)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       u32 opcode;
+       u32 current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32);
+       arm_instruction_t instruction;
+       int instruction_size;
+       
+       if (armv4_5->core_state == ARMV4_5_STATE_ARM)
+       {
+               /* get current instruction, and identify it */
+               target_read_u32(target, current_pc, &opcode);
+               arm_evaluate_opcode(opcode, current_pc, &instruction);
+               instruction_size = 4;
+       }
+       else
+       {
+               /* TODO: add support for Thumb instruction set */
+               instruction_size = 2;
+       }
+       
+       /* check condition code */
+       if (!pass_condition(buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32), opcode))
+       {
+               if (dry_run_pc)
+               {
+                       *dry_run_pc = current_pc + instruction_size;
+               }
+               else
+               {
+                       buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, current_pc + instruction_size);
+               }
+               
+               return ERROR_OK;
+       }
+       
+       /* examine instruction type */
+
+       /* branch instructions */
+       if ((instruction.type >= ARM_B) && (instruction.type <= ARM_BLX))
+       {
+               u32 target;
+               
+               if (instruction.info.b_bl_bx_blx.reg_operand == -1)
+               {
+                       target = instruction.info.b_bl_bx_blx.target_address;
+               }
+               else
+               {
+                       target = buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, instruction.info.b_bl_bx_blx.reg_operand).value, 0, 32); 
+               }
+               
+               if (dry_run_pc)
+               {       
+                       *dry_run_pc = target;
+                       return ERROR_OK;
+               }
+               else
+               {
+                       if (instruction.type == ARM_B)
+                       {
+                               buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, target);
+                       }
+                       else if (instruction.type == ARM_BL)
+                       {
+                               u32 old_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32);
+                               buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 14).value, 0, 32, old_pc + 4);
+                               buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, target);
+                       }
+                       else if (instruction.type == ARM_BX)
+                       {
+                               if (target & 0x1)
+                               {
+                                       armv4_5->core_state = ARMV4_5_STATE_THUMB;
+                               }
+                               else
+                               {
+                                       armv4_5->core_state = ARMV4_5_STATE_ARM;
+                               }
+                               buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, target & 0xfffffffe);
+                       }
+                       else if (instruction.type == ARM_BLX)
+                       {
+                               u32 old_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32);
+                               buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 14).value, 0, 32, old_pc + 4);
+
+                               if (target & 0x1)
+                               {
+                                       armv4_5->core_state = ARMV4_5_STATE_THUMB;
+                               }
+                               else
+                               {
+                                       armv4_5->core_state = ARMV4_5_STATE_ARM;
+                               }
+                               buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, target & 0xfffffffe);
+                       }
+                       
+                       return ERROR_OK;
+               }
+       }
+       /* data processing instructions, except compare instructions (CMP, CMN, TST, TEQ) */
+       else if (((instruction.type >= ARM_AND) && (instruction.type <= ARM_RSC))
+                       || ((instruction.type >= ARM_ORR) && (instruction.type <= ARM_MVN)))
+       {
+               u32 Rd, Rn, shifter_operand;
+               u8 C = buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 29, 1);
+               u8 carry_out;
+               
+               Rd = 0x0;
+               Rn = buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, instruction.info.data_proc.Rn).value, 0, 32);
+               shifter_operand = arm_shifter_operand(armv4_5, instruction.info.data_proc.variant, instruction.info.data_proc.shifter_operand, &carry_out);
+
+               /* adjust Rn in case the PC is being read */
+               if (instruction.info.data_proc.Rn == 15)
+                       Rn += 2 * instruction_size;
+                               
+               if (instruction.type == ARM_AND)
+                       Rd = Rn & shifter_operand;
+               else if (instruction.type == ARM_EOR)
+                       Rd = Rn ^ shifter_operand;
+               else if (instruction.type == ARM_SUB)
+                       Rd = Rn - shifter_operand;
+               else if (instruction.type == ARM_RSB)
+                       Rd = shifter_operand - Rn;
+               else if (instruction.type == ARM_ADD)
+                       Rd = Rn + shifter_operand;
+               else if (instruction.type == ARM_ADC)
+                       Rd = Rn + shifter_operand + (C & 1);
+               else if (instruction.type == ARM_SBC)
+                       Rd = Rn - shifter_operand - (C & 1) ? 0 : 1;
+               else if (instruction.type == ARM_RSC)
+                       Rd = shifter_operand - Rn - (C & 1) ? 0 : 1;
+               else if (instruction.type == ARM_ORR)
+                       Rd = Rn | shifter_operand;
+               else if (instruction.type == ARM_BIC)
+                       Rd = Rn & ~(shifter_operand);
+               else if (instruction.type == ARM_MOV)
+                       Rd = shifter_operand;
+               else if (instruction.type == ARM_MVN)
+                       Rd = ~shifter_operand;
+               
+               if (dry_run_pc)
+               {
+                       if (instruction.info.data_proc.Rd == 15)
+                       {
+                               *dry_run_pc = Rd;
+                               return ERROR_OK;
+                       }
+                       else
+                       {
+                               *dry_run_pc = current_pc + instruction_size;
+                       }
+                       
+                       return ERROR_OK;
+               }
+               else
+               {
+                       buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, instruction.info.data_proc.Rd).value, 0, 32, Rd);
+                       WARNING("no updating of flags yet");
+
+                       if (instruction.info.data_proc.Rd == 15)  
+                               return ERROR_OK;
+               }
+       }
+       /* compare instructions (CMP, CMN, TST, TEQ) */
+       else if ((instruction.type >= ARM_TST) && (instruction.type <= ARM_CMN))
+       {
+               if (dry_run_pc)
+               {
+                       *dry_run_pc = current_pc + instruction_size;
+                       return ERROR_OK;
+               }
+               else
+               {
+                       WARNING("no updating of flags yet");
+               }
+       }
+       /* load register instructions */
+       else if ((instruction.type >= ARM_LDR) && (instruction.type <= ARM_LDRSH))
+       {
+               u32 load_address, modified_address, load_value;
+               u32 Rn = buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, instruction.info.load_store.Rn).value, 0, 32);
+               
+               /* adjust Rn in case the PC is being read */
+               if (instruction.info.load_store.Rn == 15)
+                       Rn += 2 * instruction_size;
+               
+               if (instruction.info.load_store.offset_mode == 0)
+               {
+                       if (instruction.info.load_store.U)
+                               modified_address = Rn + instruction.info.load_store.offset.offset;
+                       else
+                               modified_address = Rn - instruction.info.load_store.offset.offset;
+               }
+               else if (instruction.info.load_store.offset_mode == 1)
+               {
+                       u32 offset;
+                       u32 Rm = buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, instruction.info.load_store.offset.reg.Rm).value, 0, 32);
+                       u8 shift = instruction.info.load_store.offset.reg.shift;
+                       u8 shift_imm = instruction.info.load_store.offset.reg.shift_imm;
+                       u8 carry = buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 29, 1);
+                       
+                       offset = arm_shift(shift, Rm, shift_imm, &carry);
+                       
+                       if (instruction.info.load_store.U)
+                               modified_address = Rn + offset;
+                       else
+                               modified_address = Rn - offset;
+               }
+               else
+               {
+                       ERROR("BUG: offset_mode neither 0 (offset) nor 1 (scaled register)");
+               }
+               
+               if (instruction.info.load_store.index_mode == 0)
+               {
+                       /* offset mode
+                        * we load from the modified address, but don't change the base address register */
+                       load_address = modified_address;
+                       modified_address = Rn;
+               }
+               else if (instruction.info.load_store.index_mode == 1)
+               {
+                       /* pre-indexed mode
+                        * we load from the modified address, and write it back to the base address register */
+                       load_address = modified_address;
+               }
+               else if (instruction.info.load_store.index_mode == 2)
+               {
+                       /* post-indexed mode
+                        * we load from the unmodified address, and write the modified address back */
+                        load_address = Rn;
+               }
+               
+               target_read_u32(target, load_address, &load_value);
+               
+               if (dry_run_pc)
+               {
+                       if (instruction.info.load_store.Rd == 15)
+                       {
+                               *dry_run_pc = load_value;
+                               return ERROR_OK;
+                       }
+                       else
+                       {
+                               *dry_run_pc = current_pc + instruction_size;
+                       }
+                       
+                       return ERROR_OK;
+               }
+               else
+               {
+                       if ((instruction.info.load_store.index_mode == 1) ||
+                               (instruction.info.load_store.index_mode == 2))
+                       {
+                               buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, instruction.info.load_store.Rn).value, 0, 32, modified_address);
+                       } 
+                       buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, instruction.info.load_store.Rd).value, 0, 32, load_value);
+                       
+                       if (instruction.info.load_store.Rd == 15)
+                               return ERROR_OK;
+               }
+       }
+       /* load multiple instruction */
+       else if (instruction.type == ARM_LDM)
+       {
+               int i;
+               u32 Rn = buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, instruction.info.load_store_multiple.Rn).value, 0, 32);
+               u32 load_values[16];
+               int bits_set = 0;
+
+               for (i = 0; i < 16; i++)
+               {
+                       if (instruction.info.load_store_multiple.register_list & (1 << i))
+                               bits_set++;
+               }
+               
+               switch (instruction.info.load_store_multiple.addressing_mode)
+               {
+                       case 0: /* Increment after */
+                               Rn = Rn;
+                               break;
+                       case 1: /* Increment before */
+                               Rn = Rn + 4;
+                               break;
+                       case 2: /* Decrement after */
+                               Rn = Rn - (bits_set * 4) + 4; 
+                               break;
+                       case 3: /* Decrement before */
+                               Rn = Rn - (bits_set * 4);
+                               break;
+               }
+
+               for (i = 0; i < 16; i++)
+               {
+                       if (instruction.info.load_store_multiple.register_list & (1 << i))
+                       {
+                               target_read_u32(target, Rn, &load_values[i]);
+                               Rn += 4;
+                       }
+               }
+               
+               if (dry_run_pc)
+               {
+                       if (instruction.info.load_store_multiple.register_list & 0x8000)
+                       {
+                               *dry_run_pc = load_values[15];
+                               return ERROR_OK;
+                       }
+               }
+               else
+               {
+                       enum armv4_5_mode mode = armv4_5->core_mode;
+                       int update_cpsr = 0;
+
+                       if (instruction.info.load_store_multiple.S)
+                       {
+                               if (instruction.info.load_store_multiple.register_list & 0x8000)
+                                       update_cpsr = 1;
+                               else
+                                       mode = ARMV4_5_MODE_USR;
+                       }
+
+                       for (i = 0; i < 16; i++)
+                       {
+                               if (instruction.info.load_store_multiple.register_list & (1 << i))
+                               {
+                                       buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, mode, i).value, 0, 32, load_values[i]);
+                               }
+                       }
+                       
+                       if (update_cpsr)
+                       {
+                               u32 spsr = buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).value, 0, 32);
+                               buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32, spsr);
+                       }
+                       
+                       /* base register writeback */
+                       if (instruction.info.load_store_multiple.W)
+                               buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, instruction.info.load_store_multiple.Rn).value, 0, 32, Rn); 
+                       
+                       if (instruction.info.load_store_multiple.register_list & 0x8000)
+                               return ERROR_OK;
+               }
+       }
+       /* store multiple instruction */
+       else if (instruction.type == ARM_STM)
+       {
+               int i;
+
+               if (dry_run_pc)
+               {
+                       /* STM wont affect PC (advance by instruction size */
+               }
+               else
+               {
+                       u32 Rn = buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, instruction.info.load_store_multiple.Rn).value, 0, 32);
+                       int bits_set = 0;
+                       enum armv4_5_mode mode = armv4_5->core_mode;
+
+                       for (i = 0; i < 16; i++)
+                       {
+                               if (instruction.info.load_store_multiple.register_list & (1 << i))
+                                       bits_set++;
+                       }
+                       
+                       if (instruction.info.load_store_multiple.S)
+                       {
+                               mode = ARMV4_5_MODE_USR;
+                       }
+                       
+                       switch (instruction.info.load_store_multiple.addressing_mode)
+                       {
+                               case 0: /* Increment after */
+                                       Rn = Rn;
+                                       break;
+                               case 1: /* Increment before */
+                                       Rn = Rn + 4;
+                                       break;
+                               case 2: /* Decrement after */
+                                       Rn = Rn - (bits_set * 4) + 4; 
+                                       break;
+                               case 3: /* Decrement before */
+                                       Rn = Rn - (bits_set * 4);
+                                       break;
+                       }
+                       
+                       for (i = 0; i < 16; i++)
+                       {
+                               if (instruction.info.load_store_multiple.register_list & (1 << i))
+                               {
+                                       target_write_u32(target, Rn, buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i).value, 0, 32));
+                                       Rn += 4;
+                               }
+                       }
+                       
+                       /* base register writeback */
+                       if (instruction.info.load_store_multiple.W)
+                               buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, instruction.info.load_store_multiple.Rn).value, 0, 32, Rn); 
+                       
+               }
+       }
+       else if (!dry_run_pc)
+       {
+               /* the instruction wasn't handled, but we're supposed to simulate it
+                */
+               return ERROR_ARM_SIMULATOR_NOT_IMPLEMENTED;
+       }
+       
+       if (dry_run_pc)
+       {
+               *dry_run_pc = current_pc + instruction_size;
+               return ERROR_OK;
+       }
+       else
+       {
+               buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, current_pc + instruction_size);
+               return ERROR_OK;
+       }
+       
+}
diff --git a/src/target/arm_simulator.h b/src/target/arm_simulator.h
new file mode 100644 (file)
index 0000000..9c28a08
--- /dev/null
@@ -0,0 +1,31 @@
+/***************************************************************************
+ *   Copyright (C) 2006 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+#ifndef ARM_SIMULATOR_H
+#define ARM_SIMULATOR_H
+
+#include "target.h"
+#include "types.h"
+
+extern int arm_simulate_step(target_t *target, u32 *dry_run_pc);
+
+
+#define ERROR_ARM_SIMULATOR_NOT_IMPLEMENTED    (-1000)
+
+#endif /* ARM_SIMULATOR_H */
index 3eab03354bc6ceb3386f5a74d4aad0ef9fe1a27f..dc42d1c028c7b5aa91e0cb642d6f3a4d471d6524 100644 (file)
@@ -442,7 +442,7 @@ int handle_armv4_5_disassemble_command(struct command_context_s *cmd_ctx, char *
        for (i = 0; i < count; i++)
        {
                target_read_u32(target, address, &opcode);
-               evaluate_opcode(opcode, address, &cur_instruction);
+               arm_evaluate_opcode(opcode, address, &cur_instruction);
                command_print(cmd_ctx, "%s", cur_instruction.text);
                address += (thumb) ? 2 : 4;
        }
@@ -598,6 +598,13 @@ int armv4_5_run_algorithm(struct target_s *target, int num_mem_params, mem_param
                }
        }
        
+       if ((retval != ERROR_TARGET_TIMEOUT) && 
+               (buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32) != exit_point))
+       {
+               WARNING("target reentered debug state, but not at the desired exit point: 0x%4.4x",
+                       buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); 
+       }
+       
        breakpoint_remove(target, exit_point);
        
        for (i = 0; i < num_mem_params; i++)
index 47996de4f0f243d413d3d99fda793baee9181901..0ba94ff7cbe5c79932ff1f4c6d55e7b5b47a0c97 100644 (file)
@@ -213,6 +213,11 @@ extern int armv4_5_invalidate_core_regs(target_t *target);
  */
 #define ARMV4_5_MCR(CP, op1, Rd, CRn, CRm, op2) (0xee000010 | (CRm) | ((op2) << 5) | ((CP) << 8) | ((Rd) << 12) | ((CRn) << 16) | ((op1) << 21)) 
 
+/* Breakpoint instruction (ARMv5)
+ * Im: 16-bit immediate
+ */
+#define ARMV5_BKPT(Im) (0xe1200070 | ((Im & 0xfff0) << 8) | (Im & 0xf))
+
 
 /* Thumb mode instructions
  */
@@ -266,4 +271,9 @@ extern int armv4_5_invalidate_core_regs(target_t *target);
  */
 #define ARMV4_5_T_B(Imm)       ((0xe000 | (Imm)) | ((0xe000 | (Imm)) << 16))
 
+/* Breakpoint instruction (ARMv5) (Thumb state)
+ * Im: 8-bit immediate
+ */
+#define ARMV5_T_BKPT(Im) ((0xbe00 | Im) | ((0xbe00 | Im) << 16))
+
 #endif /* ARMV4_5_H */
index 376fc52f5ffd1d54182b33bbbe378e20ef0fdffc..548ea0c39c529ae3049f83ae9e9216e5c137afd3 100644 (file)
@@ -79,6 +79,7 @@ extern target_type_t arm9tdmi_target;
 extern target_type_t arm920t_target;
 extern target_type_t arm966e_target;
 extern target_type_t arm926ejs_target;
+extern target_type_t xscale_target;
 
 target_type_t *target_types[] =
 {
@@ -88,6 +89,7 @@ target_type_t *target_types[] =
        &arm720t_target,
        &arm966e_target,
        &arm926ejs_target,
+       &xscale_target,
        NULL,
 };
 
@@ -727,60 +729,107 @@ int target_read_buffer(struct target_s *target, u32 address, u32 size, u8 *buffe
        return ERROR_OK;
 }
 
-void target_read_u32(struct target_s *target, u32 address, u32 *value)
+int target_read_u32(struct target_s *target, u32 address, u32 *value)
 {
        u8 value_buf[4];
+
+       int retval = target->type->read_memory(target, address, 4, 1, value_buf);
        
-       target->type->read_memory(target, address, 4, 1, value_buf);
+       if (retval == ERROR_OK)
+       {
+               *value = target_buffer_get_u32(target, value_buf);
+               DEBUG("address: 0x%8.8x, value: 0x%8.8x", address, *value);
+       }
+       else
+       {
+               *value = 0x0;
+               DEBUG("address: 0x%8.8x failed", address);
+       }
        
-       *value = target_buffer_get_u32(target, value_buf);
-
-       DEBUG("address: 0x%8.8x, value: 0x%8.8x", address, *value);
+       return retval;
 }
 
-void target_read_u16(struct target_s *target, u32 address, u16 *value)
+int target_read_u16(struct target_s *target, u32 address, u16 *value)
 {
        u8 value_buf[2];
        
-       target->type->read_memory(target, address, 2, 1, value_buf);
+       int retval = target->type->read_memory(target, address, 2, 1, value_buf);
        
-       *value = target_buffer_get_u16(target, value_buf);
-
-       DEBUG("address: 0x%8.8x, value: 0x%4.4x", address, *value);
+       if (retval == ERROR_OK)
+       {
+               *value = target_buffer_get_u16(target, value_buf);
+               DEBUG("address: 0x%8.8x, value: 0x%4.4x", address, *value);
+       }
+       else
+       {
+               *value = 0x0;
+               DEBUG("address: 0x%8.8x failed", address);
+       }
+       
+       return retval;
 }
 
-void target_read_u8(struct target_s *target, u32 address, u8 *value)
+int target_read_u8(struct target_s *target, u32 address, u8 *value)
 {
-       target->type->read_memory(target, address, 1, 1, value);
+       int retval = target->type->read_memory(target, address, 1, 1, value);
 
-       DEBUG("address: 0x%8.8x, value: 0x%2.2x", address, *value);
+       if (retval == ERROR_OK)
+       {
+               DEBUG("address: 0x%8.8x, value: 0x%2.2x", address, *value);
+       }
+       else
+       {
+               *value = 0x0;
+               DEBUG("address: 0x%8.8x failed", address);
+       }
+       
+       return retval;
 }
 
-void target_write_u32(struct target_s *target, u32 address, u32 value)
+int target_write_u32(struct target_s *target, u32 address, u32 value)
 {
+       int retval;
        u8 value_buf[4];
 
        DEBUG("address: 0x%8.8x, value: 0x%8.8x", address, value);
 
        target_buffer_set_u32(target, value_buf, value);        
-       target->type->write_memory(target, address, 4, 1, value_buf);
+       if ((retval = target->type->write_memory(target, address, 4, 1, value_buf)) != ERROR_OK)
+       {
+               DEBUG("failed: %i", retval);
+       }
+       
+       return retval;
 }
 
-void target_write_u16(struct target_s *target, u32 address, u16 value)
+int target_write_u16(struct target_s *target, u32 address, u16 value)
 {
+       int retval;
        u8 value_buf[2];
        
        DEBUG("address: 0x%8.8x, value: 0x%8.8x", address, value);
 
        target_buffer_set_u16(target, value_buf, value);        
-       target->type->write_memory(target, address, 2, 1, value_buf);
+       if ((retval = target->type->write_memory(target, address, 2, 1, value_buf)) != ERROR_OK)
+       {
+               DEBUG("failed: %i", retval);
+       }
+       
+       return retval;
 }
 
-void target_write_u8(struct target_s *target, u32 address, u8 value)
+int target_write_u8(struct target_s *target, u32 address, u8 value)
 {
+       int retval;
+       
        DEBUG("address: 0x%8.8x, value: 0x%2.2x", address, value);
 
-       target->type->read_memory(target, address, 1, 1, &value);
+       if ((retval = target->type->read_memory(target, address, 1, 1, &value)) != ERROR_OK)
+       {
+               DEBUG("failed: %i", retval);
+       }
+       
+       return retval;
 }
 
 int target_register_user_commands(struct command_context_s *cmd_ctx)
index 04157fde1e22139feecd155ebc52e72a709be18f..d340a77800d650fa9852746d59440f67396bafe8 100644 (file)
@@ -50,6 +50,8 @@ enum daemon_startup_mode
        DAEMON_RESET,           /* reset target (behaviour defined by reset_mode */
 };
 
+extern enum daemon_startup_mode startup_mode;
+
 enum target_reset_mode
 {
        RESET_RUN = 0,          /* reset and let target run */
@@ -222,12 +224,12 @@ extern u16 target_buffer_get_u16(target_t *target, u8 *buffer);
 extern void target_buffer_set_u32(target_t *target, u8 *buffer, u32 value);
 extern void target_buffer_set_u16(target_t *target, u8 *buffer, u16 value);
 
-void target_read_u32(struct target_s *target, u32 address, u32 *value);
-void target_read_u16(struct target_s *target, u32 address, u16 *value);
-void target_read_u8(struct target_s *target, u32 address, u8 *value);
-void target_write_u32(struct target_s *target, u32 address, u32 value);
-void target_write_u16(struct target_s *target, u32 address, u16 value);
-void target_write_u8(struct target_s *target, u32 address, u8 value);
+int target_read_u32(struct target_s *target, u32 address, u32 *value);
+int target_read_u16(struct target_s *target, u32 address, u16 *value);
+int target_read_u8(struct target_s *target, u32 address, u8 *value);
+int target_write_u32(struct target_s *target, u32 address, u32 value);
+int target_write_u16(struct target_s *target, u32 address, u16 value);
+int target_write_u8(struct target_s *target, u32 address, u8 value);
 
 #define ERROR_TARGET_INVALID   (-300)
 #define ERROR_TARGET_INIT_FAILED (-301)
diff --git a/src/target/xscale.c b/src/target/xscale.c
new file mode 100644 (file)
index 0000000..d6c9f21
--- /dev/null
@@ -0,0 +1,3175 @@
+/***************************************************************************
+ *   Copyright (C) 2006 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   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 "config.h"
+
+#include "xscale.h"
+
+#include "register.h"
+#include "target.h"
+#include "armv4_5.h"
+#include "arm_simulator.h"
+#include "log.h"
+#include "jtag.h"
+#include "binarybuffer.h"
+#include "time_support.h"
+#include "breakpoints.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+/* cli handling */
+int xscale_register_commands(struct command_context_s *cmd_ctx);
+
+/* forward declarations */
+int xscale_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target);
+int xscale_init_target(struct command_context_s *cmd_ctx, struct target_s *target);
+int xscale_quit();
+
+int xscale_arch_state(struct target_s *target, char *buf, int buf_size);
+enum target_state xscale_poll(target_t *target);
+int xscale_halt(target_t *target);
+int xscale_resume(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution);
+int xscale_step(struct target_s *target, int current, u32 address, int handle_breakpoints);
+int xscale_debug_entry(target_t *target);
+int xscale_restore_context(target_t *target);
+
+int xscale_assert_reset(target_t *target);
+int xscale_deassert_reset(target_t *target);
+int xscale_soft_reset_halt(struct target_s *target);
+
+int xscale_set_reg_u32(reg_t *reg, u32 value);
+
+int xscale_read_core_reg(struct target_s *target, int num, enum armv4_5_mode mode);
+int xscale_write_core_reg(struct target_s *target, int num, enum armv4_5_mode mode, u32 value);
+
+int xscale_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
+int xscale_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
+int xscale_bulk_write_memory(target_t *target, u32 address, u32 count, u8 *buffer);
+
+int xscale_add_breakpoint(struct target_s *target, breakpoint_t *breakpoint);
+int xscale_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint);
+int xscale_set_breakpoint(struct target_s *target, breakpoint_t *breakpoint);
+int xscale_unset_breakpoint(struct target_s *target, breakpoint_t *breakpoint);
+int xscale_add_watchpoint(struct target_s *target, watchpoint_t *watchpoint);
+int xscale_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint);
+void xscale_enable_watchpoints(struct target_s *target);
+void xscale_enable_breakpoints(struct target_s *target);
+
+target_type_t xscale_target =
+{
+       .name = "xscale",
+
+       .poll = xscale_poll,
+       .arch_state = xscale_arch_state,
+
+       .halt = xscale_halt,
+       .resume = xscale_resume,
+       .step = xscale_step,
+
+       .assert_reset = xscale_assert_reset,
+       .deassert_reset = xscale_deassert_reset,
+       .soft_reset_halt = xscale_soft_reset_halt,
+
+       .get_gdb_reg_list = armv4_5_get_gdb_reg_list,
+       
+       .read_memory = xscale_read_memory,
+       .write_memory = xscale_write_memory,
+       .bulk_write_memory = xscale_bulk_write_memory,
+
+       .run_algorithm = armv4_5_run_algorithm,
+       
+       .add_breakpoint = xscale_add_breakpoint,
+       .remove_breakpoint = xscale_remove_breakpoint,
+       .add_watchpoint = xscale_add_watchpoint,
+       .remove_watchpoint = xscale_remove_watchpoint,
+
+       .register_commands = xscale_register_commands,
+       .target_command = xscale_target_command,
+       .init_target = xscale_init_target,
+       .quit = xscale_quit
+};
+
+char* xscale_reg_list[] =
+{
+       "XSCALE_MAINID",                /* 0 */
+       "XSCALE_CACHETYPE",
+       "XSCALE_CTRL",
+       "XSCALE_AUXCTRL",
+       "XSCALE_TTB",
+       "XSCALE_DAC",
+       "XSCALE_FSR",
+       "XSCALE_FAR",
+       "XSCALE_PID",
+       "XSCALE_CPACCESS",
+       "XSCALE_IBCR0",                 /* 10 */
+       "XSCALE_IBCR1",
+       "XSCALE_DBR0",
+       "XSCALE_DBR1",
+       "XSCALE_DBCON",
+       "XSCALE_TBREG",
+       "XSCALE_CHKPT0",                
+       "XSCALE_CHKPT1",
+       "XSCALE_DCSR",
+       "XSCALE_TX",
+       "XSCALE_RX",                    /* 20 */
+       "XSCALE_TXRXCTRL",
+};
+
+xscale_reg_t xscale_reg_arch_info[] =
+{
+       {XSCALE_MAINID, NULL},
+       {XSCALE_CACHETYPE, NULL},
+       {XSCALE_CTRL, NULL},
+       {XSCALE_AUXCTRL, NULL},
+       {XSCALE_TTB, NULL},
+       {XSCALE_DAC, NULL},
+       {XSCALE_FSR, NULL},
+       {XSCALE_FAR, NULL},
+       {XSCALE_PID, NULL},
+       {XSCALE_CPACCESS, NULL},
+       {XSCALE_IBCR0, NULL},
+       {XSCALE_IBCR1, NULL},
+       {XSCALE_DBR0, NULL},
+       {XSCALE_DBR1, NULL},
+       {XSCALE_DBCON, NULL},
+       {XSCALE_TBREG, NULL},
+       {XSCALE_CHKPT0, NULL},
+       {XSCALE_CHKPT1, NULL},
+       {XSCALE_DCSR, NULL}, /* DCSR accessed via JTAG or SW */
+       {-1, NULL}, /* TX accessed via JTAG */
+       {-1, NULL}, /* RX accessed via JTAG */
+       {-1, NULL}, /* TXRXCTRL implicit access via JTAG */
+};
+
+int xscale_reg_arch_type = -1;
+
+int xscale_get_reg(reg_t *reg);
+int xscale_set_reg(reg_t *reg, u8 *buf);
+
+int xscale_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, xscale_common_t **xscale_p)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       
+       if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
+       {
+               return -1;
+       }
+       
+       if (xscale->common_magic != XSCALE_COMMON_MAGIC)
+       {
+               return -1;
+       }
+       
+       *armv4_5_p = armv4_5;
+       *xscale_p = xscale;
+       
+       return ERROR_OK;
+}
+
+int xscale_jtag_set_instr(int chain_pos, u32 new_instr)
+{
+       jtag_device_t *device = jtag_get_device(chain_pos);
+       
+       if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr)
+       {
+               scan_field_t field;
+       
+               field.device = chain_pos;
+               field.num_bits = device->ir_length;
+               field.out_value = calloc(CEIL(field.num_bits, 8), 1);
+               buf_set_u32(field.out_value, 0, field.num_bits, new_instr);
+               field.out_mask = NULL;
+               field.in_value = NULL;
+               field.in_check_value = device->expected;
+               field.in_check_mask = device->expected_mask;
+               field.in_handler = NULL;
+               field.in_handler_priv = NULL;
+               
+               jtag_add_ir_scan(1, &field, -1);
+               
+               free(field.out_value);
+       }
+       
+       return ERROR_OK;
+}
+
+int xscale_jtag_callback(enum jtag_event event, void *priv)
+{
+       switch (event)
+       {
+               case JTAG_TRST_ASSERTED:
+                       break;
+               case JTAG_TRST_RELEASED:
+                       break;
+               case JTAG_SRST_ASSERTED:
+                       break;
+               case JTAG_SRST_RELEASED:
+                       break;
+               default:
+                       WARNING("unhandled JTAG event");
+       }
+       
+       return ERROR_OK;
+}
+
+int xscale_read_dcsr(target_t *target)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       
+       int retval;
+       
+       scan_field_t fields[3];
+       u8 field0 = 0x0;
+       u8 field0_check_value = 0x2;
+       u8 field0_check_mask = 0x7;
+       u8 field2 = 0x0;
+       u8 field2_check_value = 0x0;
+       u8 field2_check_mask = 0x1;
+
+       jtag_add_end_state(TAP_PD);
+       xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dcsr);
+       
+       buf_set_u32(&field0, 1, 1, xscale->hold_rst);
+       buf_set_u32(&field0, 2, 1, xscale->external_debug_break);
+       
+       fields[0].device = xscale->jtag_info.chain_pos;
+       fields[0].num_bits = 3;
+       fields[0].out_value = &field0;
+       fields[0].out_mask = NULL;
+       fields[0].in_value = NULL;
+       fields[0].in_check_value = &field0_check_value;
+       fields[0].in_check_mask = &field0_check_mask;
+       fields[0].in_handler = NULL;
+       fields[0].in_handler_priv = NULL;
+               
+       fields[1].device = xscale->jtag_info.chain_pos;
+       fields[1].num_bits = 32;
+       fields[1].out_value = NULL;
+       fields[1].out_mask = NULL;
+       fields[1].in_value = xscale->reg_cache->reg_list[XSCALE_DCSR].value;
+       fields[1].in_handler = NULL;
+       fields[1].in_handler_priv = NULL;
+       fields[1].in_check_value = NULL;
+       fields[1].in_check_mask = NULL;
+
+       fields[2].device = xscale->jtag_info.chain_pos;
+       fields[2].num_bits = 1;
+       fields[2].out_value = &field2;
+       fields[2].out_mask = NULL;
+       fields[2].in_value = NULL;
+       fields[2].in_check_value = &field2_check_value;
+       fields[2].in_check_mask = &field2_check_mask;
+       fields[2].in_handler = NULL;
+       fields[2].in_handler_priv = NULL;
+       
+       jtag_add_dr_scan(3, fields, -1);
+
+       if ((retval = jtag_execute_queue()) != ERROR_OK)
+       {
+               ERROR("JTAG error while reading DCSR");
+               exit(-1);
+       }
+       
+       xscale->reg_cache->reg_list[XSCALE_DCSR].dirty = 0;
+       xscale->reg_cache->reg_list[XSCALE_DCSR].valid = 1;
+       
+       /* write the register with the value we just read
+        * on this second pass, only the first bit of field0 is guaranteed to be 0)
+        */
+       field0_check_mask = 0x1;
+       fields[1].out_value = xscale->reg_cache->reg_list[XSCALE_DCSR].value;
+       fields[1].in_value = NULL;
+       
+       jtag_add_end_state(TAP_RTI);
+       
+       jtag_add_dr_scan(3, fields, -1);
+       
+       return ERROR_OK;
+}
+
+int xscale_receive(target_t *target, u32 *buffer, int num_words)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       
+       enum tap_state path[3];
+       scan_field_t fields[3];
+       
+       u8 *field0 = malloc(num_words * 1);
+       u8 field0_check_value = 0x2;
+       u8 field0_check_mask = 0x6;
+       u32 *field1 = malloc(num_words * 4);
+       u8 field2_check_value = 0x0;
+       u8 field2_check_mask = 0x1;
+       int words_done = 0;
+       int words_scheduled = 0;
+       
+       int i;
+       int retval;
+
+       path[0] = TAP_SDS;
+       path[1] = TAP_CD;
+       path[2] = TAP_SD;
+       
+       fields[0].device = xscale->jtag_info.chain_pos;
+       fields[0].num_bits = 3;
+       fields[0].out_value = NULL;
+       fields[0].out_mask = NULL;
+       /* fields[0].in_value = field0; */
+       fields[0].in_check_value = &field0_check_value;
+       fields[0].in_check_mask = &field0_check_mask;
+       fields[0].in_handler = NULL;
+       fields[0].in_handler_priv = NULL;
+               
+       fields[1].device = xscale->jtag_info.chain_pos;
+       fields[1].num_bits = 32;
+       fields[1].out_value = NULL;
+       fields[1].out_mask = NULL;
+       fields[1].in_value = NULL;
+       fields[1].in_handler = NULL;
+       fields[1].in_handler_priv = NULL;
+       fields[1].in_check_value = NULL;
+       fields[1].in_check_mask = NULL;
+
+       fields[2].device = xscale->jtag_info.chain_pos;
+       fields[2].num_bits = 1;
+       fields[2].out_value = NULL;
+       fields[2].out_mask = NULL;
+       fields[2].in_value = NULL;
+       fields[2].in_check_value = &field2_check_value;
+       fields[2].in_check_mask = &field2_check_mask;
+       fields[2].in_handler = NULL;
+       fields[2].in_handler_priv = NULL;
+
+       jtag_add_end_state(TAP_RTI);
+       xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dbgtx);
+       jtag_add_runtest(1, -1);
+       
+       /* repeat until all words have been collected */
+       while (words_done < num_words)
+       {
+               /* schedule reads */
+               words_scheduled = 0;
+               for (i = words_done; i < num_words; i++)
+               {
+                       fields[0].in_value = &field0[i];
+                       fields[1].in_handler = buf_to_u32_handler;
+                       fields[1].in_handler_priv = (u8*)&field1[i];
+                       
+                       jtag_add_pathmove(3, path);
+                       jtag_add_dr_scan(3, fields, TAP_RTI);
+                       words_scheduled++;
+               }
+               
+               if ((retval = jtag_execute_queue()) != ERROR_OK)
+               {
+                       ERROR("JTAG error while receiving data from debug handler");
+                       exit(-1);
+               }
+               
+               /* examine results */
+               for (i = words_done; i < num_words; i++)
+               {
+                       if (!(field0[0] & 1))
+                       {
+                               /* move backwards if necessary */
+                               int j;
+                               for (j = i; j < num_words - 1; j++)
+                               {
+                                       field0[j] = field0[j+1];
+                                       field1[j] = field1[j+1];
+                               }
+                               words_scheduled--;
+                       }
+               }
+               words_done += words_scheduled;
+       }
+       
+       for (i = 0; i < num_words; i++)
+               *(buffer++) = buf_get_u32((u8*)&field1[i], 0, 32);
+       
+       free(field1);
+       
+       return ERROR_OK;
+}
+
+int xscale_read_tx(target_t *target, int consume)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       enum tap_state path[3];
+       
+       int retval;
+       struct timeval timeout, now;
+       
+       scan_field_t fields[3];
+       u8 field0_in = 0x0;
+       u8 field0_check_value = 0x2;
+       u8 field0_check_mask = 0x6;
+       u8 field2_check_value = 0x0;
+       u8 field2_check_mask = 0x1;
+       
+       jtag_add_end_state(TAP_RTI);
+       
+       xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dbgtx);
+       
+       path[0] = TAP_SDS;
+       path[1] = TAP_CD;
+       path[2] = TAP_SD;
+       
+       fields[0].device = xscale->jtag_info.chain_pos;
+       fields[0].num_bits = 3;
+       fields[0].out_value = NULL;
+       fields[0].out_mask = NULL;
+       fields[0].in_value = &field0_in;
+       fields[0].in_check_value = &field0_check_value;
+       fields[0].in_check_mask = &field0_check_mask;
+       fields[0].in_handler = NULL;
+       fields[0].in_handler_priv = NULL;
+               
+       fields[1].device = xscale->jtag_info.chain_pos;
+       fields[1].num_bits = 32;
+       fields[1].out_value = NULL;
+       fields[1].out_mask = NULL;
+       fields[1].in_value = xscale->reg_cache->reg_list[XSCALE_TX].value;
+       fields[1].in_handler = NULL;
+       fields[1].in_handler_priv = NULL;
+       fields[1].in_check_value = NULL;
+       fields[1].in_check_mask = NULL;
+
+       fields[2].device = xscale->jtag_info.chain_pos;
+       fields[2].num_bits = 1;
+       fields[2].out_value = NULL;
+       fields[2].out_mask = NULL;
+       fields[2].in_value = NULL;
+       fields[2].in_check_value = &field2_check_value;
+       fields[2].in_check_mask = &field2_check_mask;
+       fields[2].in_handler = NULL;
+       fields[2].in_handler_priv = NULL;
+       
+       gettimeofday(&timeout, NULL);
+       timeval_add_time(&timeout, 5, 0);
+       
+       do
+       {
+               /* if we want to consume the register content (i.e. clear TX_READY),
+                * we have to go straight from Capture-DR to Shift-DR
+                * otherwise, we go from Capture-DR to Exit1-DR to Pause-DR
+               */
+               if (consume)
+                       jtag_add_pathmove(3, path);
+               else
+                       jtag_add_statemove(TAP_PD);
+               
+               jtag_add_dr_scan(3, fields, TAP_RTI);
+       
+               if ((retval = jtag_execute_queue()) != ERROR_OK)
+               {
+                       ERROR("JTAG error while reading TX");
+                       exit(-1);
+               }
+               
+               gettimeofday(&now, NULL);
+               if ((now.tv_sec > timeout.tv_sec) && (now.tv_usec > timeout.tv_usec))
+               {
+                       ERROR("time out reading TX register");
+                       return ERROR_TARGET_TIMEOUT;
+               }
+       } while ((!(field0_in & 1)) && consume);
+       
+       if (!(field0_in & 1))
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               
+       return ERROR_OK;
+}
+
+int xscale_write_rx(target_t *target)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       
+       int retval;
+       struct timeval timeout, now;
+       
+       scan_field_t fields[3];
+       u8 field0_out = 0x0;
+       u8 field0_in = 0x0;
+       u8 field0_check_value = 0x2;
+       u8 field0_check_mask = 0x6;
+       u8 field2 = 0x0;
+       u8 field2_check_value = 0x0;
+       u8 field2_check_mask = 0x1;
+       
+       jtag_add_end_state(TAP_RTI);
+       
+       xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dbgrx);
+       
+       fields[0].device = xscale->jtag_info.chain_pos;
+       fields[0].num_bits = 3;
+       fields[0].out_value = &field0_out;
+       fields[0].out_mask = NULL;
+       fields[0].in_value = &field0_in;
+       fields[0].in_check_value = &field0_check_value;
+       fields[0].in_check_mask = &field0_check_mask;
+       fields[0].in_handler = NULL;
+       fields[0].in_handler_priv = NULL;
+               
+       fields[1].device = xscale->jtag_info.chain_pos;
+       fields[1].num_bits = 32;
+       fields[1].out_value = xscale->reg_cache->reg_list[XSCALE_RX].value;
+       fields[1].out_mask = NULL;
+       fields[1].in_value = NULL;
+       fields[1].in_handler = NULL;
+       fields[1].in_handler_priv = NULL;
+       fields[1].in_check_value = NULL;
+       fields[1].in_check_mask = NULL;
+
+       fields[2].device = xscale->jtag_info.chain_pos;
+       fields[2].num_bits = 1;
+       fields[2].out_value = &field2;
+       fields[2].out_mask = NULL;
+       fields[2].in_value = NULL;
+       fields[2].in_check_value = &field2_check_value;
+       fields[2].in_check_mask = &field2_check_mask;
+       fields[2].in_handler = NULL;
+       fields[2].in_handler_priv = NULL;
+       
+       gettimeofday(&timeout, NULL);
+       timeval_add_time(&timeout, 5, 0);
+       
+       /* poll until rx_read is low */
+       do
+       {
+               DEBUG("polling RX");
+               jtag_add_dr_scan(3, fields, TAP_RTI);
+       
+               if ((retval = jtag_execute_queue()) != ERROR_OK)
+               {
+                       ERROR("JTAG error while writing RX");
+                       exit(-1);
+               }
+               
+               gettimeofday(&now, NULL);
+               if ((now.tv_sec > timeout.tv_sec) && (now.tv_usec > timeout.tv_usec))
+               {
+                       ERROR("time out writing RX register");
+                       return ERROR_TARGET_TIMEOUT;
+               }
+       } while (field0_in & 1);
+       
+       /* set rx_valid */
+       field2 = 0x1;
+       jtag_add_dr_scan(3, fields, TAP_RTI);
+       
+       if ((retval = jtag_execute_queue()) != ERROR_OK)
+       {
+               ERROR("JTAG error while writing RX");
+               exit(-1);
+       }
+       
+       return ERROR_OK;
+}
+
+/* send count elements of size byte to the debug handler */
+int xscale_send(target_t *target, u8 *buffer, int count, int size)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+               
+       int retval;
+       
+       int done_count = 0;
+       u8 output[4] = {0, 0, 0, 0};
+       
+       scan_field_t fields[3];
+       u8 field0_out = 0x0;
+       u8 field0_in = 0x0;
+       u8 field0_check_value = 0x2;
+       u8 field0_check_mask = 0x6;
+       u8 field2 = 0x1;
+       u8 field2_check_value = 0x0;
+       u8 field2_check_mask = 0x1;
+       
+       jtag_add_end_state(TAP_RTI);
+       
+       xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dbgrx);
+       
+       fields[0].device = xscale->jtag_info.chain_pos;
+       fields[0].num_bits = 3;
+       fields[0].out_value = &field0_out;
+       fields[0].out_mask = NULL;
+       fields[0].in_value = &field0_in;
+       fields[0].in_check_value = &field0_check_value;
+       fields[0].in_check_mask = &field0_check_mask;
+       fields[0].in_handler = NULL;
+       fields[0].in_handler_priv = NULL;
+               
+       fields[1].device = xscale->jtag_info.chain_pos;
+       fields[1].num_bits = 32;
+       fields[1].out_value = output;
+       fields[1].out_mask = NULL;
+       fields[1].in_value = NULL;
+       fields[1].in_handler = NULL;
+       fields[1].in_handler_priv = NULL;
+       fields[1].in_check_value = NULL;
+       fields[1].in_check_mask = NULL;
+
+       fields[2].device = xscale->jtag_info.chain_pos;
+       fields[2].num_bits = 1;
+       fields[2].out_value = &field2;
+       fields[2].out_mask = NULL;
+       fields[2].in_value = NULL;
+       fields[2].in_check_value = &field2_check_value;
+       fields[2].in_check_mask = &field2_check_mask;
+       fields[2].in_handler = NULL;
+       fields[2].in_handler_priv = NULL;
+       
+       while (done_count++ < count)
+       {
+               /* extract sized element from target-endian buffer, and put it 
+                * into little-endian output buffer
+                */
+               switch (size)
+               {
+                       case 4:
+                               buf_set_u32(output, 0, 32, target_buffer_get_u32(target, buffer));
+                               break;
+                       case 2:
+                               buf_set_u32(output, 0, 32, target_buffer_get_u16(target, buffer));
+                               break;
+                       case 1:
+                               output[0] = *buffer;
+                               break;
+                       default:
+                               ERROR("BUG: size neither 4, 2 nor 1");
+                               exit(-1); 
+               }
+
+               jtag_add_dr_scan(3, fields, TAP_RTI);
+               buffer += size;
+       }
+       
+       if ((retval = jtag_execute_queue()) != ERROR_OK)
+       {
+               ERROR("JTAG error while sending data to debug handler");
+               exit(-1);
+       }
+       
+       return ERROR_OK;
+}
+
+int xscale_send_u32(target_t *target, u32 value)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       
+       buf_set_u32(xscale->reg_cache->reg_list[XSCALE_RX].value, 0, 32, value);
+       return xscale_write_rx(target);
+}
+
+int xscale_write_dcsr(target_t *target, int hold_rst, int ext_dbg_brk)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       
+       int retval;
+       
+       scan_field_t fields[3];
+       u8 field0 = 0x0;
+       u8 field0_check_value = 0x2;
+       u8 field0_check_mask = 0x7;
+       u8 field2 = 0x0;
+       u8 field2_check_value = 0x0;
+       u8 field2_check_mask = 0x1;
+       
+       if (hold_rst != -1)
+               xscale->hold_rst = hold_rst;
+       
+       if (ext_dbg_brk != -1)
+               xscale->external_debug_break = ext_dbg_brk;
+
+       jtag_add_end_state(TAP_RTI);
+       xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dcsr);
+       
+       buf_set_u32(&field0, 1, 1, xscale->hold_rst);
+       buf_set_u32(&field0, 2, 1, xscale->external_debug_break);
+       
+       fields[0].device = xscale->jtag_info.chain_pos;
+       fields[0].num_bits = 3;
+       fields[0].out_value = &field0;
+       fields[0].out_mask = NULL;
+       fields[0].in_value = NULL;
+       fields[0].in_check_value = &field0_check_value;
+       fields[0].in_check_mask = &field0_check_mask;
+       fields[0].in_handler = NULL;
+       fields[0].in_handler_priv = NULL;
+               
+       fields[1].device = xscale->jtag_info.chain_pos;
+       fields[1].num_bits = 32;
+       fields[1].out_value = xscale->reg_cache->reg_list[XSCALE_DCSR].value;
+       fields[1].out_mask = NULL;
+       fields[1].in_value = NULL;
+       fields[1].in_handler = NULL;
+       fields[1].in_handler_priv = NULL;
+       fields[1].in_check_value = NULL;
+       fields[1].in_check_mask = NULL;
+
+       fields[2].device = xscale->jtag_info.chain_pos;
+       fields[2].num_bits = 1;
+       fields[2].out_value = &field2;
+       fields[2].out_mask = NULL;
+       fields[2].in_value = NULL;
+       fields[2].in_check_value = &field2_check_value;
+       fields[2].in_check_mask = &field2_check_mask;
+       fields[2].in_handler = NULL;
+       fields[2].in_handler_priv = NULL;
+       
+       jtag_add_dr_scan(3, fields, -1);
+       
+       if ((retval = jtag_execute_queue()) != ERROR_OK)
+       {
+               ERROR("JTAG error while writing DCSR");
+               exit(-1);
+       }
+       
+       xscale->reg_cache->reg_list[XSCALE_DCSR].dirty = 0;
+       xscale->reg_cache->reg_list[XSCALE_DCSR].valid = 1;
+       
+       return ERROR_OK;
+}
+
+/* parity of the number of bits 0 if even; 1 if odd. for 32 bit words */
+unsigned int parity (unsigned int v)
+{
+       unsigned int ov = v;
+       v ^= v >> 16;
+       v ^= v >> 8;
+       v ^= v >> 4;
+       v &= 0xf;
+       DEBUG("parity of 0x%x is %i", ov, (0x6996 >> v) & 1);
+       return (0x6996 >> v) & 1;
+}
+
+int xscale_load_ic(target_t *target, int mini, u32 va, u32 buffer[8])
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       u8 packet[4];
+       u8 cmd;
+       int word;
+       
+       scan_field_t fields[2];
+
+       DEBUG("loading miniIC at 0x%8.8x", va);
+
+       jtag_add_end_state(TAP_RTI);
+       xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.ldic); /* LDIC */
+       
+       /* CMD is b010 for Main IC and b011 for Mini IC */
+       if (mini)
+               buf_set_u32(&cmd, 0, 3, 0x3);
+       else
+               buf_set_u32(&cmd, 0, 3, 0x2);
+       
+       buf_set_u32(&cmd, 3, 3, 0x0);
+               
+       /* virtual address of desired cache line */
+       buf_set_u32(packet, 0, 27, va >> 5);
+       
+       fields[0].device = xscale->jtag_info.chain_pos;
+       fields[0].num_bits = 6;
+       fields[0].out_value = &cmd;
+       fields[0].out_mask = NULL;
+       fields[0].in_value = NULL;
+       fields[0].in_check_value = NULL;
+       fields[0].in_check_mask = NULL;
+       fields[0].in_handler = NULL;
+       fields[0].in_handler_priv = NULL;
+
+       fields[1].device = xscale->jtag_info.chain_pos;
+       fields[1].num_bits = 27;
+       fields[1].out_value = packet;
+       fields[1].out_mask = NULL;
+       fields[1].in_value = NULL;
+       fields[1].in_check_value = NULL;
+       fields[1].in_check_mask = NULL;
+       fields[1].in_handler = NULL;
+       fields[1].in_handler_priv = NULL;
+       
+       jtag_add_dr_scan(2, fields, -1);
+
+       fields[0].num_bits = 32;
+       fields[0].out_value = packet;
+       
+       fields[1].num_bits = 1;
+       fields[1].out_value = &cmd;
+       
+       for (word = 0; word < 8; word++)
+       {
+               buf_set_u32(packet, 0, 32, buffer[word]);
+               cmd = parity(*((u32*)packet));
+               jtag_add_dr_scan(2, fields, -1);
+       }
+       
+       jtag_execute_queue();
+       
+       return ERROR_OK;
+}
+
+int xscale_invalidate_ic_line(target_t *target, u32 va)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       u8 packet[4];
+       u8 cmd;
+       
+       scan_field_t fields[2];
+
+       jtag_add_end_state(TAP_RTI);
+       xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.ldic); /* LDIC */
+       
+       /* CMD for invalidate IC line b000, bits [6:4] b000 */
+       buf_set_u32(&cmd, 0, 6, 0x0);
+       
+       /* virtual address of desired cache line */
+       buf_set_u32(packet, 0, 27, va >> 5);
+       
+       fields[0].device = xscale->jtag_info.chain_pos;
+       fields[0].num_bits = 6;
+       fields[0].out_value = &cmd;
+       fields[0].out_mask = NULL;
+       fields[0].in_value = NULL;
+       fields[0].in_check_value = NULL;
+       fields[0].in_check_mask = NULL;
+       fields[0].in_handler = NULL;
+       fields[0].in_handler_priv = NULL;
+
+       fields[1].device = xscale->jtag_info.chain_pos;
+       fields[1].num_bits = 27;
+       fields[1].out_value = packet;
+       fields[1].out_mask = NULL;
+       fields[1].in_value = NULL;
+       fields[1].in_check_value = NULL;
+       fields[1].in_check_mask = NULL;
+       fields[1].in_handler = NULL;
+       fields[1].in_handler_priv = NULL;
+       
+       jtag_add_dr_scan(2, fields, -1);
+       
+       return ERROR_OK;
+}
+
+int xscale_update_vectors(target_t *target)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       int i;
+       
+       u32 low_reset_branch, high_reset_branch;
+
+       for (i = 1; i < 8; i++)
+       {
+               /* if there's a static vector specified for this exception, override */
+               if (xscale->static_high_vectors_set & (1 << i))
+               {
+                       xscale->high_vectors[i] = xscale->static_high_vectors[i];
+               }
+               else
+               {
+                       if (target_read_u32(target, 0xffff0000 + 4*i, &xscale->high_vectors[i]) != ERROR_OK)
+                       {
+                               xscale->high_vectors[i] = ARMV4_5_B(0xfffffe, 0);
+                       }
+               }
+       }
+
+       for (i = 1; i < 8; i++)
+       {
+               if (xscale->static_low_vectors_set & (1 << i))
+               {
+                       xscale->low_vectors[i] = xscale->static_low_vectors[i];
+               }
+               else
+               {
+                       if (target_read_u32(target, 0x0 + 4*i, &xscale->low_vectors[i]) != ERROR_OK)
+                       {
+                               xscale->low_vectors[i] = ARMV4_5_B(0xfffffe, 0);
+                       }
+               }
+       }
+       
+       /* calculate branches to debug handler */
+       low_reset_branch = (xscale->handler_address + 0x20 - 0x0 - 0x8) >> 2;
+       high_reset_branch = (xscale->handler_address + 0x20 - 0xffff0000 - 0x8) >> 2;
+       
+       xscale->low_vectors[0] = ARMV4_5_B((low_reset_branch & 0xffffff), 0);
+       xscale->high_vectors[0] = ARMV4_5_B((high_reset_branch & 0xffffff), 0);
+       
+       /* invalidate and load exception vectors in mini i-cache */
+       xscale_invalidate_ic_line(target, 0x0);
+       xscale_invalidate_ic_line(target, 0xffff0000);
+       
+       xscale_load_ic(target, 1, 0x0, xscale->low_vectors);
+       xscale_load_ic(target, 1, 0xffff0000, xscale->high_vectors);
+       
+       return ERROR_OK;
+}
+
+int xscale_arch_state(struct target_s *target, char *buf, int buf_size)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       
+       char *state[] = 
+       {
+               "disabled", "enabled"
+       };
+       
+       char *arch_dbg_reason[] =
+       {
+               "", "\n(processor reset)", "\n(trace buffer full)"
+       };
+       
+       if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
+       {
+               ERROR("BUG: called for a non-ARMv4/5 target");
+               exit(-1);
+       }
+       
+       snprintf(buf, buf_size,
+                       "target halted in %s state due to %s, current mode: %s\n"
+                       "cpsr: 0x%8.8x pc: 0x%8.8x\n"
+                       "MMU: %s, D-Cache: %s, I-Cache: %s"
+                       "%s",
+                        armv4_5_state_strings[armv4_5->core_state],
+                        target_debug_reason_strings[target->debug_reason],
+                        armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)],
+                        buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32),
+                        buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32),
+                        state[xscale->armv4_5_mmu.mmu_enabled],
+                        state[xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled], 
+                        state[xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled],
+                        arch_dbg_reason[xscale->arch_debug_reason]);
+       
+       return ERROR_OK;
+}
+
+enum target_state xscale_poll(target_t *target)
+{
+       int retval;
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       
+       if ((target->state == TARGET_RUNNING) || (target->state == TARGET_DEBUG_RUNNING))
+       {
+               if ((retval = xscale_read_tx(target, 0)) == ERROR_OK)
+               {
+                       /* there's data to read from the tx register, we entered debug state */
+                       xscale->handler_running = 1;
+                       
+                       /* process debug entry, fetching current mode regs */
+                       if ((retval = xscale_debug_entry(target)) != ERROR_OK)
+                               return retval;
+                       
+                       /* if target was running, signal that we halted
+                        * otherwise we reentered from debug execution */
+                       if (target->state == TARGET_RUNNING)
+                               target_call_event_callbacks(target, TARGET_EVENT_HALTED);
+                       else
+                               target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
+
+                       target->state = TARGET_HALTED;
+               }
+               else if (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
+               {
+                       ERROR("error while polling TX register");
+                       exit(-1);
+               }
+       }
+       
+       return target->state;
+}
+
+int xscale_debug_entry(target_t *target)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       u32 pc;
+       u32 *buffer = malloc(4 * 10);
+       int i;
+       
+       u32 moe;
+       
+       /* clear external dbg break (will be written on next DCSR read) */
+       xscale->external_debug_break = 0;
+       xscale_read_dcsr(target);
+       
+       /* get r0, pc, r1 to r7 and cpsr */
+       xscale_receive(target, buffer, 10);
+       
+       /* move r0 from buffer to register cache */
+       buf_set_u32(armv4_5->core_cache->reg_list[0].value, 0, 32, buffer[0]);
+       armv4_5->core_cache->reg_list[15].dirty = 1;
+       armv4_5->core_cache->reg_list[15].valid = 1;
+       DEBUG("r0: 0x%8.8x", buffer[0]);
+       
+       /* move pc from buffer to register cache */
+       buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, buffer[1]);
+       armv4_5->core_cache->reg_list[15].dirty = 1;
+       armv4_5->core_cache->reg_list[15].valid = 1;
+       DEBUG("pc: 0x%8.8x", buffer[1]);
+       
+       /* move data from buffer to register cache */
+       for (i = 1; i <= 7; i++)
+       {
+               buf_set_u32(armv4_5->core_cache->reg_list[i].value, 0, 32, buffer[1 + i]);
+               armv4_5->core_cache->reg_list[i].dirty = 1;
+               armv4_5->core_cache->reg_list[i].valid = 1;
+               DEBUG("r%i: 0x%8.8x", i, buffer[i + 1]);
+       }
+       
+       buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32, buffer[9]);
+       armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1;
+       armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1;
+       DEBUG("cpsr: 0x%8.8x", buffer[9]);
+       
+       armv4_5->core_mode = buffer[9] & 0x1f;
+       if (armv4_5_mode_to_number(armv4_5->core_mode) == -1)
+       {
+               target->state = TARGET_UNKNOWN;
+               ERROR("cpsr contains invalid mode value - communication failure");
+               return ERROR_TARGET_FAILURE;
+       }
+       DEBUG("target entered debug state in %s mode", armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)]);
+       
+       if (buffer[9] & 0x20)
+               armv4_5->core_state = ARMV4_5_STATE_THUMB;
+       else
+               armv4_5->core_state = ARMV4_5_STATE_ARM;
+       
+       /* get banked registers, r8 to r14, and spsr if not in USR/SYS mode */
+       if ((armv4_5->core_mode != ARMV4_5_MODE_USR) && (armv4_5->core_mode != ARMV4_5_MODE_SYS))
+       {
+               xscale_receive(target, buffer, 8);
+               buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).value, 0, 32, buffer[7]);
+               ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).dirty = 0;
+               ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).valid = 1;
+       }
+       else
+       {
+               /* r8 to r14, but no spsr */
+               xscale_receive(target, buffer, 7);
+       }
+       
+       /* move data from buffer to register cache */
+       for (i = 8; i <= 14; i++)
+       {
+               buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i).value, 0, 32, buffer[i - 8]);
+               ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i).dirty = 0;
+               ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i).valid = 1;
+       }
+       
+       /* examine debug reason */
+       xscale_read_dcsr(target);
+       moe = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 2, 3);
+       
+       /* stored PC (for calculating fixup) */
+       pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32);
+       
+       switch (moe)
+       {
+               case 0x0: /* Processor reset */
+                       target->debug_reason = DBG_REASON_DBGRQ;
+                       xscale->arch_debug_reason = XSCALE_DBG_REASON_RESET;
+                       pc -= 4;
+                       break;
+               case 0x1: /* Instruction breakpoint hit */
+                       target->debug_reason = DBG_REASON_BREAKPOINT;
+                       xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC;
+                       pc -= 4;
+                       break;
+               case 0x2: /* Data breakpoint hit */
+                       target->debug_reason = DBG_REASON_WATCHPOINT;
+                       xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC;
+                       pc -= 4;
+                       break;
+               case 0x3: /* BKPT instruction executed */
+                       target->debug_reason = DBG_REASON_BREAKPOINT;
+                       xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC;
+                       pc -= 4;
+                       break;
+               case 0x4: /* Ext. debug event */
+                       target->debug_reason = DBG_REASON_DBGRQ;
+                       xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC;
+                       pc -= 4;
+                       break;
+               case 0x5: /* Vector trap occured */
+                       target->debug_reason = DBG_REASON_BREAKPOINT;
+                       xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC;
+                       pc -= 4;
+                       break;
+               case 0x6: /* Trace buffer full break */
+                       target->debug_reason = DBG_REASON_DBGRQ;
+                       xscale->arch_debug_reason = XSCALE_DBG_REASON_TB_FULL;
+                       pc -= 4;
+                       break;
+               case 0x7: /* Reserved */
+               default:
+                       ERROR("Method of Entry is 'Reserved'");
+                       exit(-1);
+                       break;
+       }
+       
+       /* apply PC fixup */
+       buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, pc); 
+       
+       /* on the first debug entry, identify cache type */
+       if (xscale->armv4_5_mmu.armv4_5_cache.ctype == -1)
+       {
+               u32 cache_type_reg;
+               
+               /* read cp15 cache type register */
+               xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CACHETYPE]);
+               cache_type_reg = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CACHETYPE].value, 0, 32);
+               
+               armv4_5_identify_cache(cache_type_reg, &xscale->armv4_5_mmu.armv4_5_cache);
+       }
+       
+       /* examine MMU and Cache settings */
+       /* read cp15 control register */
+       xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]);
+       xscale->cp15_control_reg = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32);
+       xscale->armv4_5_mmu.mmu_enabled = (xscale->cp15_control_reg & 0x1U) ? 1 : 0;
+       xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (xscale->cp15_control_reg & 0x4U) ? 1 : 0;
+       xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled = (xscale->cp15_control_reg & 0x1000U) ? 1 : 0;
+       
+       return ERROR_OK;
+}
+
+int xscale_halt(target_t *target)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       
+       DEBUG("target->state: %s", target_state_strings[target->state]);
+       
+       if (target->state == TARGET_HALTED)
+       {
+               WARNING("target was already halted");
+               return ERROR_TARGET_ALREADY_HALTED;
+       } 
+       else if (target->state == TARGET_UNKNOWN)
+       {
+               /* this must not happen for a xscale target */
+               ERROR("target was in unknown state when halt was requested");
+               exit(-1);
+       }
+       else if (target->state == TARGET_RESET)
+       {
+               DEBUG("target->state == TARGET_RESET");
+               
+               /* clear TRST */
+               jtag_add_reset(0, -1);
+       }
+       else
+       {
+               /* assert external dbg break */
+               xscale->external_debug_break = 1;
+               xscale_read_dcsr(target);
+       
+               target->debug_reason = DBG_REASON_DBGRQ;
+       }
+       
+       return ERROR_OK;
+}
+
+int xscale_enable_single_step(struct target_s *target, u32 next_pc)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale= armv4_5->arch_info;
+       reg_t *ibcr0 = &xscale->reg_cache->reg_list[XSCALE_IBCR0];
+       
+       if (xscale->ibcr0_used)
+       {
+               breakpoint_t *ibcr0_bp = breakpoint_find(target, buf_get_u32(ibcr0->value, 0, 32) & 0xfffffffe);
+               
+               if (ibcr0_bp)
+               {
+                       xscale_unset_breakpoint(target, ibcr0_bp);
+               }
+               else
+               {
+                       ERROR("BUG: xscale->ibcr0_used is set, but no breakpoint with that address found");
+                       exit(-1);
+               }
+       }
+       
+       xscale_set_reg_u32(ibcr0, next_pc | 0x1);
+       
+       return ERROR_OK;
+}
+
+int xscale_disable_single_step(struct target_s *target)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale= armv4_5->arch_info;
+       reg_t *ibcr0 = &xscale->reg_cache->reg_list[XSCALE_IBCR0];
+       
+       xscale_set_reg_u32(ibcr0, 0x0);
+       
+       return ERROR_OK;
+}
+
+int xscale_resume(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale= armv4_5->arch_info;
+       breakpoint_t *breakpoint = target->breakpoints;
+       
+       u32 current_pc;
+       
+       int retval;
+       int i;
+       
+       DEBUG("-");
+       
+       if (target->state != TARGET_HALTED)
+       {
+               WARNING("target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+       
+       if (!debug_execution)
+       {
+               target_free_all_working_areas(target);
+       }
+       
+       /* update vector tables */
+       xscale_update_vectors(target);
+       
+       /* current = 1: continue on current pc, otherwise continue at <address> */
+       if (!current)
+               buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, address);
+
+       current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32);
+       
+       /* if we're at the reset vector, we have to simulate the branch */
+       if (current_pc == 0x0)
+       {
+               arm_simulate_step(target, NULL);
+               current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32);
+       }
+       
+       /* the front-end may request us not to handle breakpoints */
+       if (handle_breakpoints)
+       {
+               if ((breakpoint = breakpoint_find(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32))))
+               {
+                       u32 next_pc;
+                       
+                       /* there's a breakpoint at the current PC, we have to step over it */
+                       DEBUG("unset breakpoint at 0x%8.8x", breakpoint->address);
+                       xscale_unset_breakpoint(target, breakpoint);
+                       
+                       /* calculate PC of next instruction */
+                       if ((retval = arm_simulate_step(target, &next_pc)) != ERROR_OK)
+                       {
+                               u32 current_opcode;
+                               target_read_u32(target, current_pc, &current_opcode);
+                               ERROR("BUG: couldn't calculate PC of next instruction, current opcode was 0x%8.8x", current_opcode);
+                       }
+                       
+                       DEBUG("enable single-step");
+                       xscale_enable_single_step(target, next_pc);
+                       
+                       /* restore banked registers */
+                       xscale_restore_context(target);
+                       
+                       /* send resume request (command 0x30 or 0x31)
+                        * clean the trace buffer if it is to be enabled (0x62) */
+                       if (xscale->trace_buffer_enabled)
+                       {
+                               xscale_send_u32(target, 0x62);
+                               xscale_send_u32(target, 0x31);
+                       }
+                       else
+                               xscale_send_u32(target, 0x30);
+                                                       
+                       /* send CPSR */
+                       xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32));
+                       DEBUG("writing cpsr with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32));
+                               
+                       for (i = 7; i >= 0; i--)
+                       {
+                               /* send register */
+                               xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32));
+                               DEBUG("writing r%i with value 0x%8.8x", i, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32));
+                       }
+
+                       /* send PC */
+                       xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32));
+                       DEBUG("writing PC with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32));
+                       
+                       /* wait for and process debug entry */
+                       xscale_debug_entry(target);
+                       
+                       DEBUG("disable single-step");
+                       xscale_disable_single_step(target);
+                       
+                       DEBUG("set breakpoint at 0x%8.8x", breakpoint->address);
+                       xscale_set_breakpoint(target, breakpoint);
+               }
+       }
+       
+       /* enable any pending breakpoints and watchpoints */
+       xscale_enable_breakpoints(target);
+       xscale_enable_watchpoints(target);
+       
+       /* restore banked registers */
+       xscale_restore_context(target);
+       
+       /* send resume request (command 0x30 or 0x31)
+        * clean the trace buffer if it is to be enabled (0x62) */
+       if (xscale->trace_buffer_enabled)
+       {
+               xscale_send_u32(target, 0x62);
+               xscale_send_u32(target, 0x31);
+       }
+       else
+               xscale_send_u32(target, 0x30);
+       
+       /* send CPSR */
+       xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32));
+       DEBUG("writing cpsr with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32));
+               
+       for (i = 7; i >= 0; i--)
+       {
+               /* send register */
+               xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32));
+               DEBUG("writing r%i with value 0x%8.8x", i, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32));
+       }
+
+       /* send PC */
+       xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32));
+       DEBUG("writing PC with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32));
+               
+       target->debug_reason = DBG_REASON_NOTHALTED;
+               
+       if (!debug_execution)
+       {
+               /* registers are now invalid */
+               armv4_5_invalidate_core_regs(target);
+               target->state = TARGET_RUNNING;
+               target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
+       }
+       else
+       {
+               target->state = TARGET_DEBUG_RUNNING;
+               target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED);
+       }
+       
+       DEBUG("target resumed");
+       
+       xscale->handler_running = 1;
+       
+       return ERROR_OK;
+}
+
+int xscale_step(struct target_s *target, int current, u32 address, int handle_breakpoints)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       breakpoint_t *breakpoint = target->breakpoints;
+       
+       u32 current_pc, next_pc;
+       int i;
+       int retval;
+
+       if (target->state != TARGET_HALTED)
+       {
+               WARNING("target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+       
+       /* current = 1: continue on current pc, otherwise continue at <address> */
+       if (!current)
+               buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, address);
+       
+       current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32);
+       
+       /* if we're at the reset vector, we have to simulate the step */
+       if (current_pc == 0x0)
+       {
+               arm_simulate_step(target, NULL);
+               current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32);
+               
+               target->debug_reason = DBG_REASON_SINGLESTEP;
+               target_call_event_callbacks(target, TARGET_EVENT_HALTED);
+               
+               return ERROR_OK;
+       }
+       
+       /* the front-end may request us not to handle breakpoints */
+       if (handle_breakpoints)
+               if ((breakpoint = breakpoint_find(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32))))
+               {
+                       xscale_unset_breakpoint(target, breakpoint);
+               }
+       
+       target->debug_reason = DBG_REASON_SINGLESTEP;
+
+       /* calculate PC of next instruction */
+       if ((retval = arm_simulate_step(target, &next_pc)) != ERROR_OK)
+       {
+               u32 current_opcode;
+               target_read_u32(target, current_pc, &current_opcode);
+               ERROR("BUG: couldn't calculate PC of next instruction, current opcode was 0x%8.8x", current_opcode);
+       }
+       
+       DEBUG("enable single-step");
+       xscale_enable_single_step(target, next_pc);
+       
+       /* restore banked registers */
+       xscale_restore_context(target);
+       
+       /* send resume request (command 0x30 or 0x31)
+        * clean the trace buffer if it is to be enabled (0x62) */
+       if (xscale->trace_buffer_enabled)
+       {
+               xscale_send_u32(target, 0x62);
+               xscale_send_u32(target, 0x31);
+       }
+       else
+               xscale_send_u32(target, 0x30);
+       
+       /* send CPSR */
+       xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32));
+       DEBUG("writing cpsr with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32));
+               
+       for (i = 7; i >= 0; i--)
+       {
+               /* send register */
+               xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32));
+               DEBUG("writing r%i with value 0x%8.8x", i, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32));
+       }
+
+       /* send PC */
+       xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32));
+       DEBUG("writing PC with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32));
+
+       target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
+
+       /* registers are now invalid */
+       armv4_5_invalidate_core_regs(target);
+       
+       /* wait for and process debug entry */
+       xscale_debug_entry(target);
+       
+       DEBUG("disable single-step");
+       xscale_disable_single_step(target);
+               
+       target_call_event_callbacks(target, TARGET_EVENT_HALTED);
+
+       if (breakpoint)
+       {
+               xscale_set_breakpoint(target, breakpoint);
+       }
+               
+       DEBUG("target stepped");
+
+       return ERROR_OK;
+
+}
+
+int xscale_assert_reset(target_t *target)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       
+       DEBUG("target->state: %s", target_state_strings[target->state]);
+       
+       /* if the handler isn't installed yet, we have to assert TRST, too */
+       if (!xscale->handler_installed)
+       {
+               jtag_add_reset(1, 1);
+       }
+       else
+               jtag_add_reset(-1, 1);
+       
+       /* sleep 1ms, to be sure we fulfill any requirements */
+       jtag_add_sleep(1000);
+       
+       target->state = TARGET_RESET;
+       
+       return ERROR_OK;
+
+}
+
+int xscale_deassert_reset(target_t *target)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       
+       FILE *binary;
+       u32 address;
+       struct stat binary_stat;
+       u32 binary_size;
+
+       u32 buffer[8];
+       u32 buf_cnt;
+       int i;
+       
+       breakpoint_t *breakpoint = target->breakpoints;
+       
+       xscale->ibcr_available = 2;
+       xscale->ibcr0_used = 0;
+       xscale->ibcr1_used = 0;
+               
+       xscale->dbr_available = 2;
+       xscale->dbr0_used = 0;
+       xscale->dbr1_used = 0;
+       
+       /* mark all hardware breakpoints as unset */
+       while (breakpoint)
+       {
+               if (breakpoint->type == BKPT_HARD)
+               {
+                       breakpoint->set = 0;
+               }
+               breakpoint = breakpoint->next;
+       }
+       
+       if (!xscale->handler_installed)
+       {
+               /* release TRST */
+               jtag_add_reset(0, -1);
+               jtag_add_sleep(100000);
+               
+               /* set Hold reset, Halt mode and Trap Reset */
+               buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 30, 1, 0x1);
+               buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 1, 0x1);
+               xscale_write_dcsr(target, 1, 0);
+               jtag_add_runtest(100, TAP_RTI);
+               jtag_execute_queue();
+               
+               /* release SRST */
+               jtag_add_reset(0, 0);
+               /* wait 150ms; 100ms were not enough */
+               jtag_add_sleep(150000);
+
+               jtag_add_runtest(2030, TAP_RTI);
+               jtag_execute_queue();
+               
+               xscale_write_dcsr(target, 1, 0);
+               jtag_execute_queue();
+               
+               /* TODO: load debug handler */
+               if (stat("target/xscale/debug_handler.bin", &binary_stat) == -1)
+               {
+                       ERROR("couldn't stat() target/xscale/debug_handler.bin: %s",  strerror(errno));
+                       return ERROR_OK;
+               }
+               
+               if (!(binary = fopen("target/xscale/debug_handler.bin", "r")))
+               {
+                       ERROR("couldn't open target/xscale/debug_handler.bin: %s", strerror(errno));
+                       return ERROR_OK;
+               }
+               
+               if ((binary_size = binary_stat.st_size) % 4)
+               {
+                       ERROR("debug_handler.bin: size not a multiple of 4");
+                       exit(-1);
+               }
+                       
+               if (binary_size > 0x800)
+               {
+                       ERROR("debug_handler.bin: larger than 2kb");
+                       exit(-1);
+               }
+               
+               binary_size = CEIL(binary_size, 32) * 32;
+               
+               address = xscale->handler_address;
+               while (binary_size > 0)
+               {
+                       buf_cnt = fread(buffer, 4, 8, binary);
+                       
+                       for (i = 0; i < buf_cnt; i++)
+                       {
+                               /* convert LE buffer to host-endian u32 */
+                               buffer[i] = buf_get_u32((u8*)(&buffer[i]), 0, 32);
+                       }
+                       
+                       if (buf_cnt < 8)
+                       {
+                               for (; buf_cnt < 8; buf_cnt++)
+                               {
+                                       buffer[buf_cnt] = 0xe1a08008;
+                               }
+                       }
+                       
+                       /* only load addresses other than the reset vectors */
+                       if ((address % 0x400) != 0x0)
+                       {
+                               xscale_load_ic(target, 1, address, buffer);
+                       }
+                       
+                       address += buf_cnt * 4;
+                       binary_size -= buf_cnt * 4;
+               };
+               
+               xscale_load_ic(target, 1, 0x0, xscale->low_vectors);
+               xscale_load_ic(target, 1, 0xffff0000, xscale->high_vectors);
+       
+               jtag_add_runtest(30, TAP_RTI);
+               
+               /* let the target run (should enter debug handler) */
+               xscale_write_dcsr(target, 0, 0);
+               target->state = TARGET_RUNNING;
+               
+               if ((target->reset_mode != RESET_HALT) && (target->reset_mode != RESET_INIT))
+               {
+                       jtag_add_sleep(10000);
+                       
+                       /* we should have entered debug now */
+                       xscale_debug_entry(target);
+                       target->state = TARGET_HALTED;
+                       
+                       /* the PC is now at 0x0 */
+                       buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, 0x0);
+               }
+       }
+       else
+       {
+               jtag_add_reset(0, 0);
+       }
+               
+               
+       return ERROR_OK;
+}
+
+int xscale_soft_reset_halt(struct target_s *target)
+{
+       
+       return ERROR_OK;
+}
+
+int xscale_read_core_reg(struct target_s *target, int num, enum armv4_5_mode mode)
+{
+
+       return ERROR_OK;
+}
+
+int xscale_write_core_reg(struct target_s *target, int num, enum armv4_5_mode mode, u32 value)
+{
+       
+       return ERROR_OK;
+}
+
+int xscale_full_context(target_t *target)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       
+       u32 *buffer;
+       
+       int i, j;
+       
+       DEBUG("-");
+       
+       if (target->state != TARGET_HALTED)
+       {
+               WARNING("target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+       
+       buffer = malloc(4 * 8);
+       
+       /* iterate through processor modes (FIQ, IRQ, SVC, ABT, UND and SYS)
+        * we can't enter User mode on an XScale (unpredictable),
+        * but User shares registers with SYS
+        */
+       for(i = 1; i < 7; i++)
+       {
+               int valid = 1;
+               
+               /* check if there are invalid registers in the current mode 
+                */
+               for (j = 0; j <= 16; j++)
+               {
+                       if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).valid == 0)
+                               valid = 0;
+               }
+               
+               if (!valid)
+               {
+                       u32 tmp_cpsr;
+                       
+                       /* request banked registers */
+                       xscale_send_u32(target, 0x0);
+                       
+                       tmp_cpsr = 0x0;
+                       tmp_cpsr |= armv4_5_number_to_mode(i);
+                       tmp_cpsr |= 0xc0; /* I/F bits */
+                       
+                       /* send CPSR for desired mode */
+                       xscale_send_u32(target, tmp_cpsr);
+
+                       /* get banked registers, r8 to r14, and spsr if not in USR/SYS mode */
+                       if ((armv4_5_number_to_mode(i) != ARMV4_5_MODE_USR) && (armv4_5_number_to_mode(i) != ARMV4_5_MODE_SYS))
+                       {
+                               xscale_receive(target, buffer, 8);
+                               buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).value, 0, 32, buffer[7]);
+                               ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).dirty = 0;
+                               ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).valid = 1;
+                       }
+                       else
+                       {
+                               xscale_receive(target, buffer, 7);
+                       }
+       
+                       /* move data from buffer to register cache */
+                       for (j = 8; j <= 14; j++)
+                       {
+                               buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).value, 0, 32, buffer[j - 8]);
+                               ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).dirty = 0;
+                               ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).valid = 1;
+                       }
+               }
+       }
+       
+       free(buffer);
+       
+       return ERROR_OK;
+}
+
+int xscale_restore_context(target_t *target)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       
+       int i, j;
+       
+       DEBUG("-");
+       
+       if (target->state != TARGET_HALTED)
+       {
+               WARNING("target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+       
+       /* iterate through processor modes (FIQ, IRQ, SVC, ABT, UND and SYS)
+       * we can't enter User mode on an XScale (unpredictable),
+       * but User shares registers with SYS
+       */
+       for(i = 1; i < 7; i++)
+       {
+               int dirty = 0;
+               
+               /* check if there are invalid registers in the current mode 
+               */
+               for (j = 8; j <= 14; j++)
+               {
+                       if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).dirty == 1)
+                               dirty = 1;
+               }
+               
+               /* if not USR/SYS, check if the SPSR needs to be written */
+               if ((armv4_5_number_to_mode(i) != ARMV4_5_MODE_USR) && (armv4_5_number_to_mode(i) != ARMV4_5_MODE_SYS))
+               {
+                       if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).dirty == 1)
+                               dirty = 1;
+               }
+               
+               if (dirty)
+               {
+                       u32 tmp_cpsr;
+                       
+                       /* send banked registers */
+                       xscale_send_u32(target, 0x1);
+                       
+                       tmp_cpsr = 0x0;
+                       tmp_cpsr |= armv4_5_number_to_mode(i);
+                       tmp_cpsr |= 0xc0; /* I/F bits */
+                       
+                       /* send CPSR for desired mode */
+                       xscale_send_u32(target, tmp_cpsr);
+
+                       /* send banked registers, r8 to r14, and spsr if not in USR/SYS mode */
+                       for (j = 8; j <= 14; j++)
+                       {
+                               xscale_send_u32(target, buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, j).value, 0, 32));
+                               ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).dirty = 0;
+                       }
+                       
+                       if ((armv4_5_number_to_mode(i) != ARMV4_5_MODE_USR) && (armv4_5_number_to_mode(i) != ARMV4_5_MODE_SYS))
+                       {
+                               xscale_send_u32(target, buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).value, 0, 32));
+                               ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).dirty = 0;
+                       }
+               }
+       }
+       
+       return ERROR_OK;
+}
+
+int xscale_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       u32 *buf32;
+       int i;
+       
+       DEBUG("address: 0x%8.8x, size: 0x%8.8x, count: 0x%8.8x", address, size, count);
+
+       if (target->state != TARGET_HALTED)
+       {
+               WARNING("target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* sanitize arguments */
+       if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer))
+               return ERROR_INVALID_ARGUMENTS;
+
+       if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))
+               return ERROR_TARGET_UNALIGNED_ACCESS;
+       
+       /* send memory read request (command 0x1n, n: access size) */
+       xscale_send_u32(target, 0x10 | size);
+       
+       /* send base address for read request */
+       xscale_send_u32(target, address);
+       
+       /* send number of requested data words */
+       xscale_send_u32(target, count);
+       
+       /* receive data from target (count times 32-bit words in host endianness) */
+       buf32 = malloc(4 * count);
+       xscale_receive(target, buf32, count);
+       
+       /* extract data from host-endian buffer into byte stream */
+       for (i = 0; i < count; i++)
+       {
+               switch (size)
+               {
+                       case 4:
+                               target_buffer_set_u32(target, buffer, buf32[i]);
+                               buffer += 4;
+                               break;
+                       case 2:
+                               target_buffer_set_u16(target, buffer, buf32[i] & 0xffff);
+                               buffer += 2;
+                               break;
+                       case 1:
+                               *buffer++ = buf32[i] & 0xff;
+                               break;
+                       default:
+                               ERROR("should never get here");
+                               exit(-1);
+               }
+       }
+
+       free(buf32);
+       
+       /* examine DCSR, to see if Sticky Abort (SA) got set */ 
+       xscale_read_dcsr(target);
+       if (buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 5, 1) == 1)
+       {
+               /* clear SA bit */
+               xscale_send_u32(target, 0x60);
+               
+               return ERROR_TARGET_DATA_ABORT;
+       }
+       
+       return ERROR_OK;
+}
+
+int xscale_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       
+       DEBUG("address: 0x%8.8x, size: 0x%8.8x, count: 0x%8.8x", address, size, count);
+
+       if (target->state != TARGET_HALTED)
+       {
+               WARNING("target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* sanitize arguments */
+       if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer))
+               return ERROR_INVALID_ARGUMENTS;
+
+       if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))
+               return ERROR_TARGET_UNALIGNED_ACCESS;
+       
+       /* send memory write request (command 0x2n, n: access size) */
+       xscale_send_u32(target, 0x20 | size);
+       
+       /* send base address for read request */
+       xscale_send_u32(target, address);
+       
+       /* send number of requested data words to be written*/
+       xscale_send_u32(target, count);
+       
+       /* extract data from host-endian buffer into byte stream */
+#if 0
+       for (i = 0; i < count; i++)
+       {
+               switch (size)
+               {
+                       case 4:
+                               value = target_buffer_get_u32(target, buffer);
+                               xscale_send_u32(target, value);
+                               buffer += 4;
+                               break;
+                       case 2:
+                               value = target_buffer_get_u16(target, buffer);
+                               xscale_send_u32(target, value);
+                               buffer += 2;
+                               break;
+                       case 1:
+                               value = *buffer;
+                               xscale_send_u32(target, value);
+                               buffer += 1; 
+                               break;
+                       default:
+                               ERROR("should never get here");
+                               exit(-1);
+               }
+       }
+#endif
+       xscale_send(target, buffer, count, size);
+       
+       /* examine DCSR, to see if Sticky Abort (SA) got set */ 
+       xscale_read_dcsr(target);
+       if (buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 5, 1) == 1)
+       {
+               /* clear SA bit */
+               xscale_send_u32(target, 0x60);
+               
+               return ERROR_TARGET_DATA_ABORT;
+       }
+       
+       return ERROR_OK;
+}
+
+int xscale_bulk_write_memory(target_t *target, u32 address, u32 count, u8 *buffer)
+{
+       xscale_write_memory(target, address, 4, count, buffer);
+       
+       return ERROR_OK;
+}
+
+u32 xscale_get_ttb(target_t *target)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       u32 ttb;
+
+       xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_TTB]);
+       ttb = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_TTB].value, 0, 32);
+
+       return ttb;
+}
+
+void xscale_disable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       u32 cp15_control;
+
+       /* read cp15 control register */
+       xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]);
+       cp15_control = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32);
+       
+       if (mmu)
+               cp15_control &= ~0x1U;
+       
+       if (d_u_cache)
+       {
+               /* clean DCache */
+               xscale_send_u32(target, 0x50);
+               xscale_send_u32(target, xscale->cache_clean_address);
+               
+               /* invalidate DCache */
+               xscale_send_u32(target, 0x51);
+               
+               cp15_control &= ~0x4U;
+       }
+       
+       if (i_cache)
+       {
+               /* invalidate ICache */
+               xscale_send_u32(target, 0x52);
+               cp15_control &= ~0x1000U;
+       }
+
+       /* write new cp15 control register */
+       xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_CTRL], cp15_control);
+       
+       /* execute cpwait to ensure outstanding operations complete */
+       xscale_send_u32(target, 0x53);
+}
+
+void xscale_enable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       u32 cp15_control;
+
+       /* read cp15 control register */
+       xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]);
+       cp15_control = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32);
+                       
+       if (mmu)
+               cp15_control |= 0x1U;
+       
+       if (d_u_cache)
+               cp15_control |= 0x4U;
+       
+       if (i_cache)
+               cp15_control |= 0x1000U;
+       
+       /* write new cp15 control register */
+       xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_CTRL], cp15_control);
+       
+       /* execute cpwait to ensure outstanding operations complete */
+       xscale_send_u32(target, 0x53);
+}
+
+int xscale_set_breakpoint(struct target_s *target, breakpoint_t *breakpoint)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       
+       if (target->state != TARGET_HALTED)
+       {
+               WARNING("target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+       
+       if (xscale->force_hw_bkpts)
+               breakpoint->type = BKPT_HARD;
+
+       if (breakpoint->set)
+       {
+               WARNING("breakpoint already set");
+               return ERROR_OK;
+       }
+
+       if (breakpoint->type == BKPT_HARD)
+       {
+               u32 value = breakpoint->address | 1;
+               if (!xscale->ibcr0_used)
+               {
+                       xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR0], value); 
+                       xscale->ibcr0_used = 1;
+                       breakpoint->set = 1;    /* breakpoint set on first breakpoint register */
+               }
+               else if (!xscale->ibcr1_used)
+               {
+                       xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR1], value); 
+                       xscale->ibcr1_used = 1;
+                       breakpoint->set = 2;    /* breakpoint set on second breakpoint register */
+               }
+               else
+               {
+                       ERROR("BUG: no hardware comparator available");
+                       return ERROR_OK;
+               }
+       }
+       else if (breakpoint->type == BKPT_SOFT)
+       {
+               if (breakpoint->length == 4)
+               {
+                       /* keep the original instruction in target endianness */
+                       target->type->read_memory(target, breakpoint->address, 4, 1, breakpoint->orig_instr);
+                       /* write the original instruction in target endianness (arm7_9->arm_bkpt is host endian) */
+                       target_write_u32(target, breakpoint->address, xscale->arm_bkpt);
+               }
+               else
+               {
+                       /* keep the original instruction in target endianness */
+                       target->type->read_memory(target, breakpoint->address, 2, 1, breakpoint->orig_instr);
+                       /* write the original instruction in target endianness (arm7_9->arm_bkpt is host endian) */
+                       target_write_u32(target, breakpoint->address, xscale->thumb_bkpt);
+               }
+               breakpoint->set = 1;
+       }
+
+       return ERROR_OK;
+
+}
+
+int xscale_add_breakpoint(struct target_s *target, breakpoint_t *breakpoint)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       
+       if (target->state != TARGET_HALTED)
+       {
+               WARNING("target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+       
+       if (xscale->force_hw_bkpts)
+       {
+               DEBUG("forcing use of hardware breakpoint at address 0x%8.8x", breakpoint->address);
+               breakpoint->type = BKPT_HARD;
+       }
+       
+       if ((breakpoint->type == BKPT_HARD) && (xscale->ibcr_available < 1))
+       {
+               INFO("no breakpoint unit available for hardware breakpoint");
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       }
+       else
+       {
+               xscale->ibcr_available--;
+       }
+       
+       if ((breakpoint->length != 2) && (breakpoint->length != 4))
+       {
+               INFO("only breakpoints of two (Thumb) or four (ARM) bytes length supported");
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       }
+       
+       return ERROR_OK;
+}
+
+int xscale_unset_breakpoint(struct target_s *target, breakpoint_t *breakpoint)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       
+       if (target->state != TARGET_HALTED)
+       {
+               WARNING("target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (!breakpoint->set)
+       {
+               WARNING("breakpoint not set");
+               return ERROR_OK;
+       }
+       
+       if (breakpoint->type == BKPT_HARD)
+       {
+               if (breakpoint->set == 1)
+               {
+                       xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR0], 0x0); 
+                       xscale->ibcr0_used = 0;
+               }
+               else if (breakpoint->set == 2)
+               {
+                       xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR1], 0x0); 
+                       xscale->ibcr1_used = 0;
+               }
+               breakpoint->set = 0;
+       }
+       else
+       {
+               /* restore original instruction (kept in target endianness) */
+               if (breakpoint->length == 4)
+               {
+                       target->type->write_memory(target, breakpoint->address, 4, 1, breakpoint->orig_instr);
+               }
+               else
+               {
+                       target->type->write_memory(target, breakpoint->address, 2, 1, breakpoint->orig_instr);
+               }
+               breakpoint->set = 0;
+       }
+
+       return ERROR_OK;
+}
+
+int xscale_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       
+       if (target->state != TARGET_HALTED)
+       {
+               WARNING("target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+       
+       if (breakpoint->set)
+       {
+               xscale_unset_breakpoint(target, breakpoint);
+       }
+       
+       if (breakpoint->type == BKPT_HARD)
+               xscale->ibcr_available++;
+       
+       return ERROR_OK;
+}
+
+int xscale_set_watchpoint(struct target_s *target, watchpoint_t *watchpoint)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       u8 enable;
+       reg_t *dbcon = &xscale->reg_cache->reg_list[XSCALE_DBCON];
+       u32 dbcon_value = buf_get_u32(dbcon->value, 0, 32);
+       
+       if (target->state != TARGET_HALTED)
+       {
+               WARNING("target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+       
+       xscale_get_reg(dbcon);
+       
+       switch (watchpoint->rw)
+       {
+               case WPT_READ:
+                       enable = 0x3;
+                       break;
+               case WPT_ACCESS:
+                       enable = 0x2;
+                       break;
+               case WPT_WRITE:
+                       enable = 0x1;
+                       break;
+               default:
+                       ERROR("BUG: watchpoint->rw neither read, write nor access");    
+       }
+
+       if (!xscale->dbr0_used)
+       {
+               xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_DBR0], watchpoint->address);
+               dbcon_value |= enable;
+               xscale_set_reg_u32(dbcon, dbcon_value);
+               watchpoint->set = 1;
+               xscale->dbr0_used = 1;
+       }
+       else if (!xscale->dbr1_used)
+       {
+               xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_DBR1], watchpoint->address);
+               dbcon_value |= enable << 2;
+               xscale_set_reg_u32(dbcon, dbcon_value);
+               watchpoint->set = 2;
+               xscale->dbr1_used = 1;
+       }
+       else
+       {
+               ERROR("BUG: no hardware comparator available");
+               return ERROR_OK;
+       }
+       
+       return ERROR_OK;
+}
+
+int xscale_add_watchpoint(struct target_s *target, watchpoint_t *watchpoint)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       
+       if (target->state != TARGET_HALTED)
+       {
+               WARNING("target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+       
+       if (xscale->dbr_available < 1)
+       {
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       }
+       
+       if ((watchpoint->length != 1) && (watchpoint->length != 2) && (watchpoint->length != 4))
+       {
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       }
+       
+       xscale->dbr_available--;
+               
+       return ERROR_OK;
+}
+
+int xscale_unset_watchpoint(struct target_s *target, watchpoint_t *watchpoint)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       reg_t *dbcon = &xscale->reg_cache->reg_list[XSCALE_DBCON];
+       u32 dbcon_value = buf_get_u32(dbcon->value, 0, 32);
+       
+       if (target->state != TARGET_HALTED)
+       {
+               WARNING("target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+       
+       if (!watchpoint->set)
+       {
+               WARNING("breakpoint not set");
+               return ERROR_OK;
+       }
+       
+       if (watchpoint->set == 1)
+       {
+               dbcon_value &= ~0x3;
+               xscale_set_reg_u32(dbcon, dbcon_value);
+               xscale->dbr0_used = 0;
+       }
+       else if (watchpoint->set == 2)
+       {
+               dbcon_value &= ~0xc;
+               xscale_set_reg_u32(dbcon, dbcon_value);
+               xscale->dbr1_used = 0;
+       }
+       watchpoint->set = 0;
+
+       return ERROR_OK;
+}
+
+int xscale_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       
+       if (target->state != TARGET_HALTED)
+       {
+               WARNING("target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+       
+       if (watchpoint->set)
+       {
+               xscale_unset_watchpoint(target, watchpoint);
+       }
+               
+       xscale->dbr_available++;
+       
+       return ERROR_OK;
+}
+
+void xscale_enable_watchpoints(struct target_s *target)
+{
+       watchpoint_t *watchpoint = target->watchpoints;
+       
+       while (watchpoint)
+       {
+               if (watchpoint->set == 0)
+                       xscale_set_watchpoint(target, watchpoint);
+               watchpoint = watchpoint->next;
+       }
+}
+
+void xscale_enable_breakpoints(struct target_s *target)
+{
+       breakpoint_t *breakpoint = target->breakpoints;
+       
+       /* set any pending breakpoints */
+       while (breakpoint)
+       {
+               if (breakpoint->set == 0)
+                       xscale_set_breakpoint(target, breakpoint);
+               breakpoint = breakpoint->next;
+       }
+}
+
+int xscale_get_reg(reg_t *reg)
+{
+       xscale_reg_t *arch_info = reg->arch_info;
+       target_t *target = arch_info->target;
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+               
+       /* DCSR, TX and RX are accessible via JTAG */
+       if (strcmp(reg->name, "XSCALE_DCSR") == 0)
+       {
+               return xscale_read_dcsr(arch_info->target);
+       }
+       else if (strcmp(reg->name, "XSCALE_TX") == 0)
+       {
+               /* 1 = consume register content */
+               return xscale_read_tx(arch_info->target, 1);
+       }
+       else if (strcmp(reg->name, "XSCALE_RX") == 0)
+       {
+               /* can't read from RX register (host -> debug handler) */
+               return ERROR_OK;
+       }
+       else if (strcmp(reg->name, "XSCALE_TXRXCTRL") == 0)
+       {
+               /* can't (explicitly) read from TXRXCTRL register */
+               return ERROR_OK;
+       }
+       else /* Other DBG registers have to be transfered by the debug handler */
+       {
+               /* send CP read request (command 0x40) */
+               xscale_send_u32(target, 0x40);
+               
+               /* send CP register number */
+               xscale_send_u32(target, arch_info->dbg_handler_number);
+
+               /* read register value */
+               xscale_read_tx(target, 1);
+               buf_cpy(xscale->reg_cache->reg_list[XSCALE_TX].value, reg->value, 32);
+
+               reg->dirty = 0;
+               reg->valid = 1;
+       }
+       
+       return ERROR_OK;
+}
+
+int xscale_set_reg(reg_t *reg, u8* buf)
+{
+       xscale_reg_t *arch_info = reg->arch_info;
+       target_t *target = arch_info->target;
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       u32 value = buf_get_u32(buf, 0, 32);
+       
+       /* DCSR, TX and RX are accessible via JTAG */
+       if (strcmp(reg->name, "XSCALE_DCSR") == 0)
+       {
+               buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 0, 32, value);
+               return xscale_write_dcsr(arch_info->target, -1, -1);
+       }
+       else if (strcmp(reg->name, "XSCALE_RX") == 0)
+       {
+               buf_set_u32(xscale->reg_cache->reg_list[XSCALE_RX].value, 0, 32, value);
+               return xscale_write_rx(arch_info->target);
+       }
+       else if (strcmp(reg->name, "XSCALE_TX") == 0)
+       {
+               /* can't write to TX register (debug-handler -> host) */
+               return ERROR_OK;
+       }
+       else if (strcmp(reg->name, "XSCALE_TXRXCTRL") == 0)
+       {
+               /* can't (explicitly) write to TXRXCTRL register */
+               return ERROR_OK;
+       }
+       else /* Other DBG registers have to be transfered by the debug handler */
+       {
+               /* send CP write request (command 0x41) */
+               xscale_send_u32(target, 0x41);
+               
+               /* send CP register number */
+               xscale_send_u32(target, arch_info->dbg_handler_number);
+               
+               /* send CP register value */
+               xscale_send_u32(target, value);
+               buf_set_u32(reg->value, 0, 32, value);
+       }
+       
+       return ERROR_OK;
+}
+
+/* convenience wrapper to access XScale specific registers */
+int xscale_set_reg_u32(reg_t *reg, u32 value)
+{
+       u8 buf[4];
+       
+       buf_set_u32(buf, 0, 32, value);
+       
+       return xscale_set_reg(reg, buf);
+}
+
+int xscale_write_dcsr_sw(target_t *target, u32 value)
+{
+       /* get pointers to arch-specific information */
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       reg_t *dcsr = &xscale->reg_cache->reg_list[XSCALE_DCSR];
+       xscale_reg_t *dcsr_arch_info = dcsr->arch_info;
+       
+       /* send CP write request (command 0x41) */
+       xscale_send_u32(target, 0x41);
+               
+       /* send CP register number */
+       xscale_send_u32(target, dcsr_arch_info->dbg_handler_number);
+               
+       /* send CP register value */
+       xscale_send_u32(target, value);
+       buf_set_u32(dcsr->value, 0, 32, value);
+       
+       return ERROR_OK;
+}
+
+void xscale_build_reg_cache(target_t *target)
+{
+       /* get pointers to arch-specific information */
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+
+       reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache);
+       xscale_reg_t *arch_info = malloc(sizeof(xscale_reg_arch_info));
+       int i;
+       int num_regs = sizeof(xscale_reg_arch_info) / sizeof(xscale_reg_t);
+       
+       (*cache_p) = armv4_5_build_reg_cache(target, armv4_5);
+       armv4_5->core_cache = (*cache_p);
+       
+       /* register a register arch-type for XScale dbg registers only once */
+       if (xscale_reg_arch_type == -1)
+               xscale_reg_arch_type = register_reg_arch_type(xscale_get_reg, xscale_set_reg);
+       
+       (*cache_p)->next = malloc(sizeof(reg_cache_t));
+       cache_p = &(*cache_p)->next;
+       
+       /* fill in values for the xscale reg cache */
+       (*cache_p)->name = "XScale registers";
+       (*cache_p)->next = NULL;
+       (*cache_p)->reg_list = malloc(num_regs * sizeof(reg_t));
+       (*cache_p)->num_regs = num_regs;
+       
+       for (i = 0; i < num_regs; i++)
+       {
+               (*cache_p)->reg_list[i].name = xscale_reg_list[i];
+               (*cache_p)->reg_list[i].value = calloc(4, 1);
+               (*cache_p)->reg_list[i].dirty = 0;
+               (*cache_p)->reg_list[i].valid = 0;
+               (*cache_p)->reg_list[i].size = 32;
+               (*cache_p)->reg_list[i].bitfield_desc = NULL;
+               (*cache_p)->reg_list[i].num_bitfields = 0;
+               (*cache_p)->reg_list[i].arch_info = &arch_info[i];
+               (*cache_p)->reg_list[i].arch_type = xscale_reg_arch_type;
+               arch_info[i] = xscale_reg_arch_info[i];
+               arch_info[i].target = target;
+       }
+       
+       xscale->reg_cache = (*cache_p);
+}
+
+int xscale_init_target(struct command_context_s *cmd_ctx, struct target_s *target)
+{
+       if (startup_mode != DAEMON_RESET)
+       {
+               ERROR("XScale target requires a reset");
+               ERROR("Reset target to enable debug");
+       }
+       
+       return ERROR_OK;
+}
+
+int xscale_quit()
+{
+       
+       return ERROR_OK;
+}
+
+int xscale_init_arch_info(target_t *target, xscale_common_t *xscale, int chain_pos, char *variant)
+{
+       armv4_5_common_t *armv4_5;
+       u32 high_reset_branch, low_reset_branch;
+       int i;
+       
+       armv4_5 = &xscale->armv4_5_common;
+       
+       /* store architecture specfic data (none so far) */
+       xscale->arch_info = NULL;
+       xscale->common_magic = XSCALE_COMMON_MAGIC;
+       
+       /* remember the variant (PXA25x, PXA27x, IXP42x, ...) */
+       xscale->variant = strdup(variant);
+       
+       /* prepare JTAG information for the new target */
+       xscale->jtag_info.chain_pos = chain_pos;
+       jtag_register_event_callback(xscale_jtag_callback, target);
+
+       xscale->jtag_info.dbgrx = 0x02;
+       xscale->jtag_info.dbgtx = 0x10;
+       xscale->jtag_info.dcsr = 0x09;
+       xscale->jtag_info.ldic = 0x07;  
+
+       if ((strcmp(xscale->variant, "pxa250") == 0) ||
+               (strcmp(xscale->variant, "pxa255") == 0) ||
+               (strcmp(xscale->variant, "pxa26x") == 0))
+       {
+               xscale->jtag_info.ir_length = 5;
+       }
+       else if ((strcmp(xscale->variant, "pxa27x") == 0) ||
+               (strcmp(xscale->variant, "ixp42x") == 0) ||
+               (strcmp(xscale->variant, "ixp45x") == 0) ||
+               (strcmp(xscale->variant, "ixp46x") == 0))
+       {
+               xscale->jtag_info.ir_length = 7;
+       }
+       
+       /* the debug handler isn't installed (and thus not running) at this time */
+       xscale->handler_installed = 0;
+       xscale->handler_running = 0;
+       xscale->handler_address = 0xfe000800;
+       
+       /* clear the vectors we keep locally for reference */
+       memset(xscale->low_vectors, 0, sizeof(xscale->low_vectors));
+       memset(xscale->high_vectors, 0, sizeof(xscale->high_vectors));
+
+       /* no user-specified vectors have been configured yet */
+       xscale->static_low_vectors_set = 0x0;
+       xscale->static_high_vectors_set = 0x0;
+
+       /* calculate branches to debug handler */
+       low_reset_branch = (xscale->handler_address + 0x20 - 0x0 - 0x8) >> 2;
+       high_reset_branch = (xscale->handler_address + 0x20 - 0xffff0000 - 0x8) >> 2;
+       
+       xscale->low_vectors[0] = ARMV4_5_B((low_reset_branch & 0xffffff), 0);
+       xscale->high_vectors[0] = ARMV4_5_B((high_reset_branch & 0xffffff), 0);
+       
+       for (i = 1; i <= 7; i++)
+       {
+               xscale->low_vectors[i] = ARMV4_5_B(0xfffffe, 0);
+               xscale->high_vectors[i] = ARMV4_5_B(0xfffffe, 0);
+       }
+       
+       /* 64kB aligned region used for DCache cleaning */ 
+       xscale->cache_clean_address = 0xfffe0000;       
+       
+       xscale->hold_rst = 0;
+       xscale->external_debug_break = 0;
+       
+       xscale->force_hw_bkpts = 1;
+       
+       xscale->ibcr_available = 2;
+       xscale->ibcr0_used = 0;
+       xscale->ibcr1_used = 0;
+               
+       xscale->dbr_available = 2;
+       xscale->dbr0_used = 0;
+       xscale->dbr1_used = 0;
+       
+       xscale->arm_bkpt = ARMV5_BKPT(0x0);
+       xscale->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff;
+       
+       xscale->vector_catch = 0x1;
+       
+       xscale->trace_buffer_enabled = 0;
+       xscale->trace_buffer_fill = 0;
+       
+       /* prepare ARMv4/5 specific information */
+       armv4_5->arch_info = xscale;
+       armv4_5->read_core_reg = xscale_read_core_reg;
+       armv4_5->write_core_reg = xscale_write_core_reg;
+       armv4_5->full_context = xscale_full_context;
+
+       armv4_5_init_arch_info(target, armv4_5);
+
+       xscale->armv4_5_mmu.armv4_5_cache.ctype = -1;
+       xscale->armv4_5_mmu.get_ttb = xscale_get_ttb;
+       xscale->armv4_5_mmu.read_memory = xscale_read_memory;
+       xscale->armv4_5_mmu.write_memory = xscale_write_memory;
+       xscale->armv4_5_mmu.disable_mmu_caches = xscale_disable_mmu_caches;
+       xscale->armv4_5_mmu.enable_mmu_caches = xscale_enable_mmu_caches;
+       xscale->armv4_5_mmu.has_tiny_pages = 1;
+       xscale->armv4_5_mmu.mmu_enabled = 0;
+       
+       return ERROR_OK;
+}
+
+/* target xscale <endianess> <startup_mode> <chain_pos> <variant> */
+int xscale_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target)
+{
+       int chain_pos;
+       char *variant = NULL;
+       xscale_common_t *xscale = malloc(sizeof(xscale_common_t));
+
+       if (argc < 5)
+       {
+               ERROR("'target xscale' requires four arguments: <endianess> <startup_mode> <chain_pos> <variant>");
+               exit(-1);
+       }
+       
+       chain_pos = strtoul(args[3], NULL, 0);
+       
+       variant = args[4];
+       
+       xscale_init_arch_info(target, xscale, chain_pos, variant);
+       xscale_build_reg_cache(target);
+       
+       return ERROR_OK;
+}
+
+int xscale_handle_debug_handler_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       target_t *target = NULL;
+       armv4_5_common_t *armv4_5;
+       xscale_common_t *xscale;
+
+       u32 handler_address;
+
+       if (argc < 2)
+       {
+               ERROR("'xscale debug_handler <target#> <address>' command takes two required operands");
+               return ERROR_OK;
+       }
+       
+       if ((target = get_target_by_num(strtoul(args[0], NULL, 0))) == NULL)
+       {
+               ERROR("no target '%s' configured", args[0]);
+               return ERROR_OK;
+       }
+       
+       if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK)
+       {
+               command_print(cmd_ctx, "target isn't an ARM920t target");
+               return ERROR_OK;
+       }
+       
+       handler_address = strtoul(args[1], NULL, 0);
+       
+       if (((handler_address >= 0x800) && (handler_address <= 0x1fef800)) ||
+               ((handler_address >= 0xfe000800) && (handler_address <= 0xfffff800)))
+       {
+               xscale->handler_address = handler_address;
+       }
+       else
+       {
+               ERROR("xscale debug_handler <address> must be between 0x800 and 0x1fef800 or between 0xfe000800 and 0xfffff800");
+       }
+       
+       return ERROR_OK;
+}
+
+int xscale_handle_cache_clean_address_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       target_t *target = NULL;
+       armv4_5_common_t *armv4_5;
+       xscale_common_t *xscale;
+
+       u32 cache_clean_address;
+       
+       if (argc < 2)
+       {
+               ERROR("'xscale cache_clean_address <target#> <address>' command takes two required operands");
+               return ERROR_OK;
+       }
+       
+       if ((target = get_target_by_num(strtoul(args[0], NULL, 0))) == NULL)
+       {
+               ERROR("no target '%s' configured", args[0]);
+               return ERROR_OK;
+       }
+       
+       if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK)
+       {
+               command_print(cmd_ctx, "target isn't an XScale target");
+               return ERROR_OK;
+       }
+       
+       cache_clean_address = strtoul(args[1], NULL, 0);
+       
+       if (cache_clean_address & 0xffff)
+       {
+               ERROR("xscale cache_clean_address <address> must be 64kb aligned");
+       }
+       else
+       {
+               xscale->cache_clean_address = cache_clean_address;
+       }
+       
+       return ERROR_OK;
+}
+
+int xscale_handle_cache_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       target_t *target = get_current_target(cmd_ctx);
+       armv4_5_common_t *armv4_5;
+       xscale_common_t *xscale;
+       
+       if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK)
+       {
+               command_print(cmd_ctx, "target isn't an XScale target");
+               return ERROR_OK;
+       }
+       
+       return armv4_5_handle_cache_info_command(cmd_ctx, &xscale->armv4_5_mmu.armv4_5_cache);
+}
+
+int xscale_handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
+{      
+       target_t *target = get_current_target(cmd_ctx);
+       armv4_5_common_t *armv4_5;
+       xscale_common_t *xscale;
+       
+       if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK)
+       {
+               command_print(cmd_ctx, "target isn't an XScale target");
+               return ERROR_OK;
+       }
+       
+       if (target->state != TARGET_HALTED)
+       {
+               command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
+               return ERROR_OK;
+       }
+               
+       return armv4_5_mmu_handle_virt2phys_command(cmd_ctx, cmd, args, argc, target, &xscale->armv4_5_mmu);
+}
+
+int xscale_handle_mmu_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
+{      
+       target_t *target = get_current_target(cmd_ctx);
+       armv4_5_common_t *armv4_5;
+       xscale_common_t *xscale;
+       
+       if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK)
+       {
+               command_print(cmd_ctx, "target isn't an XScale target");
+               return ERROR_OK;
+       }
+       
+       if (target->state != TARGET_HALTED)
+       {
+               command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
+               return ERROR_OK;
+       }
+       
+       if (argc >= 1)
+       {
+               if (strcmp("enable", args[0]) == 0)
+               {
+                       xscale_enable_mmu_caches(target, 1, 0, 0);
+                       xscale->armv4_5_mmu.mmu_enabled = 1;
+               }
+               else if (strcmp("disable", args[0]) == 0)
+               {
+                       xscale_disable_mmu_caches(target, 1, 0, 0);
+                       xscale->armv4_5_mmu.mmu_enabled = 0;
+               }
+       }
+               
+       command_print(cmd_ctx, "mmu %s", (xscale->armv4_5_mmu.mmu_enabled) ? "enabled" : "disabled");
+       
+       return ERROR_OK;
+}
+
+int xscale_handle_idcache_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
+{      
+       target_t *target = get_current_target(cmd_ctx);
+       armv4_5_common_t *armv4_5;
+       xscale_common_t *xscale;
+       int icache = 0, dcache = 0;
+       
+       if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK)
+       {
+               command_print(cmd_ctx, "target isn't an XScale target");
+               return ERROR_OK;
+       }
+       
+       if (target->state != TARGET_HALTED)
+       {
+               command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
+               return ERROR_OK;
+       }
+       
+       if (strcmp(cmd, "icache") == 0)
+               icache = 1;
+       else if (strcmp(cmd, "dcache") == 0)
+               dcache = 1;
+       
+       if (argc >= 1)
+       {
+               if (strcmp("enable", args[0]) == 0)
+               {
+                       xscale_enable_mmu_caches(target, 0, dcache, icache);
+                       
+                       if (icache)
+                               xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 1;
+                       else if (dcache)
+                               xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 1;
+               }
+               else if (strcmp("disable", args[0]) == 0)
+               {
+                       xscale_disable_mmu_caches(target, 0, dcache, icache);
+
+                       if (icache)
+                               xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0;
+                       else if (dcache)
+                               xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0;
+               }
+       }
+       
+       if (icache)
+               command_print(cmd_ctx, "icache %s", (xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled) ? "enabled" : "disabled");
+       
+       if (dcache)
+               command_print(cmd_ctx, "dcache %s", (xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) ? "enabled" : "disabled");
+               
+       return ERROR_OK;
+}
+
+int xscale_handle_vector_catch_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
+{      
+       target_t *target = get_current_target(cmd_ctx);
+       armv4_5_common_t *armv4_5;
+       xscale_common_t *xscale;
+       
+       if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK)
+       {
+               command_print(cmd_ctx, "target isn't an XScale target");
+               return ERROR_OK;
+       }
+       
+       if (argc < 1)
+       {
+               command_print(cmd_ctx, "usage: xscale vector_catch [mask]");
+       }
+       else
+       {
+               xscale->vector_catch = strtoul(args[0], NULL, 0);
+               buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 8, xscale->vector_catch);
+               xscale_write_dcsr(target, -1, -1);
+       }
+       
+       command_print(cmd_ctx, "vector catch mask: 0x%2.2x", xscale->vector_catch);
+       
+       return ERROR_OK;
+}
+
+int xscale_handle_force_hw_bkpts_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       target_t *target = get_current_target(cmd_ctx);
+       armv4_5_common_t *armv4_5;
+       xscale_common_t *xscale;
+       
+       if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK)
+       {
+               command_print(cmd_ctx, "target isn't an XScale target");
+               return ERROR_OK;
+       }
+       
+       if ((argc >= 1) && (strcmp("enable", args[0]) == 0))
+       {
+               xscale->force_hw_bkpts = 1;
+       }
+       else if ((argc >= 1) && (strcmp("disable", args[0]) == 0))
+       {
+               xscale->force_hw_bkpts = 0;
+       }
+       else
+       {
+               command_print(cmd_ctx, "usage: xscale force_hw_bkpts <enable|disable>");
+       }
+               
+       command_print(cmd_ctx, "force hardware breakpoints %s", (xscale->force_hw_bkpts) ? "enabled" : "disabled");
+
+       return ERROR_OK;
+}
+
+int xscale_handle_trace_buffer_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       target_t *target = get_current_target(cmd_ctx);
+       armv4_5_common_t *armv4_5;
+       xscale_common_t *xscale;
+       u32 dcsr_value;
+       
+       if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK)
+       {
+               command_print(cmd_ctx, "target isn't an XScale target");
+               return ERROR_OK;
+       }
+       
+       if (target->state != TARGET_HALTED)
+       {
+               command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
+               return ERROR_OK;
+       }
+       
+       if ((argc >= 1) && (strcmp("enable", args[0]) == 0))
+       {
+               xscale->trace_buffer_enabled = 1;
+       }
+       else if ((argc >= 1) && (strcmp("disable", args[0]) == 0))
+       {
+               xscale->trace_buffer_enabled = 0;
+       }
+
+       if ((argc >= 2) && (strcmp("fill", args[1]) == 0))
+       {
+               xscale->trace_buffer_fill = 1;
+       }
+       else if ((argc >= 2) && (strcmp("wrap", args[1]) == 0))
+       {
+               xscale->trace_buffer_fill = 0;
+       }
+       
+       command_print(cmd_ctx, "trace buffer %s (%s)", 
+               (xscale->trace_buffer_enabled) ? "enabled" : "disabled",
+               (xscale->trace_buffer_fill) ? "fill" : "wrap");
+
+       dcsr_value = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 0, 32);
+       if (xscale->trace_buffer_fill)
+               xscale_write_dcsr_sw(target, (dcsr_value & 0xfffffffc) | 2);
+       else
+               xscale_write_dcsr_sw(target, dcsr_value & 0xfffffffc);
+               
+       return ERROR_OK;
+}
+
+int xscale_handle_dump_trace_buffer_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       target_t *target = get_current_target(cmd_ctx);
+       armv4_5_common_t *armv4_5;
+       xscale_common_t *xscale;
+       u32 trace_buffer[258];
+       int is_address[256];
+       int i;
+       
+       if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK)
+       {
+               command_print(cmd_ctx, "target isn't an XScale target");
+               return ERROR_OK;
+       }
+       
+       if (target->state != TARGET_HALTED)
+       {
+               command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
+               return ERROR_OK;
+       }
+
+       /* send read trace buffer command (command 0x61) */
+       xscale_send_u32(target, 0x61);
+       
+       /* receive trace buffer content */
+       xscale_receive(target, trace_buffer, 258);
+       
+       for (i = 255; i >= 0; i--)
+       {
+               is_address[i] = 0;
+               if (((trace_buffer[i] & 0xf0) == 0x90) ||
+                       ((trace_buffer[i] & 0xf0) == 0xd0)) 
+               {
+                       if (i >= 4)
+                               is_address[--i] = 1;
+                       if (i >= 3)
+                               is_address[--i] = 1;
+                       if (i >= 2)
+                               is_address[--i] = 1;
+                       if (i >= 1)
+                               is_address[--i] = 1;
+               }
+       }
+       
+       for (i = 0; i < 256; i++)
+       {
+#if 0
+               command_print(cmd_ctx, "0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x",
+                       trace_buffer[i + 0], trace_buffer[i + 1], trace_buffer[i + 2], trace_buffer[i + 3],
+                       trace_buffer[i + 4], trace_buffer[i + 5], trace_buffer[i + 6], trace_buffer[i + 6]
+                       );
+               i += 8;
+#endif
+               if (is_address[i])
+               {
+                       command_print(cmd_ctx, "address: 0x%2.2x%2.2x%2.2x%2.2x", trace_buffer[i], trace_buffer[i+1], trace_buffer[i+2], trace_buffer[i+3]);
+                       i += 3; 
+               }
+               else
+               {
+                       switch ((trace_buffer[i] & 0xf0) >> 4)
+                       {
+                               case 0:
+                                       command_print(cmd_ctx, "0x%2.2x: reset exception", trace_buffer[i]);
+                                       break;
+                               case 1:
+                                       command_print(cmd_ctx, "0x%2.2x: undef exception", trace_buffer[i]);
+                                       break;
+                               case 2:
+                                       command_print(cmd_ctx, "0x%2.2x: swi exception", trace_buffer[i]);
+                                       break;
+                               case 3:
+                                       command_print(cmd_ctx, "0x%2.2x: pabort exception", trace_buffer[i]);
+                                       break;
+                               case 4:
+                                       command_print(cmd_ctx, "0x%2.2x: dabort exception", trace_buffer[i]);
+                                       break;
+                               case 5:
+                                       command_print(cmd_ctx, "0x%2.2x: invalid", trace_buffer[i]);
+                                       break;
+                               case 6:
+                                       command_print(cmd_ctx, "0x%2.2x: irq exception", trace_buffer[i]);
+                                       break;
+                               case 7:
+                                       command_print(cmd_ctx, "0x%2.2x: fiq exception", trace_buffer[i]);
+                                       break;
+                               case 0x8:
+                                       command_print(cmd_ctx, "0x%2.2x: direct branch", trace_buffer[i]);
+                                       break;
+                               case 0x9:
+                                       command_print(cmd_ctx, "0x%2.2x: indirect branch", trace_buffer[i]);
+                                       break;
+                               case 0xa:
+                                       command_print(cmd_ctx, "0x%2.2x: invalid", trace_buffer[i]);
+                                       break;
+                               case 0xb:
+                                       command_print(cmd_ctx, "0x%2.2x: invalid", trace_buffer[i]);
+                                       break;
+                               case 0xc:
+                                       command_print(cmd_ctx, "0x%2.2x: checkpointed direct branch", trace_buffer[i]);
+                                       break;
+                               case 0xd:
+                                       command_print(cmd_ctx, "0x%2.2x: checkpointed indirect branch", trace_buffer[i]);
+                                       break;
+                               case 0xe:
+                                       command_print(cmd_ctx, "0x%2.2x: invalid", trace_buffer[i]);
+                                       break;
+                               case 0xf:
+                                       command_print(cmd_ctx, "0x%2.2x: rollover", trace_buffer[i]);
+                                       break;
+                       } 
+               }
+       }
+       
+       command_print(cmd_ctx, "chkpt0: 0x%8.8x, chkpt1: 0x%8.8x", trace_buffer[256], trace_buffer[257]);
+
+       return ERROR_OK;        
+}
+
+int xscale_register_commands(struct command_context_s *cmd_ctx)
+{
+       command_t *xscale_cmd;
+
+       xscale_cmd = register_command(cmd_ctx, NULL, "xscale", NULL, COMMAND_ANY, "xscale specific commands");
+       
+       register_command(cmd_ctx, xscale_cmd, "debug_handler", xscale_handle_debug_handler_command, COMMAND_CONFIG, NULL);
+       register_command(cmd_ctx, xscale_cmd, "cache_clean_address", xscale_handle_cache_clean_address_command, COMMAND_ANY, NULL);
+
+       register_command(cmd_ctx, xscale_cmd, "cache_info", xscale_handle_cache_info_command, COMMAND_EXEC, NULL);
+       register_command(cmd_ctx, xscale_cmd, "virt2phys", xscale_handle_virt2phys_command, COMMAND_EXEC, NULL);
+       register_command(cmd_ctx, xscale_cmd, "mmu", xscale_handle_mmu_command, COMMAND_EXEC, "['enable'|'disable'] the MMU");
+       register_command(cmd_ctx, xscale_cmd, "icache", xscale_handle_idcache_command, COMMAND_EXEC, "['enable'|'disable'] the ICache");
+       register_command(cmd_ctx, xscale_cmd, "dcache", xscale_handle_idcache_command, COMMAND_EXEC, "['enable'|'disable'] the DCache");
+       
+       register_command(cmd_ctx, xscale_cmd, "vector_catch", xscale_handle_idcache_command, COMMAND_EXEC, "<mask> of vectors that should be catched");
+       
+       register_command(cmd_ctx, xscale_cmd, "trace_buffer", xscale_handle_trace_buffer_command, COMMAND_EXEC, "<enable|disable> ['fill'|'wrap']");
+
+       register_command(cmd_ctx, xscale_cmd, "dump_trace_buffer", xscale_handle_dump_trace_buffer_command, COMMAND_EXEC, "dump content of trace buffer");
+       
+       armv4_5_register_commands(cmd_ctx);
+       
+       return ERROR_OK;
+}
diff --git a/src/target/xscale.h b/src/target/xscale.h
new file mode 100644 (file)
index 0000000..9fcb265
--- /dev/null
@@ -0,0 +1,145 @@
+/***************************************************************************
+ *   Copyright (C) 2005 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+#ifndef XSCALE_H
+#define XSCALE_H
+
+#include "target.h"
+#include "register.h"
+#include "armv4_5.h"
+#include "armv4_5_mmu.h"
+
+#define        XSCALE_COMMON_MAGIC 0x58534341
+
+typedef struct xscale_jtag_s
+{
+       /* position in JTAG scan chain */
+       int chain_pos;
+
+       /* IR length and instructions */        
+       int ir_length;
+       u32 dbgrx;
+       u32 dbgtx;
+       u32 ldic;
+       u32 dcsr;
+} xscale_jtag_t;
+
+enum xscale_debug_reason
+{
+       XSCALE_DBG_REASON_GENERIC,
+       XSCALE_DBG_REASON_RESET,
+       XSCALE_DBG_REASON_TB_FULL,
+};
+
+typedef struct xscale_common_s
+{
+       int common_magic;
+       
+       /* XScale registers (CP15, DBG) */
+       reg_cache_t *reg_cache;
+
+       /* pxa250, pxa255, pxa27x, ixp42x, ... */
+       char *variant;
+
+       xscale_jtag_t jtag_info;
+       
+       /* current state of the debug handler */
+       int handler_installed;
+       int handler_running;
+       u32 handler_address;
+       
+       /* target-endian buffers with exception vectors */
+       u32 low_vectors[8];
+       u32 high_vectors[8];
+       
+       /* static low vectors */
+       u8 static_low_vectors_set;      /* bit field with static vectors set by the user */
+       u8 static_high_vectors_set; /* bit field with static vectors set by the user */
+       u32 static_low_vectors[8];
+       u32 static_high_vectors[8];
+
+       /* DCache cleaning */   
+       u32 cache_clean_address;
+       
+       /* whether hold_rst and ext_dbg_break should be set */
+       int hold_rst;
+       int external_debug_break;
+       
+       /* breakpoint / watchpoint handling */
+       int force_hw_bkpts;
+       int dbr_available;
+       int dbr0_used;
+       int dbr1_used;
+       int ibcr_available;
+       int ibcr0_used;
+       int     ibcr1_used;
+       u32 arm_bkpt;
+       u16 thumb_bkpt;
+       
+       u8 vector_catch;
+       
+       int trace_buffer_enabled;
+       int trace_buffer_fill;
+       
+       int arch_debug_reason;
+       
+       /* armv4/5 common stuff */
+       armv4_5_common_t armv4_5_common;
+       
+       /* MMU/Caches */
+       armv4_5_mmu_common_t armv4_5_mmu;
+       u32 cp15_control_reg;
+       
+       /* possible future enhancements that go beyond XScale common stuff */
+       void *arch_info;
+} xscale_common_t;
+
+typedef struct xscale_reg_s
+{
+       int dbg_handler_number;
+       target_t *target;
+} xscale_reg_t;
+
+enum
+{
+       XSCALE_MAINID,          /* 0 */
+       XSCALE_CACHETYPE,
+       XSCALE_CTRL,
+       XSCALE_AUXCTRL,
+       XSCALE_TTB,
+       XSCALE_DAC,
+       XSCALE_FSR,
+       XSCALE_FAR,
+       XSCALE_PID,
+       XSCALE_CPACCESS,
+       XSCALE_IBCR0,           /* 10 */
+       XSCALE_IBCR1,
+       XSCALE_DBR0,
+       XSCALE_DBR1,
+       XSCALE_DBCON,
+       XSCALE_TBREG,
+       XSCALE_CHKPT0,
+       XSCALE_CHKPT1,
+       XSCALE_DCSR,
+       XSCALE_TX,
+       XSCALE_RX,                      /* 20 */
+       XSCALE_TXRXCTRL,
+};
+
+#endif /* XSCALE_H */
diff --git a/src/target/xscale/build.sh b/src/target/xscale/build.sh
new file mode 100644 (file)
index 0000000..fc828b2
--- /dev/null
@@ -0,0 +1,7 @@
+arm-none-eabi-gcc -c debug_handler.S -o debug_handler.o
+arm-none-eabi-ld -EL -n -Tdebug_handler.cmd debug_handler.o -o debug_handler.out
+arm-none-eabi-objcopy -O binary debug_handler.out debug_handler.bin
+
+#arm-none-eabi-gcc -mbig-endian -c debug_handler.S -o debug_handler_be.o
+#arm-none-eabi-ld -EB -n -Tdebug_handler.cmd debug_handler_be.o -o debug_handler_be.out
+#arm-none-eabi-objcopy -O binary debug_handler_be.out debug_handler_be.bin
diff --git a/src/target/xscale/debug_handler.S b/src/target/xscale/debug_handler.S
new file mode 100644 (file)
index 0000000..6d9b1cd
--- /dev/null
@@ -0,0 +1,718 @@
+/***************************************************************************
+ *   Copyright (C) 2006 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   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 "protocol.h"
+
+    .text
+    .align  4
+
+@ Disable thumb mode
+    .code 32
+
+@ send word to debugger
+.macro m_send_to_debugger reg
+1:
+       mrc p14, 0, r15, c14, c0, 0
+       bvs 1b
+       mcr p14, 0, \reg, c8, c0, 0     
+.endm
+
+@ receive word from debugger
+.macro m_receive_from_debugger reg
+1:
+       mrc p14, 0, r15, c14, c0, 0
+       bpl 1b
+       mrc p14, 0, \reg, c9, c0, 0     
+.endm
+
+@ save register on debugger, small
+.macro m_small_save_reg reg
+       mov r0, \reg
+       bl send_to_debugger
+.endm
+
+@ save status register on debugger, small
+.macro m_small_save_psr
+       mrs r0, spsr
+       bl send_to_debugger
+.endm
+
+@ wait for all outstanding coprocessor accesses to complete
+.macro m_cpwait
+       mrc p15, 0, r0, c2, c0, 0
+       mov r0, r0
+       sub pc, pc, #4
+.endm
+
+.global reset_handler
+.global undef_handler
+.global swi_handler
+.global prefetch_abort_handler
+.global data_abort_handler
+.global irq_handler
+.global fiq_handler
+
+.section .part1 , "ax"
+
+reset_handler:
+       @ read DCSR
+       mrc p14, 0, r13, c10, c0
+       @ check if global enable bit (GE) is set
+       ands r13, r13, #0x80000000
+       
+       bne debug_handler
+
+       @ set global enable bit (GE)
+       mov r13, #0xc0000000
+       mcr p14, 0, r13, c10, c0
+
+debug_handler:
+
+       @ save r0 without modifying other registers
+       m_send_to_debugger r0
+
+       @ save lr (program PC) without branching (use macro)
+       m_send_to_debugger r14
+
+       @ save non-banked registers and spsr (program CPSR)
+       m_small_save_reg r1
+       m_small_save_reg r2
+       m_small_save_reg r3
+       m_small_save_reg r4
+       m_small_save_reg r5
+       m_small_save_reg r6
+       m_small_save_reg r7
+       m_small_save_psr
+
+       mrs r0, spsr
+
+       @ prepare program PSR for debug use (clear Thumb, set I/F to disable interrupts)
+       bic r0, r0, #PSR_T
+       orr r0, r0, #(PSR_I | PSR_F)
+
+       @ examine mode bits
+       and r1, r0, #MODE_MASK
+       cmp r1, #MODE_USR
+
+       bne not_user_mode
+       
+       @ replace USR mode with SYS
+       bic r0, r0, #MODE_MASK
+       orr r0, r0, #MODE_SYS
+
+not_user_mode:
+
+       b save_banked_registers
+
+@ command loop
+@ wait for command from debugger, than execute desired function
+get_command:
+       bl receive_from_debugger
+       
+       @ 0x0n - register access
+       cmp r0, #0x0
+       beq get_banked_registers
+
+       cmp r0, #0x1
+       beq set_banked_registers
+
+       @ 0x1n - read memory
+       cmp r0, #0x11
+       beq read_byte
+
+       cmp r0, #0x12
+       beq read_half_word
+
+       cmp r0, #0x14
+       beq read_word
+
+       @ 0x2n - write memory
+       cmp r0, #0x21
+       beq write_byte
+       
+       cmp r0, #0x22
+       beq write_half_word
+       
+       cmp r0, #0x24
+       beq write_word
+
+       @ 0x3n - program execution
+       cmp r0, #0x30
+       beq resume
+
+       cmp r0, #0x31
+       beq resume_w_trace
+
+       @ 0x4n - coprocessor access
+       cmp r0, #0x40
+       beq read_cp_reg
+
+       cmp r0, #0x41
+       beq write_cp_reg
+
+       @ 0x5n - cache and mmu functions
+       cmp r0, #0x50
+       beq clean_d_cache
+
+       cmp r0, #0x51
+       beq invalidate_d_cache
+       
+       cmp r0, #0x52
+       beq invalidate_i_cache
+
+       cmp r0, #0x53
+       beq cpwait
+
+       @ 0x6n - misc functions
+       cmp r0, #0x60
+       beq clear_sa
+
+       cmp r0, #0x61
+       beq read_trace_buffer
+       
+       cmp r0, #0x62
+       beq clean_trace_buffer
+       
+       @ return (back to get_command)
+       b get_command
+
+@ ----
+
+@ resume program execution
+resume:
+       @ restore CPSR (SPSR_dbg)
+       bl receive_from_debugger
+       msr spsr, r0
+
+       @ restore registers (r7 - r0)
+       bl receive_from_debugger @ r7
+       mov r7, r0
+       bl receive_from_debugger @ r6
+       mov r6, r0
+       bl receive_from_debugger @ r5
+       mov r5, r0
+       bl receive_from_debugger @ r4
+       mov r4, r0
+       bl receive_from_debugger @ r3
+       mov r3, r0
+       bl receive_from_debugger @ r2
+       mov r2, r0
+       bl receive_from_debugger @ r1
+       mov r1, r0
+       bl receive_from_debugger @ r0
+
+       @ resume addresss
+       m_receive_from_debugger lr
+
+       @ branch back to application code, restoring CPSR
+       subs pc, lr, #0 
+
+@ get banked registers
+@ receive mode bits from host, then run into save_banked_registers to 
+       
+get_banked_registers:
+       bl receive_from_debugger
+
+@ save banked registers
+@ r0[4:0]: desired mode bits
+save_banked_registers:
+       @ backup CPSR
+       mrs r7, cpsr
+       msr cpsr_c, r0
+       nop
+
+       @ keep current mode bits in r1 for later use
+       and r1, r0, #MODE_MASK
+       
+       @ backup banked registers
+       m_send_to_debugger r8
+       m_send_to_debugger r9
+       m_send_to_debugger r10
+       m_send_to_debugger r11
+       m_send_to_debugger r12
+       m_send_to_debugger r13
+       m_send_to_debugger r14
+
+       @ if not in SYS mode (or USR, which we replaced with SYS before)
+       cmp r1, #MODE_SYS
+       
+       beq no_spsr_to_save
+
+       @ backup SPSR
+       mrs r0, spsr
+       m_send_to_debugger r0
+
+no_spsr_to_save:
+
+       @ restore CPSR for SDS
+       msr cpsr_c, r7
+       nop
+
+       @ return
+       b get_command
+
+@ ----
+
+
+@ set banked registers
+@ receive mode bits from host, then run into save_banked_registers to 
+       
+set_banked_registers:
+       bl receive_from_debugger
+
+@ restore banked registers
+@ r0[4:0]: desired mode bits
+restore_banked_registers:
+       @ backup CPSR
+       mrs r7, cpsr
+       msr cpsr_c, r0
+       nop
+
+       @ keep current mode bits in r1 for later use
+       and r1, r0, #MODE_MASK
+       
+       @ set banked registers
+       m_receive_from_debugger r8
+       m_receive_from_debugger r9
+       m_receive_from_debugger r10
+       m_receive_from_debugger r11
+       m_receive_from_debugger r12
+       m_receive_from_debugger r13
+       m_receive_from_debugger r14
+
+       @ if not in SYS mode (or USR, which we replaced with SYS before)
+       cmp r1, #MODE_SYS
+       
+       beq no_spsr_to_restore
+
+       @ set SPSR
+       m_receive_from_debugger r0
+       msr spsr, r0
+
+no_spsr_to_restore:
+
+       @ restore CPSR for SDS
+       msr cpsr_c, r7
+       nop
+
+       @ return
+       b get_command
+
+@ ----
+
+read_byte:
+       @ r2: address
+       bl receive_from_debugger
+       mov r2, r0
+
+       @ r1: count
+       bl receive_from_debugger
+       mov r1, r0
+
+rb_loop:
+       ldrb r0, [r2], #1
+       
+       @ drain write- (and fill-) buffer to work around XScale errata
+       mcr p15, 0, r8, c7, c10, 4
+
+       bl send_to_debugger
+
+       subs r1, r1, #1
+       bne rb_loop
+       
+       @ return
+       b get_command
+
+@ ----
+
+read_half_word:
+       @ r2: address
+       bl receive_from_debugger
+       mov r2, r0
+
+       @ r1: count
+       bl receive_from_debugger
+       mov r1, r0
+
+rh_loop:
+       ldrh r0, [r2], #2
+       
+       @ drain write- (and fill-) buffer to work around XScale errata
+       mcr p15, 0, r8, c7, c10, 4
+
+       bl send_to_debugger
+
+       subs r1, r1, #1
+       bne rh_loop
+       
+       @ return
+       b get_command
+
+@ ----
+
+read_word:
+       @ r2: address
+       bl receive_from_debugger
+       mov r2, r0
+
+       @ r1: count
+       bl receive_from_debugger
+       mov r1, r0
+
+rw_loop:
+       ldr r0, [r2], #4
+       
+       @ drain write- (and fill-) buffer to work around XScale errata
+       mcr p15, 0, r8, c7, c10, 4
+
+       bl send_to_debugger
+
+       subs r1, r1, #1
+       bne rw_loop
+       
+       @ return
+       b get_command
+
+@ ----
+
+write_byte:
+       @ r2: address
+       bl receive_from_debugger
+       mov r2, r0
+
+       @ r1: count
+       bl receive_from_debugger
+       mov r1, r0
+
+wb_loop:
+       bl receive_from_debugger
+       strb r0, [r2], #1
+
+       @ drain write- (and fill-) buffer to work around XScale errata
+       mcr p15, 0, r8, c7, c10, 4
+
+       subs r1, r1, #1
+       bne wb_loop
+       
+       @ return
+       b get_command
+
+@ ----
+
+write_half_word:
+       @ r2: address
+       bl receive_from_debugger
+       mov r2, r0
+
+       @ r1: count
+       bl receive_from_debugger
+       mov r1, r0
+
+wh_loop:
+       bl receive_from_debugger
+       strh r0, [r2], #2
+
+       @ drain write- (and fill-) buffer to work around XScale errata
+       mcr p15, 0, r8, c7, c10, 4
+
+       subs r1, r1, #1
+       bne wh_loop
+       
+       @ return
+       b get_command
+
+@ ----
+
+write_word:
+       @ r2: address
+       bl receive_from_debugger
+       mov r2, r0
+
+       @ r1: count
+       bl receive_from_debugger
+       mov r1, r0
+
+ww_loop:
+       bl receive_from_debugger
+       str r0, [r2], #4
+
+       @ drain write- (and fill-) buffer to work around XScale errata
+       mcr p15, 0, r8, c7, c10, 4
+
+       subs r1, r1, #1
+       bne ww_loop
+       
+       @ return
+       b get_command
+
+@ ----
+
+clear_sa:
+       @ read DCSR
+       mrc p14, 0, r0, c10, c0
+       
+       @ clear SA bit
+       bic r0, r0, #0x20
+
+       @ write DCSR
+       mcr p14, 0, r0, c10, c0
+
+       @ return
+       b get_command
+
+@ ----
+
+clean_d_cache:
+       @ r0: cache clean area
+       bl receive_from_debugger
+       
+       mov r1, #1024
+clean_loop:
+       mcr p15, 0, r0, c7, c2, 5
+       add r0, r0, #32
+       subs r1, r1, #1
+       bne clean_loop
+
+       @ return
+       b get_command
+
+@ ----
+
+invalidate_d_cache:
+       mcr p15, 0, r0, c7, c6, 0
+
+       @ return
+       b get_command
+
+@ ----
+
+invalidate_i_cache:
+       mcr p15, 0, r0, c7, c5, 0
+
+       @ return
+       b get_command
+
+@ ----
+
+cpwait:
+       m_cpwait
+
+       @return
+       b get_command
+
+@ ----
+
+.section .part2 , "ax"
+
+read_cp_reg:
+       @ requested cp register
+       bl receive_from_debugger
+
+       adr r1, read_cp_table
+       add pc, r1, r0, lsl #3
+
+read_cp_table:
+       mrc p15, 0, r0, c0, c0, 0  @ XSCALE_MAINID
+       b read_cp_reg_reply
+       mrc p15, 0, r0, c0, c0, 1  @ XSCALE_CACHETYPE
+       b read_cp_reg_reply
+       mrc p15, 0, r0, c1, c0, 0  @ XSCALE_CTRL
+       b read_cp_reg_reply
+       mrc p15, 0, r0, c1, c0, 1  @ XSCALE_AUXCTRL
+       b read_cp_reg_reply
+       mrc p15, 0, r0, c2, c0, 0  @ XSCALE_TTB
+       b read_cp_reg_reply
+       mrc p15, 0, r0, c3, c0, 0  @ XSCALE_DAC
+       b read_cp_reg_reply
+       mrc p15, 0, r0, c5, c0, 0  @ XSCALE_FSR
+       b read_cp_reg_reply
+       mrc p15, 0, r0, c6, c0, 0  @ XSCALE_FAR
+       b read_cp_reg_reply
+       mrc p15, 0, r0, c13, c0, 0  @ XSCALE_PID
+       b read_cp_reg_reply
+       mrc p15, 0, r0, c15, c0, 0  @ XSCALE_CP_ACCESS
+       b read_cp_reg_reply
+       mrc p15, 0, r0, c14, c8, 0  @ XSCALE_IBCR0
+       b read_cp_reg_reply
+       mrc p15, 0, r0, c14, c9, 0  @ XSCALE_IBCR1
+       b read_cp_reg_reply
+       mrc p15, 0, r0, c14, c0, 0  @ XSCALE_DBR0
+       b read_cp_reg_reply
+       mrc p15, 0, r0, c14, c3, 0  @ XSCALE_DBR1
+       b read_cp_reg_reply
+       mrc p15, 0, r0, c14, c4, 0  @ XSCALE_DBCON
+       b read_cp_reg_reply
+       mrc p14, 0, r0, c11, c0, 0 @ XSCALE_TBREG
+       b read_cp_reg_reply
+       mrc p14, 0, r0, c12, c0, 0 @ XSCALE_CHKPT0
+       b read_cp_reg_reply
+       mrc p14, 0, r0, c13, c0, 0 @ XSCALE_CHKPT1
+       b read_cp_reg_reply
+       mrc p14, 0, r0, c10, c0, 0 @ XSCALE_DCSR
+       b read_cp_reg_reply
+
+read_cp_reg_reply:
+       bl send_to_debugger     
+
+       @ return
+       b get_command
+
+@ ----
+
+write_cp_reg:
+       @ requested cp register
+       bl receive_from_debugger
+       mov r1, r0
+
+       @ value to be written
+       bl receive_from_debugger
+
+       adr r2, write_cp_table
+       add pc, r2, r1, lsl #3
+
+write_cp_table:
+       mcr p15, 0, r0, c0, c0, 0  @ XSCALE_MAINID (0x0)
+       b get_command
+       mcr p15, 0, r0, c0, c0, 1  @ XSCALE_CACHETYPE (0x1)
+       b get_command
+       mcr p15, 0, r0, c1, c0, 0  @ XSCALE_CTRL (0x2)
+       b get_command
+       mcr p15, 0, r0, c1, c0, 1  @ XSCALE_AUXCTRL (0x3)
+       b get_command
+       mcr p15, 0, r0, c2, c0, 0  @ XSCALE_TTB (0x4)
+       b get_command
+       mcr p15, 0, r0, c3, c0, 0  @ XSCALE_DAC (0x5)
+       b get_command
+       mcr p15, 0, r0, c5, c0, 0  @ XSCALE_FSR (0x6)
+       b get_command
+       mcr p15, 0, r0, c6, c0, 0  @ XSCALE_FAR (0x7)
+       b get_command
+       mcr p15, 0, r0, c13, c0, 0  @ XSCALE_PID (0x8)
+       b get_command
+       mcr p15, 0, r0, c15, c0, 0  @ XSCALE_CP_ACCESS (0x9)
+       b get_command
+       mcr p15, 0, r0, c14, c8, 0  @ XSCALE_IBCR0 (0xa)
+       b get_command
+       mcr p15, 0, r0, c14, c9, 0  @ XSCALE_IBCR1 (0xb)
+       b get_command
+       mcr p15, 0, r0, c14, c0, 0  @ XSCALE_DBR0 (0xc)
+       b get_command
+       mcr p15, 0, r0, c14, c3, 0  @ XSCALE_DBR1 (0xd)
+       b get_command
+       mcr p15, 0, r0, c14, c4, 0  @ XSCALE_DBCON (0xe)
+       b get_command
+       mcr p14, 0, r0, c11, c0, 0 @ XSCALE_TBREG (0xf)
+       b get_command
+       mcr p14, 0, r0, c12, c0, 0 @ XSCALE_CHKPT0 (0x10)
+       b get_command
+       mcr p14, 0, r0, c13, c0, 0 @ XSCALE_CHKPT1 (0x11)
+       b get_command
+       mcr p14, 0, r0, c10, c0, 0 @ XSCALE_DCSR (0x12)
+       b get_command
+
+@ ----
+
+read_trace_buffer:
+
+       @ dump 256 entries from trace buffer
+       mov     r1, #256
+read_tb_loop:
+       mrc p14, 0, r0, c11, c0, 0 @ XSCALE_TBREG
+       bl send_to_debugger
+       subs r1, r1, #1
+       bne read_tb_loop
+
+       @ dump checkpoint register 0
+       mrc p14, 0, r0, c12, c0, 0 @ XSCALE_CHKPT0 (0x10)
+       bl send_to_debugger
+       
+       @ dump checkpoint register 1
+       mrc p14, 0, r0, c13, c0, 0 @ XSCALE_CHKPT1 (0x11)
+       bl send_to_debugger
+
+       @ return
+       b get_command
+       
+@ ----
+
+clean_trace_buffer:
+
+       @ clean 256 entries from trace buffer
+       mov     r1, #256
+clean_tb_loop:
+       mrc p14, 0, r0, c11, c0, 0 @ XSCALE_TBREG
+       subs r1, r1, #1
+       bne clean_tb_loop
+
+       @ return
+       b get_command
+       
+@ ----
+
+
+@ resume program execution with trace buffer enabled
+resume_w_trace:
+       @ restore CPSR (SPSR_dbg)
+       bl receive_from_debugger
+       msr spsr, r0
+
+       @ restore registers (r7 - r0)
+       bl receive_from_debugger @ r7
+       mov r7, r0
+       bl receive_from_debugger @ r6
+       mov r6, r0
+       bl receive_from_debugger @ r5
+       mov r5, r0
+       bl receive_from_debugger @ r4
+       mov r4, r0
+       bl receive_from_debugger @ r3
+       mov r3, r0
+       bl receive_from_debugger @ r2
+       mov r2, r0
+       bl receive_from_debugger @ r1
+       mov r1, r0
+       bl receive_from_debugger @ r0
+
+       @ resume addresss
+       m_receive_from_debugger lr
+
+       mrc p14, 0, r13, c10, c0, 0 @ XSCALE_DCSR
+       orr r13, r13, #1
+       mcr p14, 0, r13, c10, c0, 0 @ XSCALE_DCSR
+
+       @ branch back to application code, restoring CPSR
+       subs pc, lr, #0 
+
+undef_handler:
+swi_handler:
+prefetch_abort_handler:
+data_abort_handler:
+irq_handler:
+fiq_handler:
+1:
+       b 1b
+
+send_to_debugger:
+       m_send_to_debugger r0
+       mov pc, lr
+
+receive_from_debugger:
+       m_receive_from_debugger r0
+       mov pc, lr
+
diff --git a/src/target/xscale/debug_handler.cmd b/src/target/xscale/debug_handler.cmd
new file mode 100644 (file)
index 0000000..183c202
--- /dev/null
@@ -0,0 +1,49 @@
+/* identify the Entry Point  */
+ENTRY(reset_handler)
+
+/* specify the mini-ICache memory areas  */
+MEMORY 
+{
+       mini_icache_0 (x)                               : ORIGIN = 0x0, LENGTH = 1024   /* first part of mini icache (sets 0-31) */
+       mini_icache_1 (x)                               : ORIGIN = 0x400, LENGTH = 1024 /* second part of mini icache (sets 0-31) */
+}
+
+/* now define the output sections  */
+SECTIONS 
+{
+       .part1 :
+       {
+               LONG(0)
+               LONG(0)
+               LONG(0)
+               LONG(0)
+               LONG(0)
+               LONG(0)
+               LONG(0)
+               LONG(0)
+               *(.part1)
+       } >mini_icache_0
+
+       .part2 :
+       {
+               LONG(0)
+               LONG(0)
+               LONG(0)
+               LONG(0)
+               LONG(0)
+               LONG(0)
+               LONG(0)
+               LONG(0)
+               *(.part2)
+               FILL(0x0)
+       } >mini_icache_1
+
+       /DISCARD/ :
+       {
+               *(.text)
+               *(.glue_7)
+               *(.glue_7t)
+               *(.data)
+               *(.bss)
+       }
+}
diff --git a/src/target/xscale/protocol.h b/src/target/xscale/protocol.h
new file mode 100644 (file)
index 0000000..525db31
--- /dev/null
@@ -0,0 +1,70 @@
+/***************************************************************************
+ *   Copyright (C) 2006 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+
+#define REG_R0 0
+#define REG_R1 1
+#define REG_R2 2
+#define REG_R3 3
+#define REG_R4 4
+#define REG_R5 5
+#define REG_R6 6
+#define REG_R7 7
+#define REG_R8 8
+#define REG_R9 9
+#define REG_R10 10
+#define REG_R11 11
+#define REG_R12 12
+#define REG_R13 13
+#define REG_R14 14
+#define REG_R15 15
+#define REG_CPSR 16
+#define REG_SPSR 17
+
+#define MODE_USR 0x10 
+#define MODE_FIQ 0x11
+#define MODE_IRQ 0x12 
+#define MODE_SVC 0x13 
+#define MODE_ABT 0x17
+#define MODE_UND 0x1b
+#define MODE_SYS 0x1f
+
+#define MODE_ANY 0x40
+#define MODE_CURRENT 0x80
+
+#define MODE_MASK 0x1f
+#define PSR_I 0x80
+#define PSR_F 0x40
+#define PSR_T 0x20
+
+#define XSCALE_DBG_MAINID 0x0
+#define XSCALE_DBG_CACHETYPE 0x1
+#define XSCALE_DBG_CTRL 0x2
+#define XSCALE_DBG_AUXCTRL 0x3
+#define XSCALE_DBG_TTB 0x4
+#define XSCALE_DBG_DAC 0x5
+#define XSCALE_DBG_FSR 0x6
+#define XSCALE_DBG_FAR 0x7
+#define XSCALE_DBG_PID 0x8
+#define XSCALE_DBG_CPACCESS 0x9
+#define XSCALE_DBG_IBCR0 0xa
+#define XSCALE_DBG_IBCR1 0xb
+#define XSCALE_DBG_DBR0 0xc
+#define XSCALE_DBG_DBR1 0xd
+#define XSCALE_DBG_DBCON 0xe

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)