From 237e894805dd757cc24029af1b4b1e824c51712b Mon Sep 17 00:00:00 2001
From: drath <drath@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Date: Tue, 29 May 2007 11:23:42 +0000
Subject: - split fileio handling into fileio part and image handling -
 reworked etm/etb into a generic etm part with trace capture drivers
 (currently only etb supported) - added XScale debug handler binary to
 repository - added Thumb disassembling (thanks to Vincent Palatin for this
 patch) - added support for non-CFI compatible flashes to cfi driver
 (currently only SST39VFxxx devices supported) This checkin is experimental,
 not suitable for general use

git-svn-id: svn://svn.berlios.de/openocd/trunk@155 b42882b7-edfa-0310-969c-e2dbd0fdcd60
---
 src/target/Makefile.am              |   4 +-
 src/target/arm7_9_common.c          |  85 +---
 src/target/arm7_9_common.h          |   7 +-
 src/target/arm7tdmi.c               |   6 +-
 src/target/arm9tdmi.c               |  12 +-
 src/target/arm_disassembler.c       | 787 +++++++++++++++++++++++++++++++++++-
 src/target/arm_disassembler.h       |   5 +-
 src/target/arm_simulator.c          |  50 ++-
 src/target/armv4_5.h                |   8 +-
 src/target/etb.c                    | 543 +++++++++++++------------
 src/target/etb.h                    |  12 +-
 src/target/etm.c                    | 686 ++++++++++++++++++++++++++++++-
 src/target/etm.h                    | 131 +++++-
 src/target/target.c                 |  56 ++-
 src/target/xscale/debug_handler.bin | Bin 0 -> 1592 bytes
 15 files changed, 1968 insertions(+), 424 deletions(-)
 create mode 100755 src/target/xscale/debug_handler.bin

(limited to 'src/target')

diff --git a/src/target/Makefile.am b/src/target/Makefile.am
index cf1955a0..b1e6f919 100644
--- a/src/target/Makefile.am
+++ b/src/target/Makefile.am
@@ -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 xscale.c arm_simulator.c
+	arm966e.c arm926ejs.c etb.c xscale.c arm_simulator.c image.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 xscale.h arm_simulator.h
+		arm_disassembler.h arm966e.h arm926ejs.h etb.h xscale.h arm_simulator.h image.h
diff --git a/src/target/arm7_9_common.c b/src/target/arm7_9_common.c
index 2c82c91e..77a43fee 100644
--- a/src/target/arm7_9_common.c
+++ b/src/target/arm7_9_common.c
@@ -2096,8 +2096,6 @@ int arm7_9_register_commands(struct command_context_s *cmd_ctx)
 	
 	arm7_9_cmd = register_command(cmd_ctx, NULL, "arm7_9", NULL, COMMAND_ANY, "arm7/9 specific commands");
 
-	register_command(cmd_ctx, arm7_9_cmd, "etm", handle_arm7_9_etm_command, COMMAND_CONFIG, NULL);
-	
 	register_command(cmd_ctx, arm7_9_cmd, "write_xpsr", handle_arm7_9_write_xpsr_command, COMMAND_EXEC, "write program status register <value> <not cpsr|spsr>");
 	register_command(cmd_ctx, arm7_9_cmd, "write_xpsr_im8", handle_arm7_9_write_xpsr_im8_command, COMMAND_EXEC, "write program status register <8bit immediate> <rotate> <not cpsr|spsr>");
 	
@@ -2115,7 +2113,8 @@ int arm7_9_register_commands(struct command_context_s *cmd_ctx)
 		COMMAND_ANY, "use DCC downloads for larger memory writes <enable|disable>");
 
 	armv4_5_register_commands(cmd_ctx);
-	etb_register_commands(cmd_ctx, arm7_9_cmd);
+	
+	etm_register_commands(cmd_ctx);
 	
 	return ERROR_OK;
 }
@@ -2425,83 +2424,6 @@ int handle_arm7_9_dcc_downloads_command(struct command_context_s *cmd_ctx, char
 	return ERROR_OK;
 }
 
-int handle_arm7_9_etm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
-	target_t *target;
-	armv4_5_common_t *armv4_5;
-	arm7_9_common_t *arm7_9;
-	
-	if (argc != 1)
-	{
-		ERROR("incomplete 'arm7_9 etm <target>' command");
-		exit(-1);
-	}
-	
-	target = get_target_by_num(strtoul(args[0], NULL, 0));
-	
-	if (!target)
-	{
-		ERROR("target number '%s' not defined", args[0]);
-		exit(-1);
-	}
-	
-	if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
-	{
-		command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
-		return ERROR_OK;
-	}
-	
-	arm7_9->has_etm = 1;
-	
-	return ERROR_OK;
-}
-
-int handle_arm7_9_etb_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
-	target_t *target;
-	jtag_device_t *jtag_device;
-	armv4_5_common_t *armv4_5;
-	arm7_9_common_t *arm7_9;
-	
-	if (argc != 2)
-	{
-		ERROR("incomplete 'arm7_9 etb <target> <chain_pos>' command");
-		exit(-1);
-	}
-	
-	target = get_target_by_num(strtoul(args[0], NULL, 0));
-	
-	if (!target)
-	{
-		ERROR("target number '%s' not defined", args[0]);
-		exit(-1);
-	}
-	
-	if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
-	{
-		command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
-		return ERROR_OK;
-	}
-	
-	jtag_device = jtag_get_device(strtoul(args[1], NULL, 0));
-	
-	if (!jtag_device)
-	{
-		ERROR("jtag device number '%s' not defined", args[1]);
-		exit(-1);
-	}
-
-	arm7_9->etb = malloc(sizeof(etb_t));
-	
-	arm7_9->etb->chain_pos = strtoul(args[1], NULL, 0);
-	arm7_9->etb->cur_scan_chain = -1;
-	arm7_9->etb->reg_cache = NULL;
-	arm7_9->etb->RAM_width = 0;
-	arm7_9->etb->RAM_depth = 0;
-
-	return ERROR_OK;
-}
-
 int arm7_9_init_arch_info(target_t *target, arm7_9_common_t *arm7_9)
 {
 	armv4_5_common_t *armv4_5 = &arm7_9->armv4_5_common;
@@ -2515,8 +2437,7 @@ int arm7_9_init_arch_info(target_t *target, arm7_9_common_t *arm7_9)
 	arm7_9->force_hw_bkpts = 0;
 	arm7_9->use_dbgrq = 0;
 	
-	arm7_9->has_etm = 0;
-	arm7_9->etb = NULL;
+	arm7_9->etm_ctx = NULL;
 	arm7_9->has_single_step = 0;
 	arm7_9->has_monitor_mode = 0;
 	arm7_9->has_vector_catch = 0;
diff --git a/src/target/arm7_9_common.h b/src/target/arm7_9_common.h
index e77bedac..fbcb920d 100644
--- a/src/target/arm7_9_common.h
+++ b/src/target/arm7_9_common.h
@@ -25,7 +25,7 @@
 #include "breakpoints.h"
 #include "target.h"
 
-#include "etb.h"
+#include "etm.h"
 
 #define	ARM7_9_COMMON_MAGIC 0x0a790a79
 
@@ -35,7 +35,6 @@ typedef struct arm7_9_common_s
 	
 	arm_jtag_t jtag_info;
 	reg_cache_t *eice_cache;
-	reg_cache_t *etm_cache;
 	
 	u32 arm_bkpt;
 	u16 thumb_bkpt;
@@ -48,8 +47,8 @@ typedef struct arm7_9_common_s
 	int dbgreq_adjust_pc;
 	int use_dbgrq;
 	
-	int has_etm;
-	etb_t *etb;
+	etm_context_t *etm_ctx;
+	
 	int has_single_step;
 	int has_monitor_mode;
 	int has_vector_catch;
diff --git a/src/target/arm7tdmi.c b/src/target/arm7tdmi.c
index 5684dcfa..7c6b937f 100644
--- a/src/target/arm7tdmi.c
+++ b/src/target/arm7tdmi.c
@@ -744,10 +744,10 @@ void arm7tdmi_build_reg_cache(target_t *target)
 	(*cache_p)->next = embeddedice_build_reg_cache(target, arm7_9);
 	arm7_9->eice_cache = (*cache_p)->next;
 	
-	if (arm7_9->has_etm)
+	if (arm7_9->etm_ctx)
 	{
-		(*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, 0);
-		arm7_9->etm_cache = (*cache_p)->next->next;
+		(*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, arm7_9->etm_ctx);
+		arm7_9->etm_ctx->reg_cache = (*cache_p)->next->next;
 	}
 }
 
diff --git a/src/target/arm9tdmi.c b/src/target/arm9tdmi.c
index 112926d1..7ecd1f0d 100644
--- a/src/target/arm9tdmi.c
+++ b/src/target/arm9tdmi.c
@@ -874,16 +874,10 @@ void arm9tdmi_build_reg_cache(target_t *target)
 	(*cache_p)->next = embeddedice_build_reg_cache(target, arm7_9);
 	arm7_9->eice_cache = (*cache_p)->next;
 
-	if (arm7_9->has_etm)
+	if (arm7_9->etm_ctx)
 	{
-		(*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, 0);
-		arm7_9->etm_cache = (*cache_p)->next->next;
-	}
-	
-	if (arm7_9->etb)
-	{
-		(*cache_p)->next->next->next = etb_build_reg_cache(arm7_9->etb);
-		arm7_9->etb->reg_cache = (*cache_p)->next->next->next;
+		(*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, arm7_9->etm_ctx);
+		arm7_9->etm_ctx->reg_cache = (*cache_p)->next->next;
 	}
 }
 
diff --git a/src/target/arm_disassembler.c b/src/target/arm_disassembler.c
index dd779282..1c275f54 100644
--- a/src/target/arm_disassembler.c
+++ b/src/target/arm_disassembler.c
@@ -343,7 +343,10 @@ int evaluate_load_store(u32 opcode, u32 address, arm_instruction_t *instruction)
 	if (!I) /* #+-<offset_12> */
 	{
 		u32 offset_12 = (opcode & 0xfff);
-		snprintf(offset, 32, "#%s0x%x", (U) ? "" : "-", offset_12);
+		if (offset_12)
+			snprintf(offset, 32, ", #%s0x%x", (U) ? "" : "-", offset_12);
+		else
+			snprintf(offset, 32, "");
 		
 		instruction->info.load_store.offset_mode = 0;
 		instruction->info.load_store.offset.offset = offset_12;
@@ -376,26 +379,26 @@ int evaluate_load_store(u32 opcode, u32 address, arm_instruction_t *instruction)
 
 		if ((shift_imm == 0x0) && (shift == 0x0)) /* +-<Rm> */
 		{
-			snprintf(offset, 32, "%sr%i", (U) ? "" : "-", Rm);
+			snprintf(offset, 32, ", %sr%i", (U) ? "" : "-", Rm);
 		}
 		else /* +-<Rm>, <Shift>, #<shift_imm> */
 		{
 			switch (shift)
 			{
 				case 0x0: /* LSL */
-					snprintf(offset, 32, "%sr%i, LSL #0x%x", (U) ? "" : "-", Rm, shift_imm);
+					snprintf(offset, 32, ", %sr%i, LSL #0x%x", (U) ? "" : "-", Rm, shift_imm);
 					break;
 				case 0x1: /* LSR */
-					snprintf(offset, 32, "%sr%i, LSR #0x%x", (U) ? "" : "-", Rm, shift_imm);
+					snprintf(offset, 32, ", %sr%i, LSR #0x%x", (U) ? "" : "-", Rm, shift_imm);
 					break;
 				case 0x2: /* ASR */
-					snprintf(offset, 32, "%sr%i, ASR #0x%x", (U) ? "" : "-", Rm, shift_imm);
+					snprintf(offset, 32, ", %sr%i, ASR #0x%x", (U) ? "" : "-", Rm, shift_imm);
 					break;
 				case 0x3: /* ROR */
-					snprintf(offset, 32, "%sr%i, ROR #0x%x", (U) ? "" : "-", Rm, shift_imm);
+					snprintf(offset, 32, ", %sr%i, ROR #0x%x", (U) ? "" : "-", Rm, shift_imm);
 					break;
 				case 0x4: /* RRX */
-					snprintf(offset, 32, "%sr%i, RRX", (U) ? "" : "-", Rm);
+					snprintf(offset, 32, ", %sr%i, RRX", (U) ? "" : "-", Rm);
 					break;
 			}
 		}
@@ -405,7 +408,7 @@ int evaluate_load_store(u32 opcode, u32 address, arm_instruction_t *instruction)
 	{
 		if (W == 0) /* offset */
 		{
-			snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i, %s]",
+			snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i%s]",
 					 address, opcode, operation, COND(opcode), suffix,
 					 Rd, Rn, offset);
 			
