- 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