@@ -413,7 +416,7 @@ int evaluate_load_store(u32 opcode, u32 address, arm_instruction_t *instruction)
 		}
 		else /* pre-indexed */
 		{
-			snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i, %s]!",
+			snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i%s]!",
 					 address, opcode, operation, COND(opcode), suffix,
 					 Rd, Rn, offset);
 			
@@ -422,7 +425,7 @@ int evaluate_load_store(u32 opcode, u32 address, arm_instruction_t *instruction)
 	}
 	else /* post-indexed */
 	{
-		snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i], %s",
+		snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i]%s",
 				 address, opcode, operation, COND(opcode), suffix,
 				 Rd, Rn, offset);
 		
@@ -1157,7 +1160,10 @@ int evaluate_data_proc(u32 opcode, u32 address, arm_instruction_t *instruction)
 	}
 	else if ((op == 0xd) || (op == 0xf)) /* <opcode1>{<cond>}{S} <Rd>, <shifter_operand> */
 	{
-		snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, %s",
+		if (opcode==0xe1a00000) /* print MOV r0,r0 as NOP */
+			snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tNOP",address, opcode);
+		else
+			snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, %s",
 				 address, opcode, mnemonic, COND(opcode),
 				 (S) ? "S" : "", Rd, shifter_operand);
 	}
@@ -1315,3 +1321,762 @@ int arm_evaluate_opcode(u32 opcode, u32 address, arm_instruction_t *instruction)
 	return -1;
 }
 
+int evaluate_b_bl_blx_thumb(u16 opcode, u32 address, arm_instruction_t *instruction)
+{
+	u32 offset = opcode & 0x7ff;
+	u32 opc = (opcode >> 11) & 0x3;
+	u32 target_address;
+	char *mnemonic = NULL;
+	
+	/* sign extend 11-bit offset */
+	if (((opc==0) || (opc==2)) && (offset & 0x00000400))
+		offset = 0xfffff800 | offset;
+	
+	target_address = address + 4 + (offset<<1);
+
+	switch(opc)
+	{
+		/* unconditional branch */
+		case 0:
+			instruction->type = ARM_B;
+			mnemonic = "B";
+			break;
+		/* BLX suffix */
+		case 1:
+			instruction->type = ARM_BLX;
+			mnemonic = "BLX";
+			break;
+		/* BL/BLX prefix */
+		case 2:
+			instruction->type = ARM_UNKNOWN_INSTUCTION;
+			mnemonic = "prefix";
+			target_address = offset<<12;
+			break;
+		/* BL suffix */
+		case 3:
+			instruction->type = ARM_BL;
+			mnemonic = "BL";
+			break;
+	}
+	/* TODO: deals correctly with dual opcodes BL/BLX ... */
+
+	snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s 0x%8.8x", address, opcode,mnemonic, target_address);
+	
+	instruction->info.b_bl_bx_blx.reg_operand = -1;
+	instruction->info.b_bl_bx_blx.target_address = target_address;
+
+	return ERROR_OK;
+}
+
+int evaluate_add_sub_thumb(u16 opcode, u32 address, arm_instruction_t *instruction)
+{
+	u8 Rd = (opcode >> 0) & 0x7;
+	u8 Rn = (opcode >> 3) & 0x7;
+	u8 Rm_imm = (opcode >> 6) & 0x7;
+	u32 opc = opcode & (1<<9);
+	u32 reg_imm  = opcode & (1<<10);
+	char *mnemonic;
+	
+	if (opc)
+	{
+		instruction->type = ARM_SUB;
+		mnemonic = "SUBS";
+	}
+	else
+	{
+		instruction->type = ARM_ADD;
+		mnemonic = "ADDS";
+	}
+	
+	instruction->info.data_proc.Rd = Rd;
+	instruction->info.data_proc.Rn = Rn;
+	instruction->info.data_proc.S = 1;
+
+	if (reg_imm)
+	{
+		instruction->info.data_proc.variant = 0; /*immediate*/
+		instruction->info.data_proc.shifter_operand.immediate.immediate = Rm_imm;
+		snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s r%i, r%i, #%d",
+				 address, opcode, mnemonic, Rd, Rn, Rm_imm);
+	}
+	else
+	{
+		instruction->info.data_proc.variant = 1; /*immediate shift*/
+		instruction->info.data_proc.shifter_operand.immediate_shift.Rm = Rm_imm;
+		snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s r%i, r%i, r%i",
+				 address, opcode, mnemonic, Rd, Rn, Rm_imm);
+	}
+
+	return ERROR_OK;
+}
+
+int evaluate_shift_imm_thumb(u16 opcode, u32 address, arm_instruction_t *instruction)
+{
+	u8 Rd = (opcode >> 0) & 0x7;
+	u8 Rm = (opcode >> 3) & 0x7;
+	u8 imm = (opcode >> 6) & 0x1f;
+	u8 opc = (opcode >> 11) & 0x3;
+	char *mnemonic = NULL;
+	
+	switch(opc)
+	{
+		case 0:
+			instruction->type = ARM_MOV;
+			mnemonic = "LSLS";
+			instruction->info.data_proc.shifter_operand.immediate_shift.shift = 0;
+			break;
+		case 1:
+			instruction->type = ARM_MOV;
+			mnemonic = "LSRS";
+			instruction->info.data_proc.shifter_operand.immediate_shift.shift = 1;
+			break;
+		case 2:
+			instruction->type = ARM_MOV;
+			mnemonic = "ASRS";
+			instruction->info.data_proc.shifter_operand.immediate_shift.shift = 2;
+			break;
+	}
+
+	if ((imm==0) && (opc!=0))
+		imm = 32;
+
+	instruction->info.data_proc.Rd = Rd;
+	instruction->info.data_proc.Rn = -1;
+	instruction->info.data_proc.S = 1;
+
+	instruction->info.data_proc.variant = 1; /*immediate_shift*/
+	instruction->info.data_proc.shifter_operand.immediate_shift.Rm = Rm;
+	instruction->info.data_proc.shifter_operand.immediate_shift.shift_imm = imm;
+
+	snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s r%i, r%i, #0x%02x",
+				 address, opcode, mnemonic, Rd, Rm, imm);
+
+	return ERROR_OK;
+}
+
+int evaluate_data_proc_imm_thumb(u16 opcode, u32 address, arm_instruction_t *instruction)
+{
+	u8 imm = opcode & 0xff;
+	u8 Rd = (opcode >> 8) & 0x7;
+	u32 opc = (opcode >> 11) & 0x3;
+	char *mnemonic = NULL;
+	
+	instruction->info.data_proc.Rd = Rd;
+	instruction->info.data_proc.Rn = Rd;
+	instruction->info.data_proc.S = 1;
+	instruction->info.data_proc.variant = 0; /*immediate*/
+	instruction->info.data_proc.shifter_operand.immediate.immediate = imm;
+	
+	switch(opc)
+	{
+		case 0:
+			instruction->type = ARM_MOV;
+			mnemonic = "MOVS";
+			instruction->info.data_proc.Rn = -1;
+			break;
+		case 1:
+			instruction->type = ARM_CMP;
+			mnemonic = "CMP";
+			instruction->info.data_proc.Rd = -1;
+			break;
+		case 2:
+			instruction->type = ARM_ADD;
+			mnemonic = "ADDS";
+			break;
+		case 3:
+			instruction->type = ARM_SUB;
+			mnemonic = "SUBS";
+			break;
+	}
+	
+	snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s r%i, #0x%02x",
+				 address, opcode, mnemonic, Rd, imm);
+
+	return ERROR_OK;
+}
+
+int evaluate_data_proc_thumb(u16 opcode, u32 address, arm_instruction_t *instruction)
+{
+	u8 high_reg, op, Rm, Rd,H1,H2;
+	char *mnemonic = NULL;
+	
+	high_reg = (opcode & 0x0400) >> 10;
+	op = (opcode & 0x03C0) >> 6;
+	
+	Rd = (opcode & 0x0007);
+	Rm = (opcode & 0x0038) >> 3;
+	H1 = (opcode & 0x0080) >> 7;
+	H2 = (opcode & 0x0040) >> 6;
+	
+	instruction->info.data_proc.Rd = Rd;
+	instruction->info.data_proc.Rn = Rd;
+	instruction->info.data_proc.S = (!high_reg || (instruction->type == ARM_CMP));
+	instruction->info.data_proc.variant = 1 /*immediate shift*/;
+	instruction->info.data_proc.shifter_operand.immediate_shift.Rm = Rm;
+
+	if (high_reg)
+	{
+		Rd |= H1 << 3;
+		Rm |= H2 << 3;
+		op >>= 2;
+	
+		switch (op)
+		{
+			case 0x0:
+				instruction->type = ARM_ADD;
+				mnemonic = "ADD";
+				break;
+			case 0x1:
+				instruction->type = ARM_CMP;
+				mnemonic = "CMP";
+				break;
+			case 0x2:
+				instruction->type = ARM_MOV;
+				mnemonic = "MOV";
+				break;
+			case 0x3:
+				if ((opcode & 0x7) == 0x0)
+				{
+					instruction->info.b_bl_bx_blx.reg_operand = Rm;
+					if (H1)
+					{
+						instruction->type = ARM_BLX;
+						snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\tBLX r%i", address, opcode, Rm);
+					}
+					else
+					{
+						instruction->type = ARM_BX;
+						snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\tBX r%i", address, opcode, Rm);
+					}
+				}
+				else
+				{
+					instruction->type = ARM_UNDEFINED_INSTRUCTION;
+					snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\tUNDEFINED INSTRUCTION", address, opcode);
+				}
+				return ERROR_OK;	
+				break;
+		}
+	}
+	else
+	{
+		switch (op)
+		{
+			case 0x0:
+				instruction->type = ARM_AND;
+				mnemonic = "ANDS";
+				break;
+			case 0x1:
+				instruction->type = ARM_EOR;
+				mnemonic = "EORS";
+				break;
+			case 0x2:
+				instruction->type = ARM_MOV;
+				mnemonic = "LSLS";
+				instruction->info.data_proc.variant = 2 /*register shift*/;
+				instruction->info.data_proc.shifter_operand.register_shift.shift = 0;
+				instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd;
+				instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm;
+				break;
+			case 0x3:
+				instruction->type = ARM_MOV;
+				mnemonic = "LSRS";
+				instruction->info.data_proc.variant = 2 /*register shift*/;
+				instruction->info.data_proc.shifter_operand.register_shift.shift = 1;
+				instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd;
+				instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm;
+				break;
+			case 0x4:
+				instruction->type = ARM_MOV;
+				mnemonic = "ASRS";
+				instruction->info.data_proc.variant = 2 /*register shift*/;
+				instruction->info.data_proc.shifter_operand.register_shift.shift = 2;
+				instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd;
+				instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm;
+				break;
+			case 0x5:
+				instruction->type = ARM_ADC;
+				mnemonic = "ADCS";
+				break;
+			case 0x6:
+				instruction->type = ARM_SBC;
+				mnemonic = "SBCS";
+				break;
+			case 0x7:
+				instruction->type = ARM_MOV;
+				mnemonic = "RORS";
+				instruction->info.data_proc.variant = 2 /*register shift*/;
+				instruction->info.data_proc.shifter_operand.register_shift.shift = 3;
+				instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd;
+				instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm;
+				break;
+			case 0x8:
+				instruction->type = ARM_TST;
+				mnemonic = "TST";
+				break;
+			case 0x9:
+				instruction->type = ARM_RSB;
+				mnemonic = "NEGS";
+				instruction->info.data_proc.variant = 0 /*immediate*/;
+				instruction->info.data_proc.shifter_operand.immediate.immediate = 0;
+				instruction->info.data_proc.Rn = Rm;
+				break;
+			case 0xA:
+				instruction->type = ARM_CMP;
+				mnemonic = "CMP";
+				break;
+			case 0xB:
+				instruction->type = ARM_CMN;
+				mnemonic = "CMN";
+				break;
+			case 0xC:
+				instruction->type = ARM_ORR;
+				mnemonic = "ORRS";
+				break;
+			case 0xD:
+				instruction->type = ARM_MUL;
+				mnemonic = "MULS";
+				break;
+			case 0xE:
+				instruction->type = ARM_BIC;
+				mnemonic = "BICS";
+				break;
+			case 0xF:
+				instruction->type = ARM_MVN;
+				mnemonic = "MVNS";
+				break;
+		}
+	}
+
+	snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s r%i, r%i",
+				 address, opcode, mnemonic, Rd, Rm);
+
+	return ERROR_OK;
+}
+
+int evaluate_load_literal_thumb(u16 opcode, u32 address, arm_instruction_t *instruction)
+{
+	u32 immediate;
+	u8 Rd = (opcode >> 8) & 0x7; 
+
+	instruction->type = ARM_LDR;
+	immediate = opcode & 0x000000ff;
+
+	snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\tLDR r%i, [PC, #0x%x]", address, opcode, Rd, immediate*4);
+
+	instruction->info.load_store.Rd = Rd;
+	instruction->info.load_store.Rn = 15 /*PC*/;
+	instruction->info.load_store.index_mode = 0; /*offset*/
+	instruction->info.load_store.offset_mode = 0; /*immediate*/
+	instruction->info.load_store.offset.offset = immediate*4;
+
+	return ERROR_OK;
+}
+
+int evaluate_load_store_reg_thumb(u16 opcode, u32 address, arm_instruction_t *instruction)
+{
+	u8 Rd = (opcode >> 0) & 0x7; 
+	u8 Rn = (opcode >> 3) & 0x7; 
+	u8 Rm = (opcode >> 6) & 0x7; 
+	u8 opc = (opcode >> 9) & 0x7; 
+	char *mnemonic = NULL;
+
+	switch(opc)
+	{
+		case 0:
+			instruction->type = ARM_STR;
+			mnemonic = "STR";
+			break;
+		case 1:
+			instruction->type = ARM_STRH;
+			mnemonic = "STRH";
+			break;
+		case 2:
+			instruction->type = ARM_STRB;
+			mnemonic = "STRB";
+			break;
+		case 3:
+			instruction->type = ARM_LDRSB;
+			mnemonic = "LDRSB";
+			break;
+		case 4:
+			instruction->type = ARM_LDR;
+			mnemonic = "LDR";
+			break;
+		case 5:
+			instruction->type = ARM_LDRH;
+			mnemonic = "LDRH";
+			break;
+		case 6:
+			instruction->type = ARM_LDRB;
+			mnemonic = "LDRB";
+			break;
+		case 7:
+			instruction->type = ARM_LDRSH;
+			mnemonic = "LDRSH";
+			break;
+	}
+
+	snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s r%i, [r%i, r%i]", address, opcode, mnemonic, Rd, Rn, Rm);
+	
+	instruction->info.load_store.Rd = Rd;
+	instruction->info.load_store.Rn = Rn;
+	instruction->info.load_store.index_mode = 0; /*offset*/
+	instruction->info.load_store.offset_mode = 1; /*register*/
+	instruction->info.load_store.offset.reg.Rm = Rm;
+
+	return ERROR_OK;
+}
+
+int evaluate_load_store_imm_thumb(u16 opcode, u32 address, arm_instruction_t *instruction)
+{
+	u32 offset = (opcode >> 6) & 0x1f;
+	u8 Rd = (opcode >> 0) & 0x7; 
+	u8 Rn = (opcode >> 3) & 0x7; 
+	u32 L = opcode & (1<<11);
+	u32 B = opcode & (1<<12);
+	char *mnemonic;
+	char suffix = ' ';
+	u32 shift = 2;
+
+	if (L)
+	{
+		instruction->type = ARM_LDR;
+		mnemonic = "LDR";
+	}
+	else
+	{
+		instruction->type = ARM_STR;
+		mnemonic = "STR";
+	}
+
+	if ((opcode&0xF000)==0x8000)
+	{
+		suffix = 'H';
+		shift = 1;
+	}
+	else if (B)
+	{
+		suffix = 'B';
+		shift = 0;
+	}
+
+	snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s%c r%i, [r%i, #0x%x]", address, opcode, mnemonic, suffix, Rd, Rn, offset<<shift);
+	
+	instruction->info.load_store.Rd = Rd;
+	instruction->info.load_store.Rn = Rn;
+	instruction->info.load_store.index_mode = 0; /*offset*/
+	instruction->info.load_store.offset_mode = 0; /*immediate*/
+	instruction->info.load_store.offset.offset = offset<<shift;
+
+	return ERROR_OK;
+}
+
+int evaluate_load_store_stack_thumb(u16 opcode, u32 address, arm_instruction_t *instruction)
+{
+	u32 offset = opcode  & 0xff;
+	u8 Rd = (opcode >> 8) & 0x7; 
+	u32 L = opcode & (1<<11);
+	char *mnemonic;
+
+	if (L)
+	{
+		instruction->type = ARM_LDR;
+		mnemonic = "LDR";
+	}
+	else
+	{
+		instruction->type = ARM_STR;
+		mnemonic = "STR";
+	}
+
+	snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s r%i, [SP, #0x%x]", address, opcode, mnemonic, Rd, offset*4);
+	
+	instruction->info.load_store.Rd = Rd;
+	instruction->info.load_store.Rn = 13 /*SP*/;
+	instruction->info.load_store.index_mode = 0; /*offset*/
+	instruction->info.load_store.offset_mode = 0; /*immediate*/
+	instruction->info.load_store.offset.offset = offset*4;
+
+	return ERROR_OK;
+}
+
+int evaluate_add_sp_pc_thumb(u16 opcode, u32 address, arm_instruction_t *instruction)
+{
+	u32 imm = opcode  & 0xff;
+	u8 Rd = (opcode >> 8) & 0x7; 
+	u8 Rn;
+	u32 SP = opcode & (1<<11);
+	char *reg_name;
+
+	instruction->type = ARM_ADD;
+	
+	if (SP)
+	{
+		reg_name = "SP";
+		Rn = 13;
+	}
+	else
+	{
+		reg_name = "PC";
+		Rn = 15;
+	}
+
+	snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\tADD r%i, %s, #0x%x", address, opcode, Rd,reg_name, imm*4);
+
+	instruction->info.data_proc.variant = 0 /* immediate */;
+	instruction->info.data_proc.Rd = Rd;
+	instruction->info.data_proc.Rn = Rn;
+	instruction->info.data_proc.shifter_operand.immediate.immediate = imm*4;
+
+	return ERROR_OK;
+}
+
+int evaluate_adjust_stack_thumb(u16 opcode, u32 address, arm_instruction_t *instruction)
+{
+	u32 imm = opcode  & 0x7f;
+	u8 opc = opcode & (1<<7);
+	char *mnemonic;
+
+	
+	if (opc)
+	{
+		instruction->type = ARM_SUB;
+		mnemonic = "SUB";
+	}
+	else
+	{
+		instruction->type = ARM_ADD;
+		mnemonic = "ADD";
+	}
+
+	snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s SP, #0x%x", address, opcode, mnemonic, imm*4);
+
+	instruction->info.data_proc.variant = 0 /* immediate */;
+	instruction->info.data_proc.Rd = 13 /*SP*/;
+	instruction->info.data_proc.Rn = 13 /*SP*/;
+	instruction->info.data_proc.shifter_operand.immediate.immediate = imm*4;
+
+	return ERROR_OK;
+}
+
+int evaluate_breakpoint_thumb(u16 opcode, u32 address, arm_instruction_t *instruction)
+{
+	u32 imm = opcode  & 0xff;
+	
+	instruction->type = ARM_BKPT;
+
+	snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\tBKPT 0x%02x", address, opcode, imm);
+
+	return ERROR_OK;
+}
+
+int evaluate_load_store_multiple_thumb(u16 opcode, u32 address, arm_instruction_t *instruction)
+{
+	u32 reg_list = opcode  & 0xff;
+	u32 L = opcode & (1<<11);
+	u32 R = opcode & (1<<8);
+	u8 Rn = (opcode >> 8) & 7;
+	u8 addr_mode = 0 /* IA */;
+	char reg_names[40];
+	char *reg_names_p;
+	char *mnemonic;
+	char ptr_name[7] = "";
+	int i;	
+
+	if ((opcode & 0xf000) == 0xc000)
+	{ /* generic load/store multiple */
+		if (L)
+		{
+			instruction->type = ARM_LDM;
+			mnemonic = "LDMIA";
+		}
+		else
+		{
+			instruction->type = ARM_STM;
+			mnemonic = "STMIA";
+		}
+		snprintf(ptr_name,7,"r%i!, ",Rn);
+	}
+	else
+	{ /* push/pop */
+		Rn = 13; /* SP */
+		if (L)
+		{
+			instruction->type = ARM_LDM;
+			mnemonic = "POP";
+			if (R)
+				reg_list |= (1<<15) /*PC*/;
+		}
+		else
+		{
+			instruction->type = ARM_STM;
+			mnemonic = "PUSH";
+			addr_mode = 3; /*DB*/
+			if (R)
+				reg_list |= (1<<14) /*LR*/;
+		}
+	}
+
+	reg_names_p = reg_names;
+	for (i = 0; i <= 15; i++)
+	{
+		if (reg_list & (1<<i))
+			reg_names_p += snprintf(reg_names_p, (reg_names + 40 - reg_names_p), "r%i, ", i);
+	}
+	if (reg_names_p>reg_names)
+		reg_names_p[-2] = '\0';
+	else /* invalid op : no registers */
+    		reg_names[0] = '\0';
+
+	snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s %s{%s}", address, opcode, mnemonic, ptr_name,reg_names);
+
+	instruction->info.load_store_multiple.register_list = reg_list;
+	instruction->info.load_store_multiple.Rn = Rn;
+	instruction->info.load_store_multiple.addressing_mode = addr_mode;
+
+	return ERROR_OK;
+}
+
+int evaluate_cond_branch_thumb(u16 opcode, u32 address, arm_instruction_t *instruction)
+{
+	u32 offset = opcode  & 0xff;
+	u8 cond = (opcode >> 8) & 0xf;
+	u32 target_address;
+
+	if (cond == 0xf)
+	{
+		instruction->type = ARM_SWI;
+		snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\tSWI 0x%02x", address, opcode, offset);
+		return ERROR_OK;
+	}
+	else if (cond == 0xe)
+	{
+		instruction->type = ARM_UNDEFINED_INSTRUCTION;
+		snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\tUNDEFINED INSTRUCTION", address, opcode);
+		return ERROR_OK;
+	}
+
+	/* sign extend 8-bit offset */
+	if (offset & 0x00000080)
+		offset = 0xffffff00 | offset;
+	
+	target_address = address + 4 + (offset<<1);
+
+	snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\tB%s 0x%8.8x", address, opcode,
+			 arm_condition_strings[cond], target_address);
+	
+	instruction->type = ARM_B;
+	instruction->info.b_bl_bx_blx.reg_operand = -1;
+	instruction->info.b_bl_bx_blx.target_address = target_address;
+
+	return ERROR_OK;
+}
+
+int thumb_evaluate_opcode(u16 opcode, u32 address, arm_instruction_t *instruction)
+{
+	/* clear fields, to avoid confusion */
+	memset(instruction, 0, sizeof(arm_instruction_t));
+	instruction->opcode = opcode;
+	
+	if ((opcode & 0xe000) == 0x0000)
+	{
+		/* add/substract register or immediate */
+		if ((opcode & 0x1800) == 0x1800)
+			return evaluate_add_sub_thumb(opcode, address, instruction);
+		/* shift by immediate */
+		else
+			return evaluate_shift_imm_thumb(opcode, address, instruction);
+	}
+	
+	/* Add/substract/compare/move immediate */
+	if ((opcode & 0xe000) == 0x2000)
+	{
+		return evaluate_data_proc_imm_thumb(opcode, address, instruction);
+	}
+	
+	/* Data processing instructions */
+	if ((opcode & 0xf800) == 0x4000)
+	{
+		return evaluate_data_proc_thumb(opcode, address, instruction);
+	}
+	
+	/* Load from literal pool */
+	if ((opcode & 0xf800) == 0x4800)
+	{
+		return evaluate_load_literal_thumb(opcode, address, instruction);
+	}
+
+	/* Load/Store register offset */
+	if ((opcode & 0xf000) == 0x5000)
+	{
+		return evaluate_load_store_reg_thumb(opcode, address, instruction);
+	}
+
+	/* Load/Store immediate offset */
+	if (((opcode & 0xe000) == 0x6000)
+		||((opcode & 0xf000) == 0x8000))
+	{
+		return evaluate_load_store_imm_thumb(opcode, address, instruction);
+	}
+	
+	/* Load/Store from/to stack */
+	if ((opcode & 0xf000) == 0x9000)
+	{
+		return evaluate_load_store_stack_thumb(opcode, address, instruction);
+	}
+
+	/* Add to SP/PC */
+	if ((opcode & 0xf000) == 0xa000)
+	{
+		return evaluate_add_sp_pc_thumb(opcode, address, instruction);
+	}
+
+	/* Misc */
+	if ((opcode & 0xf000) == 0xb000)
+	{
+		if ((opcode & 0x0f00) == 0x0000)
+			return evaluate_adjust_stack_thumb(opcode, address, instruction);
+		else if ((opcode & 0x0f00) == 0x0e00)
+			return evaluate_breakpoint_thumb(opcode, address, instruction);
+		else if ((opcode & 0x0600) == 0x0400) /* push pop */
+			return evaluate_load_store_multiple_thumb(opcode, address, instruction);
+		else
+		{
+			instruction->type = ARM_UNDEFINED_INSTRUCTION;
+			snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\tUNDEFINED INSTRUCTION", address, opcode);
+			return ERROR_OK;
+		}
+	}
+
+	/* Load/Store multiple */
+	if ((opcode & 0xf000) == 0xc000)
+	{
+		return evaluate_load_store_multiple_thumb(opcode, address, instruction);
+	}
+
+	/* Conditional branch + SWI */
+	if ((opcode & 0xf000) == 0xd000)
+	{
+		return evaluate_cond_branch_thumb(opcode, address, instruction);
+	}
+	
+	if ((opcode & 0xe000) == 0xe000)
+	{
+		/* Undefined instructions */
+		if ((opcode & 0xf801) == 0xe801)
+		{
+			instruction->type = ARM_UNDEFINED_INSTRUCTION;
+			snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address, opcode);
+			return ERROR_OK;
+		}
+		else
+		{ /* Branch to offset */
+			return evaluate_b_bl_blx_thumb(opcode, address, instruction);
+		}
+	}
+
+	ERROR("should never reach this point (opcode=%04x)",opcode);
+	return -1;
+}
+
diff --git a/src/target/arm_disassembler.h b/src/target/arm_disassembler.h
index b55c8855..bdab113d 100644
--- a/src/target/arm_disassembler.h
+++ b/src/target/arm_disassembler.h
@@ -133,7 +133,7 @@ union arm_shifter_operand
 	} immediate;
 	struct {
 		u8 Rm;
-		u8 shift;
+		u8 shift; /* 0: LSL, 1: LSR, 2: ASR, 3: ROR, 4: RRX */
 		u8 shift_imm;
 	} immediate_shift;
 	struct {
@@ -164,7 +164,7 @@ typedef struct arm_load_store_instr_s
 		u32 offset;
 		struct {
 			u8 Rm;
-			u8 shift;
+			u8 shift; /* 0: LSL, 1: LSR, 2: ASR, 3: ROR, 4: RRX */
 			u8 shift_imm;
 		} reg;
 	} offset;
@@ -195,6 +195,7 @@ typedef struct arm_instruction_s
 } arm_instruction_t;
 
 extern int arm_evaluate_opcode(u32 opcode, u32 address, arm_instruction_t *instruction);
+extern int thumb_evaluate_opcode(u16 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
index fd0b309c..561b14f8 100644
--- a/src/target/arm_simulator.c
+++ b/src/target/arm_simulator.c
@@ -257,6 +257,11 @@ int pass_condition(u32 cpsr, u32 opcode)
 	return 0;
 }
 
+int thumb_pass_branch_condition(u32 cpsr, u16 opcode)
+{
+	return pass_condition(cpsr, (opcode & 0x0f00) << 20); 
+}
+
 /* 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
@@ -275,26 +280,43 @@ int arm_simulate_step(target_t *target, u32 *dry_run_pc)
 		target_read_u32(target, current_pc, &opcode);
 		arm_evaluate_opcode(opcode, current_pc, &instruction);
 		instruction_size = 4;
+		
+		/* check condition code (for all instructions) */
+		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;
+		}
 	}
 	else
 	{
-		/* TODO: add support for Thumb instruction set */
+		target_read_u32(target, current_pc, &opcode);
+		arm_evaluate_opcode(opcode, current_pc, &instruction);
 		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
+		
+		/* check condition code (only for branch instructions) */
+		if ((!thumb_pass_branch_condition(buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32), opcode)) &&
+			(instruction.type == ARM_B))
 		{
-			buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, current_pc + instruction_size);
+			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;
 		}
-		
-		return ERROR_OK;
 	}
 	
 	/* examine instruction type */
diff --git a/src/target/armv4_5.h b/src/target/armv4_5.h
index 0ba94ff7..36264f35 100644
--- a/src/target/armv4_5.h
+++ b/src/target/armv4_5.h
@@ -23,7 +23,7 @@
 #include "register.h"
 #include "target.h"
 
-enum armv4_5_mode
+typedef enum armv4_5_mode
 {
 	ARMV4_5_MODE_USR = 16, 
 	ARMV4_5_MODE_FIQ = 17, 
@@ -33,16 +33,16 @@ enum armv4_5_mode
 	ARMV4_5_MODE_UND = 27,
 	ARMV4_5_MODE_SYS = 31,
 	ARMV4_5_MODE_ANY = -1
-};
+} armv4_5_mode_t;
 
 extern char* armv4_5_mode_strings[];
 
-enum armv4_5_state
+typedef enum armv4_5_state
 {
 	ARMV4_5_STATE_ARM,
 	ARMV4_5_STATE_THUMB,
 	ARMV4_5_STATE_JAZELLE,
-};
+} armv4_5_state_t;
 
 extern char* armv4_5_state_strings[];
 
diff --git a/src/target/etb.c b/src/target/etb.c
index 21f250aa..257c4b18 100644
--- a/src/target/etb.c
+++ b/src/target/etb.c
@@ -21,8 +21,11 @@
 #include "config.h"
 #endif
 
+#include <string.h>
+
 #include "arm7_9_common.h"
 #include "etb.h"
+#include "etm.h"
 
 #include "log.h"
 #include "types.h"
@@ -55,16 +58,7 @@ int etb_set_reg_w_exec(reg_t *reg, u8 *buf);
 int etb_write_reg(reg_t *reg, u32 value);
 int etb_read_reg(reg_t *reg);
 
-int handle_arm7_9_etb_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_arm7_9_etb_dump_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-char *etmv1_branch_reason_string[] =
-{
-	"normal pc change", "tracing enabled", "restart after FIFO overflow",
-	"exit from debug state", "peridoic synchronization point",
-	"reserved", "reserved", "reserved"
-};
-
+int handle_etb_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 
 int etb_set_instr(etb_t *etb, u32 new_instr)
 {
@@ -180,6 +174,74 @@ int etb_get_reg(reg_t *reg)
 	return ERROR_OK;
 }
 
+int etb_read_ram(etb_t *etb, u32 *data, int num_frames)
+{
+	scan_field_t fields[3];
+	int i;
+	
+	jtag_add_end_state(TAP_RTI);
+	etb_scann(etb, 0x0);
+	etb_set_instr(etb, 0xc);
+	
+	fields[0].device = etb->chain_pos;
+	fields[0].num_bits = 32;
+	fields[0].out_value = NULL;
+	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 = etb->chain_pos;
+	fields[1].num_bits = 7;
+	fields[1].out_value = malloc(1);
+	buf_set_u32(fields[1].out_value, 0, 7, 4);
+	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;
+
+	fields[2].device = etb->chain_pos;
+	fields[2].num_bits = 1;
+	fields[2].out_value = malloc(1);
+	buf_set_u32(fields[2].out_value, 0, 1, 0);
+	fields[2].out_mask = NULL;
+	fields[2].in_value = NULL;
+	fields[2].in_check_value = NULL;
+	fields[2].in_check_mask = NULL;
+	fields[2].in_handler = NULL;
+	fields[2].in_handler_priv = NULL;
+	
+	jtag_add_dr_scan(3, fields, -1, NULL);
+
+	fields[0].in_handler = buf_to_u32_handler;
+	
+	for (i = 0; i < num_frames; i++)
+	{
+		/* ensure nR/W reamins set to read */
+		buf_set_u32(fields[2].out_value, 0, 1, 0);
+		
+		/* address remains set to 0x4 (RAM data) until we read the last frame */
+		if (i < num_frames - 1)
+			buf_set_u32(fields[1].out_value, 0, 7, 4);
+		else
+			buf_set_u32(fields[1].out_value, 0, 7, 0);
+		
+		fields[0].in_handler_priv = &data[i];
+		jtag_add_dr_scan(3, fields, -1, NULL);
+	}
+	
+	jtag_execute_queue();
+	
+	free(fields[1].out_value);
+	free(fields[2].out_value);
+	
+	return ERROR_OK;
+}
+
 int etb_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask)
 {
 	etb_reg_t *etb_reg = reg->arch_info;
@@ -333,293 +395,266 @@ int etb_store_reg(reg_t *reg)
 	return etb_write_reg(reg, buf_get_u32(reg->value, 0, reg->size));
 }
 
-int etb_register_commands(struct command_context_s *cmd_ctx, command_t *arm7_9_cmd)
+int etb_register_commands(struct command_context_s *cmd_ctx)
 {
-	register_command(cmd_ctx, arm7_9_cmd, "etb", handle_arm7_9_etb_command, COMMAND_CONFIG, NULL);
+	command_t *etb_cmd;
+	
+	etb_cmd = register_command(cmd_ctx, NULL, "etb", NULL, COMMAND_ANY, "Embedded Trace Buffer");
+	
+	register_command(cmd_ctx, etb_cmd, "config", handle_etb_config_command, COMMAND_CONFIG, NULL);
+
+	return ERROR_OK;
+}
 
-	register_command(cmd_ctx, arm7_9_cmd, "etb_dump", handle_arm7_9_etb_dump_command, COMMAND_EXEC, "dump current ETB content");
+int handle_etb_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+	target_t *target;
+	jtag_device_t *jtag_device;
+	armv4_5_common_t *armv4_5;
+	arm7_9_common_t *arm7_9;
+	
+	if (argc != 2)
+	{
+		ERROR("incomplete 'etb config <target> <chain_pos>' command");
+		exit(-1);
+	}
+	
+	target = get_target_by_num(strtoul(args[0], NULL, 0));
+	
+	if (!target)
+	{
+		ERROR("target number '%s' not defined", args[0]);
+		exit(-1);
+	}
+	
+	if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+	{
+		command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+		return ERROR_OK;
+	}
+	
+	jtag_device = jtag_get_device(strtoul(args[1], NULL, 0));
+	
+	if (!jtag_device)
+	{
+		ERROR("jtag device number '%s' not defined", args[1]);
+		exit(-1);
+	}
+	
+	if (arm7_9->etm_ctx)
+	{
+		etb_t *etb = malloc(sizeof(etb_t));
+		
+		arm7_9->etm_ctx->capture_driver_priv = etb;
+		
+		etb->chain_pos = strtoul(args[1], NULL, 0);
+		etb->cur_scan_chain = -1;
+		etb->reg_cache = NULL;
+		etb->ram_width = 0;
+		etb->ram_depth = 0;
+	}
+	else
+	{
+		ERROR("target has no ETM defined, ETB left unconfigured");
+	}
 
 	return ERROR_OK;
 }
 
-#define PIPESTAT(x) ((x) & 0x7)
-#define TRACEPKT(x) (((x) & 0x7fff8) >> 3)
-#define TRACESYNC(x) (((x) & 0x80000) >> 19)
+int etb_init(etm_context_t *etm_ctx)
+{
+	etb_t *etb = etm_ctx->capture_driver_priv;
+	
+	etb->etm_ctx = etm_ctx;
+	
+	/* identify ETB RAM depth and width */
+	etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_DEPTH]);
+	etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_WIDTH]);
+	jtag_execute_queue();
+
+	etb->ram_depth = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_DEPTH].value, 0, 32);
+	etb->ram_width = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WIDTH].value, 0, 32);
+	
+	return ERROR_OK;
+}
 
-int etmv1_next_packet(int trace_depth, u32 *trace_data, int frame, int *port_half, int apo, u8 *packet)
+trace_status_t etb_status(etm_context_t *etm_ctx)
 {
-	while (frame < trace_depth)
+	etb_t *etb = etm_ctx->capture_driver_priv;
+	
+	etb->etm_ctx = etm_ctx;
+	
+	/* if tracing is currently idle, return this information */
+	if (etm_ctx->capture_status == TRACE_IDLE)
 	{
-		if (apo > 0)
-		{
-			if (TRACESYNC(trace_data[frame]))
-				apo--;
-		}
-		else
+		return etm_ctx->capture_status;
+	}
+	else if (etm_ctx->capture_status & TRACE_RUNNING)
+	{
+		reg_t *etb_status_reg = &etb->reg_cache->reg_list[ETB_STATUS];
+		int etb_timeout = 100;
+		
+		/* trace is running, check the ETB status flags */
+		etb_get_reg(etb_status_reg);
+	
+		/* check Full bit to identify an overflow */
+		if (buf_get_u32(etb_status_reg->value, 0, 1) == 1)
+			etm_ctx->capture_status |= TRACE_OVERFLOWED;
+
+		/* check Triggered bit to identify trigger condition */
+		if (buf_get_u32(etb_status_reg->value, 1, 1) == 1)
+			etm_ctx->capture_status |= TRACE_TRIGGERED;
+
+		/* check AcqComp to identify trace completion */
+		if (buf_get_u32(etb_status_reg->value, 2, 1) == 1)
 		{
-			/* we're looking for a branch address, skip if TRACESYNC isn't set */
-			if ((apo == 0) && (!TRACESYNC(trace_data[frame])))
+			while (etb_timeout-- && (buf_get_u32(etb_status_reg->value, 3, 1) == 0))
 			{
-				frame++;
-				continue;
+				/* wait for data formatter idle */
+				etb_get_reg(etb_status_reg);
 			}
-				
-			/* TRACEPKT is valid if this isn't a TD nor a TRIGGER cycle */
-			if (((PIPESTAT(trace_data[frame]) != 0x7) && (PIPESTAT(trace_data[frame]) != 0x6))
-				&& !((apo == 0) && (!TRACESYNC(trace_data[frame]))))
+			
+			if (etb_timeout == 0)
+			{
+				ERROR("AcqComp set but DFEmpty won't go high, ETB status: 0x%x",
+					buf_get_u32(etb_status_reg->value, 0, etb_status_reg->size));
+			}
+			
+			if (!(etm_ctx->capture_status && TRACE_TRIGGERED))
 			{
-				if (*port_half == 0)
-				{
-					*packet = TRACEPKT(trace_data[frame]) & 0xff;
-					*port_half = 1;
-				}
-				else
-				{
-					*packet = (TRACEPKT(trace_data[frame]) & 0xff00) >> 8;
-					*port_half = 0;
-					frame++;
-				}
-				return frame;
+				ERROR("trace completed, but no trigger condition detected");
 			}
+			
+			etm_ctx->capture_status &= ~TRACE_RUNNING;
+			etm_ctx->capture_status |= TRACE_COMPLETED;
 		}
-		frame++;
 	}
 	
-	/* we reached the end of the trace without finding the packet we're looking for
-	 * tracing is finished
-	 */
-	return -1;
+	return etm_ctx->capture_status;
 }
 
-int handle_arm7_9_etb_dump_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+int etb_read_trace(etm_context_t *etm_ctx)
 {
-	int retval;
-	target_t *target = get_current_target(cmd_ctx);
-	armv4_5_common_t *armv4_5;
-	arm7_9_common_t *arm7_9;
-	int i, j, k;
+	etb_t *etb = etm_ctx->capture_driver_priv;
 	int first_frame = 0;
-	int last_frame;
-	int addressbits_valid = 0;
-	u32 address = 0x0;
-	u32 *trace_data;
-	int port_half = 0;
-	int last_instruction = -1;
-	u8 branch_reason;
-	u8 packet;
-	char trace_output[256];
-	int trace_output_len;
-	u8 apo;
-
-	if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
-	{
-		command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
-		return ERROR_OK;
-	}
+	int num_frames = etb->ram_depth;
+	u32 *trace_data = NULL;
+	int i, j;
+	
+	etb_read_reg(&etb->reg_cache->reg_list[ETB_STATUS]);
+	etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER]);
+	jtag_execute_queue();
 	
-	if (!arm7_9->etb)
+	/* check if we overflowed, and adjust first frame of the trace accordingly
+	 * if we didn't overflow, read only up to the frame that would be written next,
+	 * i.e. don't read invalid entries
+	 */
+	if (buf_get_u32(etb->reg_cache->reg_list[ETB_STATUS].value, 0, 1))
 	{
-		command_print(cmd_ctx, "no ETB configured for current target");
-		return ERROR_OK;
+		first_frame = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER].value, 0, 32);
 	}
-	
-	if (!(arm7_9->etb->RAM_depth && arm7_9->etb->RAM_width))
+	else
 	{
-		/* identify ETB RAM depth and width */
-		etb_read_reg(&arm7_9->etb->reg_cache->reg_list[ETB_RAM_DEPTH]);
-		etb_read_reg(&arm7_9->etb->reg_cache->reg_list[ETB_RAM_WIDTH]);
-		jtag_execute_queue();
-	
-		arm7_9->etb->RAM_depth = buf_get_u32(arm7_9->etb->reg_cache->reg_list[ETB_RAM_DEPTH].value, 0, 32);
-		arm7_9->etb->RAM_width = buf_get_u32(arm7_9->etb->reg_cache->reg_list[ETB_RAM_WIDTH].value, 0, 32);
+		num_frames = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER].value, 0, 32);
 	}
 	
-	trace_data = malloc(sizeof(u32) * arm7_9->etb->RAM_depth);
-	
-	etb_read_reg(&arm7_9->etb->reg_cache->reg_list[ETB_STATUS]);
-	etb_read_reg(&arm7_9->etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER]);
-	jtag_execute_queue();
-	
-	/* check if we overflowed, and adjust first and last frame of the trace accordingly */
-	if (buf_get_u32(arm7_9->etb->reg_cache->reg_list[ETB_STATUS].value, 1, 1))
+	etb_write_reg(&etb->reg_cache->reg_list[ETB_RAM_READ_POINTER], first_frame);
+
+	/* read data into temporary array for unpacking */	
+	trace_data = malloc(sizeof(u32) * num_frames);
+	etb_read_ram(etb, trace_data, num_frames);
+
+	if (etm_ctx->trace_depth > 0)
 	{
-		first_frame = buf_get_u32(arm7_9->etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER].value, 0, 32);
+		free(etm_ctx->trace_data);
 	}
 	
-	last_frame = buf_get_u32(arm7_9->etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER].value, 0, 32) - 1;
-	
-	etb_write_reg(&arm7_9->etb->reg_cache->reg_list[ETB_RAM_READ_POINTER], first_frame);
+	if ((etm_ctx->portmode & ETM_PORT_MODE_MASK) == ETM_PORT_DEMUXED)
+		etm_ctx->trace_depth = num_frames * 2;
+	else
+		etm_ctx->trace_depth = num_frames;
 
-	/* read trace data from ETB */
-	i = first_frame;
-	j = 0;
-	do {
-		etb_read_reg(&arm7_9->etb->reg_cache->reg_list[ETB_RAM_DATA]);
-		jtag_execute_queue();
-		trace_data[j++] = buf_get_u32(arm7_9->etb->reg_cache->reg_list[ETB_RAM_DATA].value, 0, 32);
-		i++;
-	} while ((i % arm7_9->etb->RAM_depth) != (first_frame % arm7_9->etb->RAM_depth));
+	etm_ctx->trace_data= malloc(sizeof(etmv1_trace_data_t) * etm_ctx->trace_depth);
 	
-	for (i = 0, j = 0; i < arm7_9->etb->RAM_depth; i++)
+	for (i = 0, j = 0; i < num_frames; i++)
 	{
-		int trigger = 0;
-		
-		trace_output_len = 0;
-		
-		/* catch trigger, actual PIPESTAT is encoded in TRACEPKT[2:0] */
-		if (PIPESTAT(trace_data[i]) == 0x6)
+		if ((etm_ctx->portmode & ETM_PORT_MODE_MASK) == ETM_PORT_DEMUXED)
 		{
-			trigger = 1;
-			trace_data[i] &= ~0x7;
-			trace_data[i] |= TRACEPKT(trace_data[i]) & 0x7;
-		}
-	
-		if (addressbits_valid == 32)
-		{
-			trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len,
-				"%i: 0x%8.8x %s", i, address, (trigger) ? "(TRIGGER) " : "");
-		}
-		else if (addressbits_valid != 0)
-		{
-			trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len,
-				"%i: 0x...%x %s", i, address, (trigger) ? "(TRIGGER) " : "");
+			etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7;
+			etm_ctx->trace_data[j].packet = (trace_data[i] & 0x7f8) >> 3;
+			etm_ctx->trace_data[j].tracesync = (trace_data[i] & 0x800) >> 11;
+
+			etm_ctx->trace_data[j+1].pipestat = (trace_data[i] & 0x7000) >> 12;
+			etm_ctx->trace_data[j+1].packet = (trace_data[i] & 0x7f8000) >> 15;
+			etm_ctx->trace_data[j+1].tracesync = (trace_data[i] & 0x800000) >> 23;
+			
+			j += 2;
 		}
 		else
 		{
-			trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len,
-				"%i: 0xUNK %s", i, (trigger) ? "(TRIGGER) " : "");
-		}
-		
-		switch (PIPESTAT(trace_data[i]))
-		{
-			case 0x0:
-				trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len,
-					"IE");
-				break;
-			case 0x1:
-				trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len,
-					"ID");
-				break;
-			case 0x2:
-				/* Instruction exectued - TRACEPKT might be valid, but belongs to another cycle */
-				trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len,
-					"IN");
-				break;
-			case 0x3:
-				/* WAIT cycle - TRACEPKT is valid, but belongs to another cycle */
-				trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len,
-					"WT");
-				break;
-			case 0x4:
-				/* following a branch two APO cycles are output on PIPESTAT[1:0]
-				 * but another BE/BD could overwrite the current branch,
-				 * or a trigger could cause the APO to be output on TRACEPKT[1:0]
-				 */
-				if ((PIPESTAT(trace_data[i + 1]) == 0x4)
-					|| (PIPESTAT(trace_data[i + 1]) == 0x5))
-				{
-					/* another branch occured, we ignore this one */
-					j = (j < i + 1) ? i + 1 : j;
-					break;
-				}
-				else if (PIPESTAT(trace_data[i + 1]) == 0x6)
-				{
-					apo = TRACEPKT(trace_data[i + 1]) & 0x3;
-				}
-				else
-				{
-					apo = PIPESTAT(trace_data[i + 1]) & 0x3;
-				}
-
-				if ((PIPESTAT(trace_data[i + 2]) == 0x4)
-					|| (PIPESTAT(trace_data[i + 2]) == 0x5))
-				{
-					j = (j < i + 2) ? i + 1 : j;
-					i = i + 1;
-					break;
-				}
-				else if (PIPESTAT(trace_data[i + 2]) == 0x6)
-				{
-					apo |= (TRACEPKT(trace_data[i + 2]) & 0x3) << 2;
-				}
-				else
-				{
-					apo = (PIPESTAT(trace_data[i + 1]) & 0x3) << 2;
-				}
-				
-				branch_reason = -1;
-				k = 0;
-				do
-				{
-					if ((j = etmv1_next_packet(arm7_9->etb->RAM_depth, trace_data, j, &port_half, apo, &packet)) != -1)
-					{
-						address &= ~(0x7f << (k * 7));
-						address |= (packet & 0x7f) << (k * 7);
-					}
-					else
-					{
-						break;
-					}
-					k++;
-				} while ((k < 5) && (packet & 0x80));
-				
-				if (addressbits_valid < ((k * 7 > 32) ? 32 : k * 7))
-					addressbits_valid = (k * 7 > 32) ? 32 : k * 7;
-				
-				if (k == 5)
-				{
-					branch_reason = (packet & 0x7) >> 4;
-					trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len,
-						"BE 0x%x (/%i) (%s)", address, addressbits_valid, etmv1_branch_reason_string[branch_reason]);
-				}
-				else
-				{
-					trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len,
-						"BE 0x%x (/%i)", address, addressbits_valid);
-				}
-				
-				break;
-			case 0x5:
-				trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len,
-					"BD");
-				break;
-			case 0x6:
-				/* We catch the trigger event before we get here */
-				ERROR("TR pipestat should have been caught earlier");
-				trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len,
-					"--");
-				break;
-			case 0x7:
-				/* TRACE disabled - TRACEPKT = invalid */
-				trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len,
-					"TD");
-				break;
-		}
-		
-		/* PIPESTAT other than WT (b011) and TD (b111) mean we executed an instruction */
-		if ((PIPESTAT(trace_data[i]) & 0x3) != 0x3)
-		{
-			last_instruction = i;
-			address += 4;
+			etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7;
+			etm_ctx->trace_data[j].packet = (trace_data[i] & 0x7fff8) >> 3;
+			etm_ctx->trace_data[j].tracesync = (trace_data[i] & 0x80000) >> 19;
+			
+			j += 1;
 		}
+	}
+	
+	free(trace_data);
+	
+	return ERROR_OK;
+}
 
-		/* The group of packets for a particular instruction cannot start on or before any
-		 * previous functional PIPESTAT (IE, IN, ID, BE, or BD)
-		 */
-		if (j < last_instruction)
-		{
-			j = last_instruction + 1;
-		}
+int etb_start_capture(etm_context_t *etm_ctx)
+{
+	etb_t *etb = etm_ctx->capture_driver_priv;
+	u32 etb_ctrl_value = 0x1;
 
-		/* restore trigger PIPESTAT to ensure TRACEPKT is ignored */		
-		if (trigger == 1)
+	if ((etm_ctx->portmode & ETM_PORT_MODE_MASK) == ETM_PORT_DEMUXED)
+	{
+		if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_16BIT)
 		{
-			trace_data[i] &= ~0x7;
-			trace_data[i] |= 0x6;	
+			DEBUG("ETB can't run in demultiplexed mode with a 16-bit port");
+			return ERROR_ETM_PORTMODE_NOT_SUPPORTED;
 		}
-		
-		command_print(cmd_ctx, "%s (raw: 0x%8.8x)", trace_output, trace_data[i]);
+		etb_ctrl_value |= 0x2;
 	}
 	
+	if ((etm_ctx->portmode & ETM_PORT_MODE_MASK) == ETM_PORT_MUXED)
+		return ERROR_ETM_PORTMODE_NOT_SUPPORTED;
+	
+	etb_write_reg(&etb->reg_cache->reg_list[ETB_TRIGGER_COUNTER], 0x600);
+	etb_write_reg(&etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER], 0x0);
+	etb_write_reg(&etb->reg_cache->reg_list[ETB_CTRL], etb_ctrl_value);
+	jtag_execute_queue();
+	
+	/* we're starting a new trace, initialize capture status */
+	etm_ctx->capture_status = TRACE_RUNNING;
+	
+	return ERROR_OK; 
+}
+
+int etb_stop_capture(etm_context_t *etm_ctx)
+{
+	etb_t *etb = etm_ctx->capture_driver_priv;
+	reg_t *etb_ctrl_reg = &etb->reg_cache->reg_list[ETB_CTRL];
+
+	etb_write_reg(etb_ctrl_reg, 0x0);
+	jtag_execute_queue();
+	
+	/* trace stopped, just clear running flag, but preserve others */ 
+	etm_ctx->capture_status &= ~TRACE_RUNNING;
+	
 	return ERROR_OK;
 }
+
+etm_capture_driver_t etb_capture_driver =
+{
+	.name = "etb",
+	.register_commands = etb_register_commands,
+	.init = etb_init,
+	.status = etb_status,
+	.start_capture = etb_start_capture,
+	.stop_capture = etb_stop_capture,
+	.read_trace = etb_read_trace,
+};
diff --git a/src/target/etb.h b/src/target/etb.h
index 12e613ff..1a579cb3 100644
--- a/src/target/etb.h
+++ b/src/target/etb.h
@@ -25,6 +25,9 @@
 #include "register.h"
 #include "arm_jtag.h"
 
+#include "etb.h"
+#include "etm.h"
+
 /* ETB registers */
 enum
 {
@@ -41,13 +44,14 @@ enum
 
 typedef struct etb_s
 {
+	etm_context_t *etm_ctx;
 	int chain_pos;
 	int cur_scan_chain;
 	reg_cache_t *reg_cache;
 	
 	/* ETB parameters */
-	int RAM_depth;
-	int RAM_width;
+	int ram_depth;
+	int ram_width;
 } etb_t;
 
 typedef struct etb_reg_s
@@ -56,6 +60,8 @@ typedef struct etb_reg_s
 	etb_t *etb;
 } etb_reg_t;
 
+extern etm_capture_driver_t etb_capture_driver;
+
 extern reg_cache_t* etb_build_reg_cache(etb_t *etb);
 extern int etb_read_reg(reg_t *reg);
 extern int etb_write_reg(reg_t *reg, u32 value);
@@ -64,6 +70,6 @@ extern int etb_store_reg(reg_t *reg);
 extern int etb_set_reg(reg_t *reg, u32 value);
 extern int etb_set_reg_w_exec(reg_t *reg, u8 *buf);
 
-extern int etb_register_commands(struct command_context_s *cmd_ctx, command_t *arm7_9_cmd);
+extern int etb_register_commands(struct command_context_s *cmd_ctx);
 
 #endif /* ETB_H */
diff --git a/src/target/etm.c b/src/target/etm.c
index 016130d5..02c33104 100644
--- a/src/target/etm.c
+++ b/src/target/etm.c
@@ -21,7 +21,10 @@
 #include "config.h"
 #endif
 
+#include <string.h>
+
 #include "etm.h"
+#include "etb.h"
 
 #include "armv4_5.h"
 #include "arm7_9_common.h"
@@ -33,9 +36,14 @@
 #include "target.h"
 #include "register.h"
 #include "jtag.h"
+#include "fileio.h"
 
 #include <stdlib.h>
 
+/* ETM register access functionality 
+ * 
+ */
+
 bitfield_desc_t etm_comms_ctrl_bitfield_desc[] = 
 {
 	{"R", 1},
@@ -204,13 +212,16 @@ int etm_set_reg_w_exec(reg_t *reg, u8 *buf);
 int etm_write_reg(reg_t *reg, u32 value);
 int etm_read_reg(reg_t *reg);
 
-reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, int extra_reg)
+command_t *etm_cmd = NULL;
+
+reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, etm_context_t *etm_ctx)
 {
 	reg_cache_t *reg_cache = malloc(sizeof(reg_cache_t));
 	reg_t *reg_list = NULL;
 	etm_reg_t *arch_info = NULL;
 	int num_regs = sizeof(etm_reg_arch_info)/sizeof(int);
 	int i;
+	u32 etm_ctrl_value;
 	
 	/* register a register arch-type for etm registers only once */
 	if (etm_reg_arch_type == -1)
@@ -242,6 +253,44 @@ reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, int ex
 		arch_info[i].addr = etm_reg_arch_info[i];
 		arch_info[i].jtag_info = jtag_info;
 	}
+
+	/* initialize some ETM control register settings */	
+	etm_get_reg(&reg_list[ETM_CTRL]);
+	etm_ctrl_value = buf_get_u32(reg_list[ETM_CTRL].value, 0, reg_list[ETM_CTRL].size);
+	
+	/* clear the ETM powerdown bit (0) */
+	etm_ctrl_value &= ~0x1;
+		
+	/* configure port width (6:4), mode (17:16) and clocking (13) */
+	etm_ctrl_value = (etm_ctrl_value & 
+		~ETM_PORT_WIDTH_MASK & ~ETM_PORT_MODE_MASK & ~ETM_PORT_CLOCK_MASK)
+		| etm_ctx->portmode;
+	
+	buf_set_u32(reg_list[ETM_CTRL].value, 0, reg_list[ETM_CTRL].size, etm_ctrl_value);
+	etm_store_reg(&reg_list[ETM_CTRL]);
+	
+	/* the ETM might have an ETB connected */
+	if (strcmp(etm_ctx->capture_driver->name, "etb") == 0)
+	{
+		etb_t *etb = etm_ctx->capture_driver_priv;
+		
+		if (!etb)
+		{
+			ERROR("etb selected as etm capture driver, but no ETB configured");
+			return ERROR_OK;
+		}
+		
+		reg_cache->next = etb_build_reg_cache(etb);
+		
+		etb->reg_cache = reg_cache->next;
+		
+		if (etm_ctx->capture_driver->init(etm_ctx) != ERROR_OK)
+		{
+			ERROR("ETM capture driver initialization failed");
+			exit(-1);
+		}
+	}
+	
 	return reg_cache;
 }
 
@@ -410,3 +459,638 @@ int etm_store_reg(reg_t *reg)
 	return etm_write_reg(reg, buf_get_u32(reg->value, 0, reg->size));
 }
 
+/* ETM trace analysis functionality
+ * 
+ */
+extern etm_capture_driver_t etb_capture_driver;
+
+etm_capture_driver_t *etm_capture_drivers[] = 
+{
+	&etb_capture_driver,
+	NULL
+};
+
+char *etmv1v1_branch_reason_strings[] =
+{
+	"normal PC change",
+	"tracing enabled",
+	"trace restarted after overflow",
+	"exit from debug",
+	"periodic synchronization",
+	"reserved",
+	"reserved",
+	"reserved",
+};
+
+int etmv1_next_packet(etm_context_t *ctx, u8 *packet)
+{
+	
+	
+	return ERROR_OK;
+}
+
+int etmv1_analyse_trace(etm_context_t *ctx)
+{
+	ctx->pipe_index = 0;
+	ctx->data_index = 0;
+	
+	while (ctx->pipe_index < ctx->trace_depth)
+	{
+		switch (ctx->trace_data[ctx->pipe_index].pipestat)
+		{
+			case STAT_IE:
+			case STAT_ID:
+				break;
+			case STAT_IN:
+				DEBUG("IN");
+				break;
+			case STAT_WT:
+				DEBUG("WT");
+				break;
+			case STAT_BE:
+			case STAT_BD:
+				break;
+			case STAT_TD:
+				/* TODO: in cycle accurate trace, we have to count cycles */
+				DEBUG("TD");
+				break;
+		}
+	}
+	
+	return ERROR_OK;
+}
+
+int handle_etm_tracemode_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+	target_t *target;
+	armv4_5_common_t *armv4_5;
+	arm7_9_common_t *arm7_9;
+	etmv1_tracemode_t tracemode;
+	
+	target = get_current_target(cmd_ctx);
+	
+	if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+	{
+		command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+		return ERROR_OK;
+	}
+	
+	if (!arm7_9->etm_ctx)
+	{
+		command_print(cmd_ctx, "current target doesn't have an ETM configured");
+		return ERROR_OK;
+	}
+	
+	tracemode = arm7_9->etm_ctx->tracemode;
+
+	if (argc == 3)
+	{
+		if (strcmp(args[0], "none") == 0)
+		{
+			tracemode = ETMV1_TRACE_NONE;
+		}
+		else if (strcmp(args[0], "data") == 0)
+		{
+			tracemode = ETMV1_TRACE_DATA;
+		}
+		else if (strcmp(args[0], "address") == 0)
+		{
+			tracemode = ETMV1_TRACE_ADDR;
+		}
+		else if (strcmp(args[0], "all") == 0)
+		{
+			tracemode = ETMV1_TRACE_DATA | ETMV1_TRACE_ADDR;
+		}
+		else
+		{
+			command_print(cmd_ctx, "invalid option '%s'", args[0]);
+			return ERROR_OK;
+		}
+		
+		switch (strtol(args[1], NULL, 0))
+		{
+			case 0:
+				tracemode |= ETMV1_CONTEXTID_NONE;
+				break;
+			case 8:
+				tracemode |= ETMV1_CONTEXTID_8;
+				break;
+			case 16:
+				tracemode |= ETMV1_CONTEXTID_16;
+				break;
+			case 32:
+				tracemode |= ETMV1_CONTEXTID_32;
+				break;
+			default:
+				command_print(cmd_ctx, "invalid option '%s'", args[1]);
+				return ERROR_OK;
+		}
+		
+		if (strcmp(args[2], "enable") == 0)
+		{
+			tracemode |= ETMV1_CYCLE_ACCURATE;
+		}
+		else if (strcmp(args[2], "disable") == 0)
+		{
+			tracemode |= 0;
+		}
+		else
+		{
+			command_print(cmd_ctx, "invalid option '%s'", args[2]);
+			return ERROR_OK;
+		}
+	}
+	else if (argc != 0)
+	{
+		command_print(cmd_ctx, "usage: configure trace mode <none|data|address|all> <context id bits> <enable|disable cycle accurate>");
+		return ERROR_OK;
+	}
+	
+	command_print(cmd_ctx, "current tracemode configuration:");
+	
+	switch (tracemode & ETMV1_TRACE_MASK)
+	{
+		case ETMV1_TRACE_NONE:
+			command_print(cmd_ctx, "data tracing: none");
+			break;
+		case ETMV1_TRACE_DATA:
+			command_print(cmd_ctx, "data tracing: data only");
+			break;
+		case ETMV1_TRACE_ADDR:
+			command_print(cmd_ctx, "data tracing: address only");
+			break;
+		case ETMV1_TRACE_DATA | ETMV1_TRACE_ADDR:
+			command_print(cmd_ctx, "data tracing: address and data");
+			break;
+	}
+	
+	switch (tracemode & ETMV1_CONTEXTID_MASK)
+	{
+		case ETMV1_CONTEXTID_NONE:
+			command_print(cmd_ctx, "contextid tracing: none");
+			break;
+		case ETMV1_CONTEXTID_8:
+			command_print(cmd_ctx, "contextid tracing: 8 bit");
+			break;
+		case ETMV1_CONTEXTID_16:
+			command_print(cmd_ctx, "contextid tracing: 16 bit");
+			break;
+		case ETMV1_CONTEXTID_32:
+			command_print(cmd_ctx, "contextid tracing: 32 bit");
+			break;
+	}
+	
+	if (tracemode & ETMV1_CYCLE_ACCURATE)
+	{
+		command_print(cmd_ctx, "cycle-accurate tracing enabled");
+	}
+	else
+	{
+		command_print(cmd_ctx, "cycle-accurate tracing disabled");
+	}
+	
+	/* only update ETM_CTRL register if tracemode changed */
+	if (arm7_9->etm_ctx->tracemode != tracemode)
+	{
+		reg_t *etm_ctrl_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CTRL];
+		
+		etm_get_reg(etm_ctrl_reg);
+		
+		buf_set_u32(etm_ctrl_reg->value, 2, 2, tracemode & ETMV1_TRACE_MASK);
+		buf_set_u32(etm_ctrl_reg->value, 14, 2, (tracemode & ETMV1_CONTEXTID_MASK) >> 4);
+		buf_set_u32(etm_ctrl_reg->value, 12, 1, (tracemode & ETMV1_CYCLE_ACCURATE) >> 8);
+		
+		etm_store_reg(etm_ctrl_reg);
+		
+		arm7_9->etm_ctx->tracemode = tracemode;
+		
+		/* invalidate old trace data */
+		arm7_9->etm_ctx->capture_status = TRACE_IDLE;
+		if (arm7_9->etm_ctx->trace_depth > 0)
+		{
+			free(arm7_9->etm_ctx->trace_data);
+		}
+		arm7_9->etm_ctx->trace_depth = 0;
+	}
+	
+	return ERROR_OK;
+}
+
+int handle_etm_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+	target_t *target;
+	armv4_5_common_t *armv4_5;
+	arm7_9_common_t *arm7_9;
+	etm_portmode_t portmode = 0x0;
+	etm_context_t *etm_ctx = malloc(sizeof(etm_context_t));
+	int i;
+	
+	if (argc != 5)
+	{
+		ERROR("incomplete 'etm config <target> <port_width> <port_mode> <clocking> <capture_driver>' command");
+		exit(-1);
+	}
+	
+	target = get_target_by_num(strtoul(args[0], NULL, 0));
+	
+	if (!target)
+	{
+		ERROR("target number '%s' not defined", args[0]);
+		exit(-1);
+	}
+	
+	if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+	{
+		command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+		return ERROR_OK;
+	}
+	
+	switch (strtoul(args[1], NULL, 0))
+	{
+		case 4:
+			portmode |= ETM_PORT_4BIT;
+			break;
+		case 8:
+			portmode |= ETM_PORT_8BIT;
+			break;
+		case 16:
+			portmode |= ETM_PORT_16BIT;
+			break;
+		default:
+			command_print(cmd_ctx, "unsupported ETM port width '%s', must be 4, 8 or 16", args[1]);
+			return ERROR_OK;
+	}
+	
+	if (strcmp("normal", args[2]) == 0)
+	{
+		portmode |= ETM_PORT_NORMAL;
+	}
+	else if (strcmp("multiplexed", args[2]) == 0)
+	{
+		portmode |= ETM_PORT_MUXED;
+	}
+	else if (strcmp("demultiplexed", args[2]) == 0)
+	{
+		portmode |= ETM_PORT_DEMUXED;
+	}
+	else
+	{
+		command_print(cmd_ctx, "unsupported ETM port mode '%s', must be 'normal', 'multiplexed' or 'demultiplexed'", args[2]);
+		return ERROR_OK;
+	}
+	
+	if (strcmp("half", args[3]) == 0)
+	{
+		portmode |= ETM_PORT_HALF_CLOCK;
+	}
+	else if (strcmp("full", args[3]) == 0)
+	{
+		portmode |= ETM_PORT_FULL_CLOCK;
+	}
+	else
+	{
+		command_print(cmd_ctx, "unsupported ETM port clocking '%s', must be 'full' or 'half'", args[3]);
+		return ERROR_OK;
+	}
+	
+	for (i=0; etm_capture_drivers[i]; i++)
+	{
+		if (strcmp(args[4], etm_capture_drivers[i]->name) == 0)
+		{
+			if (etm_capture_drivers[i]->register_commands(cmd_ctx) != ERROR_OK)
+			{
+				free(etm_ctx);
+				exit(-1);
+			}
+		
+			etm_ctx->capture_driver = etm_capture_drivers[i];
+
+			break;
+		}
+	}
+	
+	etm_ctx->trace_data = NULL;
+	etm_ctx->trace_depth = 0;
+	etm_ctx->portmode = portmode;
+	etm_ctx->tracemode = 0x0;
+	etm_ctx->core_state = ARMV4_5_STATE_ARM;
+	etm_ctx->pipe_index = 0;
+	etm_ctx->data_index = 0;
+	etm_ctx->current_pc = 0x0;
+	etm_ctx->pc_ok = 0;
+	etm_ctx->last_branch = 0x0;
+	etm_ctx->last_ptr = 0x0;
+	etm_ctx->context_id = 0x0;
+	
+	arm7_9->etm_ctx = etm_ctx;
+	
+	etm_register_user_commands(cmd_ctx);
+	
+	return ERROR_OK;
+}
+
+int handle_etm_status_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+	target_t *target;
+	armv4_5_common_t *armv4_5;
+	arm7_9_common_t *arm7_9;
+	trace_status_t trace_status;
+	
+	target = get_current_target(cmd_ctx);
+	
+	if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+	{
+		command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+		return ERROR_OK;
+	}
+	
+	if (!arm7_9->etm_ctx)
+	{
+		command_print(cmd_ctx, "current target doesn't have an ETM configured");
+		return ERROR_OK;
+	}
+	
+	trace_status = arm7_9->etm_ctx->capture_driver->status(arm7_9->etm_ctx);
+	
+	if (trace_status == TRACE_IDLE)
+	{
+		command_print(cmd_ctx, "tracing is idle");
+	}
+	else
+	{
+		static char *completed = " completed";
+		static char *running = " is running";
+		static char *overflowed = ", trace overflowed";
+		static char *triggered = ", trace triggered";
+		
+		command_print(cmd_ctx, "trace collection%s%s%s", 
+			(trace_status & TRACE_RUNNING) ? running : completed,
+			(trace_status & TRACE_OVERFLOWED) ? overflowed : "",
+			(trace_status & TRACE_TRIGGERED) ? triggered : "");
+		
+		if (arm7_9->etm_ctx->trace_depth > 0)
+		{
+			command_print(cmd_ctx, "%i frames of trace data read", arm7_9->etm_ctx->trace_depth);
+		}
+	}
+	
+	return ERROR_OK;
+}
+
+int handle_etm_dump_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+	fileio_t file;
+	target_t *target;
+	armv4_5_common_t *armv4_5;
+	arm7_9_common_t *arm7_9;
+	etm_context_t *etm_ctx;
+	u32 size_written;
+	
+	if (argc != 1)
+	{
+		command_print(cmd_ctx, "usage: etm dump <file>");
+		return ERROR_OK;
+	}
+	
+	target = get_current_target(cmd_ctx);
+	
+	if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+	{
+		command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+		return ERROR_OK;
+	}
+	
+	if (!(etm_ctx = arm7_9->etm_ctx))
+	{
+		command_print(cmd_ctx, "current target doesn't have an ETM configured");
+		return ERROR_OK;
+	}
+	
+	if (etm_ctx->capture_driver->status == TRACE_IDLE)
+	{
+		command_print(cmd_ctx, "trace capture wasn't enabled, no trace data captured");
+		return ERROR_OK;
+	}
+
+	if (etm_ctx->capture_driver->status(etm_ctx) & TRACE_RUNNING)
+	{
+		/* TODO: if on-the-fly capture is to be supported, this needs to be changed */
+		command_print(cmd_ctx, "trace capture not completed");
+		return ERROR_OK;
+	}
+	
+	/* read the trace data if it wasn't read already */
+	if (etm_ctx->trace_depth == 0)
+		etm_ctx->capture_driver->read_trace(etm_ctx);
+	
+	if (fileio_open(&file, args[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK)
+	{
+		command_print(cmd_ctx, "file open error: %s", file.error_str);
+		return ERROR_OK;
+	}
+	
+	//fileio_write(&file, etm_ctx->trace_depth * 4, (u8*)etm_ctx->trace_data, &size_written);
+	
+	fileio_close(&file);
+	
+	return ERROR_OK;	
+}
+
+int handle_etm_load_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+	fileio_t file;
+	target_t *target;
+	armv4_5_common_t *armv4_5;
+	arm7_9_common_t *arm7_9;
+	etm_context_t *etm_ctx;
+	u32 size_read;
+	
+	if (argc != 1)
+	{
+		command_print(cmd_ctx, "usage: etm load <file>");
+		return ERROR_OK;
+	}
+	
+	target = get_current_target(cmd_ctx);
+	
+	if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+	{
+		command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+		return ERROR_OK;
+	}
+	
+	if (!(etm_ctx = arm7_9->etm_ctx))
+	{
+		command_print(cmd_ctx, "current target doesn't have an ETM configured");
+		return ERROR_OK;
+	}
+	
+	if (etm_ctx->capture_driver->status(etm_ctx) & TRACE_RUNNING)
+	{
+		command_print(cmd_ctx, "trace capture running, stop first");
+		return ERROR_OK;
+	}
+	
+	if (fileio_open(&file, args[0], FILEIO_READ, FILEIO_BINARY) != ERROR_OK)
+	{
+		command_print(cmd_ctx, "file open error: %s", file.error_str);
+		return ERROR_OK;
+	}
+	
+	if (file.size % 4)
+	{
+		command_print(cmd_ctx, "size isn't a multiple of 4, no valid trace data");
+		return ERROR_OK;
+	}
+	
+	if (etm_ctx->trace_depth > 0)
+	{
+		free(etm_ctx->trace_data);
+	}
+	
+	//fileio_read(&file, file.size, (u8*)etm_ctx->trace_data, &size_read);
+	etm_ctx->trace_depth = file.size / 4;
+	etm_ctx->capture_status = TRACE_COMPLETED;
+	
+	fileio_close(&file);
+	
+	return ERROR_OK;	
+}
+
+int handle_etm_start_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+	target_t *target;
+	armv4_5_common_t *armv4_5;
+	arm7_9_common_t *arm7_9;
+	etm_context_t *etm_ctx;
+	reg_t *etm_ctrl_reg;
+
+	target = get_current_target(cmd_ctx);
+	
+	if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+	{
+		command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+		return ERROR_OK;
+	}
+	
+	if (!(etm_ctx = arm7_9->etm_ctx))
+	{
+		command_print(cmd_ctx, "current target doesn't have an ETM configured");
+		return ERROR_OK;
+	}
+	
+	/* invalidate old tracing data */
+	arm7_9->etm_ctx->capture_status = TRACE_IDLE;
+	if (arm7_9->etm_ctx->trace_depth > 0)
+	{
+		free(arm7_9->etm_ctx->trace_data);
+	}
+	arm7_9->etm_ctx->trace_depth = 0;
+		
+	etm_ctrl_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CTRL];
+	etm_get_reg(etm_ctrl_reg);
+		
+	/* Clear programming bit (10), set port selection bit (11) */
+	buf_set_u32(etm_ctrl_reg->value, 10, 2, 0x2);
+
+	etm_store_reg(etm_ctrl_reg);
+	jtag_execute_queue();
+
+	etm_ctx->capture_driver->start_capture(etm_ctx);
+
+	return ERROR_OK;
+}
+
+int handle_etm_stop_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+	target_t *target;
+	armv4_5_common_t *armv4_5;
+	arm7_9_common_t *arm7_9;
+	etm_context_t *etm_ctx;
+	reg_t *etm_ctrl_reg;
+
+	target = get_current_target(cmd_ctx);
+	
+	if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+	{
+		command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+		return ERROR_OK;
+	}
+	
+	if (!(etm_ctx = arm7_9->etm_ctx))
+	{
+		command_print(cmd_ctx, "current target doesn't have an ETM configured");
+		return ERROR_OK;
+	}
+	
+	etm_ctrl_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CTRL];
+	etm_get_reg(etm_ctrl_reg);
+		
+	/* Set programming bit (10), clear port selection bit (11) */
+	buf_set_u32(etm_ctrl_reg->value, 10, 2, 0x1);
+
+	etm_store_reg(etm_ctrl_reg);	
+	jtag_execute_queue();
+	
+	etm_ctx->capture_driver->stop_capture(etm_ctx);
+	
+	return ERROR_OK;
+}
+
+int handle_etm_analyse_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+	target_t *target;
+	armv4_5_common_t *armv4_5;
+	arm7_9_common_t *arm7_9;
+	etm_context_t *etm_ctx;
+
+	target = get_current_target(cmd_ctx);
+	
+	if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+	{
+		command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+		return ERROR_OK;
+	}
+	
+	if (!(etm_ctx = arm7_9->etm_ctx))
+	{
+		command_print(cmd_ctx, "current target doesn't have an ETM configured");
+		return ERROR_OK;
+	}
+	
+	etmv1_analyse_trace(etm_ctx);
+	
+	return ERROR_OK;
+}
+
+int etm_register_commands(struct command_context_s *cmd_ctx)
+{
+	etm_cmd = register_command(cmd_ctx, NULL, "etm", NULL, COMMAND_ANY, "Embedded Trace Macrocell");
+
+	register_command(cmd_ctx, etm_cmd, "config", handle_etm_config_command, COMMAND_CONFIG, NULL);
+
+	return ERROR_OK;
+}
+
+int etm_register_user_commands(struct command_context_s *cmd_ctx)
+{
+	register_command(cmd_ctx, etm_cmd, "tracemode", handle_etm_tracemode_command,
+		COMMAND_EXEC, "configure trace mode <none|data|address|all> <context id bits> <enable|disable cycle accurate>");
+
+	register_command(cmd_ctx, etm_cmd, "status", handle_etm_status_command,
+		COMMAND_EXEC, "display current target's ETM status");
+	register_command(cmd_ctx, etm_cmd, "start", handle_etm_start_command,
+		COMMAND_EXEC, "start ETM trace collection");
+	register_command(cmd_ctx, etm_cmd, "stop", handle_etm_stop_command,
+		COMMAND_EXEC, "stop ETM trace collection");
+
+	register_command(cmd_ctx, etm_cmd, "analyze", handle_etm_stop_command,
+		COMMAND_EXEC, "anaylze collected ETM trace");
+
+	register_command(cmd_ctx, etm_cmd, "dump", handle_etm_dump_command,
+		COMMAND_EXEC, "dump captured trace data <file>");
+	register_command(cmd_ctx, etm_cmd, "load", handle_etm_load_command,
+		COMMAND_EXEC, "load trace data for analysis <file>");
+
+	return ERROR_OK;
+}
diff --git a/src/target/etm.h b/src/target/etm.h
index 4b24e5c8..59591788 100644
--- a/src/target/etm.h
+++ b/src/target/etm.h
@@ -1,7 +1,10 @@
 /***************************************************************************
- *   Copyright (C) 2005 by Dominic Rath                                    *
+ *   Copyright (C) 2005, 2007 by Dominic Rath                              *
  *   Dominic.Rath@gmx.de                                                   *
  *                                                                         *
+ *   Copyright (C) 2007 by Vincent Palatin                                 *
+ *   vincent.palatin_openocd@m4x.org                                       *
+ *                                                                         *
  *   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     *
@@ -20,11 +23,14 @@
 #ifndef ETM_H
 #define ETM_H
 
+#include "trace.h"
 #include "target.h"
 #include "register.h"
 #include "arm_jtag.h"
 
-// ETM registers (V1.2 protocol)
+#include "armv4_5.h"
+
+/* ETM registers (V1.3 protocol) */
 enum
 {
 	ETM_CTRL = 0x00,
@@ -58,14 +64,123 @@ enum
 	ETM_CONTEXTID_COMPARATOR_MASK = 0x6f,	
 };
 
-
 typedef struct etm_reg_s
 {
 	int addr;
 	arm_jtag_t *jtag_info;
 } etm_reg_t;
 
-extern reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, int extra_reg);
+typedef enum
+{
+	/* Port width */
+	ETM_PORT_4BIT		= 0x00,
+	ETM_PORT_8BIT		= 0x10,
+	ETM_PORT_16BIT		= 0x20,
+	ETM_PORT_WIDTH_MASK	= 0x70, 
+	/* Port modes */
+	ETM_PORT_NORMAL    = 0x00000,
+	ETM_PORT_MUXED     = 0x10000,
+	ETM_PORT_DEMUXED   = 0x20000,
+	ETM_PORT_MODE_MASK = 0x30000,
+	/* Clocking modes */
+	ETM_PORT_FULL_CLOCK = 0x0000,
+	ETM_PORT_HALF_CLOCK = 0x1000,
+	ETM_PORT_CLOCK_MASK = 0x1000,
+} etm_portmode_t;
+
+typedef enum
+{
+	/* Data trace */
+	ETMV1_TRACE_NONE	 = 0x00,
+	ETMV1_TRACE_DATA     = 0x01,
+	ETMV1_TRACE_ADDR     = 0x02,
+	ETMV1_TRACE_MASK     = 0x03,
+	/* ContextID */
+	ETMV1_CONTEXTID_NONE = 0x00,
+	ETMV1_CONTEXTID_8    = 0x10,
+	ETMV1_CONTEXTID_16   = 0x20,
+	ETMV1_CONTEXTID_32   = 0x30,
+	ETMV1_CONTEXTID_MASK = 0x30,
+	/* Misc */
+	ETMV1_CYCLE_ACCURATE = 0x100
+} etmv1_tracemode_t;
+
+/* forward-declare ETM context */
+struct etm_context_s;
+
+typedef struct etm_capture_driver_s
+{
+	char *name;
+	int (*register_commands)(struct command_context_s *cmd_ctx);
+	int (*init)(struct etm_context_s *etm_ctx);
+	trace_status_t (*status)(struct etm_context_s *etm_ctx);
+	int (*read_trace)(struct etm_context_s *etm_ctx);
+	int (*start_capture)(struct etm_context_s *etm_ctx);
+	int (*stop_capture)(struct etm_context_s *etm_ctx);
+} etm_capture_driver_t;
+
+typedef struct etmv1_trace_data_s
+{
+	u8 pipestat;	/* pipeline cycle this packet belongs to */
+	u16 packet;	/* packet data (4, 8 or 16 bit) */
+	int tracesync;	/* 1 if tracesync was set on this packet */
+} etmv1_trace_data_t;
+
+/* describe a trace context
+ * if support for ETMv2 or ETMv3 is to be implemented,
+ * this will have to be split into version independent elements
+ * and a version specific part
+ */
+typedef struct etm_context_s
+{
+	reg_cache_t *reg_cache;			/* ETM register cache */
+	etm_capture_driver_t *capture_driver;	/* driver used to access ETM data */
+	void *capture_driver_priv;		/* capture driver private data */
+	trace_status_t capture_status;	/* current state of capture run */ 
+	etmv1_trace_data_t *trace_data;	/* trace data */
+	u32 trace_depth;				/* number of trace cycles to be analyzed, 0 if no trace data available */
+	etm_portmode_t portmode;		/* normal, multiplexed or demultiplexed */
+	etmv1_tracemode_t tracemode;	/* type of information the trace contains (data, addres, contextID, ...) */ 
+	armv4_5_state_t core_state;		/* current core state (ARM, Thumb, Jazelle) */
+//	trace_image_provider_t image_provider; 	/* source for target opcodes */
+	u32 pipe_index;					/* current trace cycle */
+	u32 data_index;					/* cycle holding next data packet */
+	u32 current_pc;					/* current program counter */
+	u32 pc_ok;						/* full PC has been acquired */
+	u32 last_branch;				/* last branch address output */ 
+	u32 last_ptr;					/* address of the last data access */
+	u32 context_id;					/* context ID of the code being traced */
+} etm_context_t;
+
+/* PIPESTAT values */
+typedef enum
+{
+	STAT_IE = 0x0,
+	STAT_ID = 0x1,
+	STAT_IN = 0x2,
+	STAT_WT = 0x3,
+	STAT_BE = 0x4,
+	STAT_BD = 0x5,
+	STAT_TR = 0x6,
+	STAT_TD = 0x7
+} etmv1_pipestat_t;
+
+/* branch reason values */
+typedef enum
+{
+	BR_NORMAL  = 0x0, /* Normal PC change : periodic synchro (ETMv1.1) */
+	BR_ENABLE  = 0x1, /* Trace has been enabled */
+	BR_RESTART = 0x2, /* Trace restarted after a FIFO overflow */
+	BR_NODEBUG = 0x3, /* ARM has exited for debug state */
+	BR_PERIOD  = 0x4, /* Peridioc synchronization point (ETM>=v1.2)*/
+	BR_RSVD5   = 0x5, /* reserved */
+	BR_RSVD6   = 0x6, /* reserved */
+	BR_RSVD7   = 0x7, /* reserved */
+} etmv1_branch_reason_t;
+
+extern char *etmv1v1_branch_reason_strings[];
+
+extern reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, etm_context_t *etm_ctx);
 extern int etm_read_reg(reg_t *reg);
 extern int etm_write_reg(reg_t *reg, u32 value);
 extern int etm_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask);
@@ -73,4 +188,12 @@ extern int etm_store_reg(reg_t *reg);
 extern int etm_set_reg(reg_t *reg, u32 value);
 extern int etm_set_reg_w_exec(reg_t *reg, u8 *buf);
 
+int etm_register_commands(struct command_context_s *cmd_ctx);
+int etm_register_user_commands(struct command_context_s *cmd_ctx);
+extern etm_context_t* etm_create_context(etm_portmode_t portmode, char *capture_driver_name);
+
+#define ERROR_ETM_INVALID_DRIVER	(-1300)
+#define ERROR_ETM_PORTMODE_NOT_SUPPORTED	(-1301)
+#define ERROR_ETM_CAPTURE_INIT_FAILED	(-1302)
+
 #endif /* ETM_H */
diff --git a/src/target/target.c b/src/target/target.c
index 050a523e..e980ae4a 100644
--- a/src/target/target.c
+++ b/src/target/target.c
@@ -43,6 +43,7 @@
 #include <time_support.h>
 
 #include <fileio.h>
+#include <image.h>
 
 int cli_target_callback_event_handler(struct target_s *target, enum target_event event, void *priv);
 
@@ -1656,12 +1657,9 @@ int handle_load_image_command(struct command_context_s *cmd_ctx, char *cmd, char
 	u32 address;
 	u8 *buffer;
 	u32 buf_cnt;
-	u32 binary_size;
-	
-	fileio_t file;
-	enum fileio_pri_type pri_type = FILEIO_IMAGE;
-	fileio_image_t image_info;
-	enum fileio_sec_type sec_type;
+	u32 image_size;
+
+	image_t image;	
 	
 	duration_t duration;
 	char *duration_text;
@@ -1674,40 +1672,41 @@ int handle_load_image_command(struct command_context_s *cmd_ctx, char *cmd, char
 		return ERROR_OK;
 	}
 	
-	memset(&file, 0, sizeof(fileio_t));
-	fileio_identify_image_type(&sec_type, (argc == 3) ? args[2] : NULL);
+	identify_image_type(&image.type, (argc == 3) ? args[2] : NULL);
 
-	image_info.base_address = strtoul(args[1], NULL, 0);
-	image_info.has_start_address = 0;
+	image.base_address_set = 1;
+	image.base_address = strtoul(args[1], NULL, 0);
+	
+	image.start_address_set = 0;
 	
 	buffer = malloc(128 * 1024);
 
 	duration_start_measure(&duration);
 	
-	if (fileio_open(&file, args[0], FILEIO_READ, 
-		pri_type, &image_info, sec_type) != ERROR_OK)
+	if (image_open(&image, args[0], FILEIO_READ) != ERROR_OK)
 	{
-		command_print(cmd_ctx, "load_image error: %s", file.error_str);
+		command_print(cmd_ctx, "load_image error: %s", image.error_str);
 		return ERROR_OK;
 	}
 	
-	binary_size = file.size;
-	address = image_info.base_address;
-	while ((binary_size > 0) &&
-		(fileio_read(&file, 128 * 1024, buffer, &buf_cnt) == ERROR_OK))
+	image_size = image.size;
+	address = image.base_address;
+	
+	while ((image_size > 0) &&
+		(image_read(&image, 128 * 1024, buffer, &buf_cnt) == ERROR_OK))
 	{
 		target_write_buffer(target, address, buf_cnt, buffer);
 		address += buf_cnt;
-		binary_size -= buf_cnt;
+		image_size -= buf_cnt;
 	}
 
 	free(buffer);
 	
 	duration_stop_measure(&duration, &duration_text);
-	command_print(cmd_ctx, "downloaded %lli byte in %s", file.size, duration_text);
+	command_print(cmd_ctx, "downloaded %u byte in %s", image.size, duration_text);
 	free(duration_text);
 	
-	fileio_close(&file);
+	image_close(&image);
 
 	return ERROR_OK;
 
@@ -1715,8 +1714,7 @@ int handle_load_image_command(struct command_context_s *cmd_ctx, char *cmd, char
 
 int handle_dump_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
 {
-	fileio_t file;
-	fileio_image_t image_info;
+	fileio_t fileio;
 	
 	u32 address;
 	u32 size;
@@ -1742,13 +1740,9 @@ int handle_dump_image_command(struct command_context_s *cmd_ctx, char *cmd, char
 		return ERROR_OK;
 	}
 	
-	image_info.base_address = address;
-	image_info.has_start_address = 0;
-	
-	if (fileio_open(&file, args[0], FILEIO_WRITE, 
-		FILEIO_IMAGE, &image_info, FILEIO_PLAIN) != ERROR_OK)
+	if (fileio_open(&fileio, args[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK)
 	{
-		command_print(cmd_ctx, "dump_image error: %s", file.error_str);
+		command_print(cmd_ctx, "dump_image error: %s", fileio.error_str);
 		return ERROR_OK;
 	}
 	
@@ -1760,16 +1754,16 @@ int handle_dump_image_command(struct command_context_s *cmd_ctx, char *cmd, char
 		u32 this_run_size = (size > 560) ? 560 : size;
 		
 		target->type->read_memory(target, address, 4, this_run_size / 4, buffer);
-		fileio_write(&file, this_run_size, buffer, &size_written);
+		fileio_write(&fileio, this_run_size, buffer, &size_written);
 		
 		size -= this_run_size;
 		address += this_run_size;
 	}
 
-	fileio_close(&file);
+	fileio_close(&fileio);
 
 	duration_stop_measure(&duration, &duration_text);
-	command_print(cmd_ctx, "dumped %lli byte in %s", file.size, duration_text);
+	command_print(cmd_ctx, "dumped %lli byte in %s", fileio.size, duration_text);
 	free(duration_text);
 	
 	return ERROR_OK;
diff --git a/src/target/xscale/debug_handler.bin b/src/target/xscale/debug_handler.bin
new file mode 100755
index 00000000..2dde1853
Binary files /dev/null and b/src/target/xscale/debug_handler.bin differ
-- 
cgit v1.2.3