Beispiel #1
0
/* talk to the target and set things up */
static int nds32_v3m_examine(struct target *target)
{
	struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
	struct nds32 *nds32 = &(nds32_v3m->nds32);
	struct aice_port_s *aice = target_to_aice(target);

	if (!target_was_examined(target)) {
		CHECK_RETVAL(nds32_edm_config(nds32));

		if (nds32->reset_halt_as_examine)
			CHECK_RETVAL(nds32_reset_halt(nds32));
	}

	uint32_t edm_cfg;
	aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CFG, &edm_cfg);

	/* get the number of hardware breakpoints */
	nds32_v3m->n_hbr = (edm_cfg & 0x7) + 1;
	nds32_v3m->used_n_wp = 0;

	/* get the number of hardware watchpoints */
	/* If the WP field is hardwired to zero, it means this is a
	 * simple breakpoint.  Otherwise, if the WP field is writable
	 * then it means this is a regular watchpoints. */
	nds32_v3m->n_hwp = 0;
	for (int32_t i = 0 ; i < nds32_v3m->n_hbr ; i++) {
		/** check the hardware breakpoint is simple or not */
		uint32_t tmp_value;
		aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + i, 0x1);
		aice_read_debug_reg(aice, NDS_EDM_SR_BPC0 + i, &tmp_value);

		if (tmp_value)
			nds32_v3m->n_hwp++;
	}
	/* hardware breakpoint is inserted from high index to low index */
	nds32_v3m->next_hbr_index = nds32_v3m->n_hbr - 1;
	/* hardware watchpoint is inserted from low index to high index */
	nds32_v3m->next_hwp_index = 0;

	LOG_INFO("%s: total hardware breakpoint %d (simple breakpoint %d)",
			target_name(target), nds32_v3m->n_hbr, nds32_v3m->n_hbr - nds32_v3m->n_hwp);
	LOG_INFO("%s: total hardware watchpoint %d", target_name(target), nds32_v3m->n_hwp);

	nds32->target->state = TARGET_RUNNING;
	nds32->target->debug_reason = DBG_REASON_NOTHALTED;

	target_set_examined(target);

	return ERROR_OK;
}
Beispiel #2
0
int arc_ocd_examine(struct target *target)
{
	uint32_t status;
	struct arc32_common *arc32 = target_to_arc32(target);

	LOG_DEBUG("-");
	CHECK_RETVAL(arc_jtag_startup(&arc32->jtag_info));

	if (!target_was_examined(target)) {
		/* read ARC core info */
		if (strncmp(target_name(target), ARCEM_STR, 6) == 0) {
			arc32->processor_type = ARCEM_NUM;
			LOG_USER("Processor type: %s", ARCEM_STR);

		} else if (strncmp(target_name(target), ARC600_STR, 6) == 0) {
			arc32->processor_type = ARC600_NUM;
			LOG_USER("Processor type: %s", ARC600_STR);

		} else if (strncmp(target_name(target), ARC700_STR, 6) == 0) {
			arc32->processor_type = ARC700_NUM;
			LOG_USER("Processor type: %s", ARC700_STR);

		} else {
			LOG_WARNING(" THIS IS A UNSUPPORTED TARGET: %s", target_name(target));
		}

		CHECK_RETVAL(arc_jtag_status(&arc32->jtag_info, &status));
		if (status & ARC_JTAG_STAT_RU) {
			target->state = TARGET_RUNNING;
		} else {
			/* It is first time we examine the target, it is halted
			 * and we don't know why. Let's set debug reason,
			 * otherwise OpenOCD will complain that reason is
			 * unknown. */
			if (target->state == TARGET_UNKNOWN)
				target->debug_reason = DBG_REASON_DBGRQ;
			target->state = TARGET_HALTED;
		}

		/* Read BCRs and configure optinal registers. */
		CHECK_RETVAL(arc_regs_read_bcrs(target));
		arc_regs_build_reg_list(target);
		CHECK_RETVAL(arc32_configure(target));

		target_set_examined(target);
	}

	return ERROR_OK;
}
Beispiel #3
0
static int arm11_assert_reset(struct target *target)
{
	struct arm11_common *arm11 = target_to_arm11(target);

	/* optionally catch reset vector */
	if (target->reset_halt && !(arm11->vcr & 1))
		CHECK_RETVAL(arm11_sc7_set_vcr(arm11, arm11->vcr | 1));

	/* Issue some kind of warm reset. */
	if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) {
		target_handle_event(target, TARGET_EVENT_RESET_ASSERT);
	} else if (jtag_get_reset_config() & RESET_HAS_SRST) {
		/* REVISIT handle "pulls" cases, if there's
		 * hardware that needs them to work.
		 */
		jtag_add_reset(0, 1);
	} else {
		LOG_ERROR("%s: how to reset?", target_name(target));
		return ERROR_FAIL;
	}

	/* registers are now invalid */
	register_cache_invalidate(arm11->arm.core_cache);

	target->state = TARGET_RESET;

	return ERROR_OK;
}
Beispiel #4
0
static int arm11_deassert_reset(struct target *target)
{
	struct arm11_common *arm11 = target_to_arm11(target);
	int retval;

	/* be certain SRST is off */
	jtag_add_reset(0, 0);

	/* WORKAROUND i.MX31 problems:  SRST goofs the TAP, and resets
	 * at least DSCR.  OMAP24xx doesn't show that problem, though
	 * SRST-only reset seems to be problematic for other reasons.
	 * (Secure boot sequences being one likelihood!)
	 */
	jtag_add_tlr();

	CHECK_RETVAL(arm11_poll(target));

	if (target->reset_halt) {
		if (target->state != TARGET_HALTED) {
			LOG_WARNING("%s: ran after reset and before halt ...",
					target_name(target));
			if ((retval = target_halt(target)) != ERROR_OK)
				return retval;
		}
	}

	/* maybe restore vector catch config */
	if (target->reset_halt && !(arm11->vcr & 1))
		CHECK_RETVAL(arm11_sc7_set_vcr(arm11, arm11->vcr));

	return ERROR_OK;
}
Beispiel #5
0
static void
parse_answer_section(ns_msg *msg) {
	int rrnum, rrmax;
	ns_rr rr;
	uint16_t prio, weight, port, len;
	const unsigned char *rdata;
	char *tname;

	rrmax = ns_msg_count(*msg, ns_s_an);
	for (rrnum = 0; rrnum < rrmax; rrnum++) {
		if (ns_parserr(msg, ns_s_an, rrnum, &rr)) {
			perror("ns_parserr");
			exit(EXIT_FAILURE);
		}
		if (ns_rr_type(rr) == ns_t_srv) {
			len = ns_rr_rdlen(rr);
			rdata = ns_rr_rdata(rr);
			if (len > 3U * NS_INT16SZ) {
				NS_GET16(prio, rdata);
				NS_GET16(weight, rdata);
				NS_GET16(port, rdata);
				len -= 3U * NS_INT16SZ;
				tname = target_name(rdata);
				insert_tuple(tname, prio, weight, port);
			}
		}
	}
}
Beispiel #6
0
/**
 * Hooks up this DPM to its associated target; call only once.
 * Initially this only covers the register cache.
 *
 * Oh, and watchpoints.  Yeah.
 */
int arm_dpm_setup(struct arm_dpm *dpm)
{
	struct arm *arm = dpm->arm;
	struct target *target = arm->target;
	struct reg_cache *cache;

	arm->dpm = dpm;

	/* register access setup */
	arm->full_context = arm_dpm_full_context;
	arm->read_core_reg = arm_dpm_read_core_reg;
	arm->write_core_reg = arm_dpm_write_core_reg;

	cache = arm_build_reg_cache(target, arm);
	if (!cache)
		return ERROR_FAIL;

	*register_get_last_cache_p(&target->reg_cache) = cache;

	/* coprocessor access setup */
	arm->mrc = dpm_mrc;
	arm->mcr = dpm_mcr;

	/* breakpoint setup -- optional until it works everywhere */
	if (!target->type->add_breakpoint) {
		target->type->add_breakpoint = dpm_add_breakpoint;
		target->type->remove_breakpoint = dpm_remove_breakpoint;
	}

	/* watchpoint setup */
	target->type->add_watchpoint = dpm_add_watchpoint;
	target->type->remove_watchpoint = dpm_remove_watchpoint;

	/* FIXME add vector catch support */

	dpm->nbp = 1 + ((dpm->didr >> 24) & 0xf);
	dpm->dbp = calloc(dpm->nbp, sizeof *dpm->dbp);

	dpm->nwp = 1 + ((dpm->didr >> 28) & 0xf);
	dpm->dwp = calloc(dpm->nwp, sizeof *dpm->dwp);

	if (!dpm->dbp || !dpm->dwp) {
		free(dpm->dbp);
		free(dpm->dwp);
		return ERROR_FAIL;
	}

	LOG_INFO("%s: hardware has %d breakpoints, %d watchpoints",
		target_name(target), dpm->nbp, dpm->nwp);

	/* REVISIT ... and some of those breakpoints could match
	 * execution context IDs...
	 */

	return ERROR_OK;
}
Beispiel #7
0
void breakpoint_clear_target_internal(struct target *target)
{
	struct breakpoint *breakpoint;

	LOG_DEBUG("Delete all breakpoints for target: %s",
			target_name(target));
	while ((breakpoint = target->breakpoints) != NULL)
	{
		breakpoint_free(target, breakpoint);
	}
}
Beispiel #8
0
void watchpoint_clear_target(struct target *target)
{
	struct watchpoint *watchpoint;

	LOG_DEBUG("Delete all watchpoints for target: %s",
			target_name(target));
	while ((watchpoint = target->watchpoints) != NULL)
	{
		watchpoint_free(target, watchpoint);
	}
}
Beispiel #9
0
static int hwthread_fill_thread(struct rtos *rtos, struct target *curr, int thread_num)
{
	char tmp_str[HW_THREAD_NAME_STR_SIZE];
	threadid_t tid = threadid_from_target(curr);

	memset(tmp_str, 0, HW_THREAD_NAME_STR_SIZE);

	/* thread-id is the core-id of this core inside the SMP group plus 1 */
	rtos->thread_details[thread_num].threadid = tid;
	/* create the thread name */
	rtos->thread_details[thread_num].exists = true;
	rtos->thread_details[thread_num].thread_name_str = strdup(target_name(curr));
	snprintf(tmp_str, HW_THREAD_NAME_STR_SIZE-1, "state: %s", debug_reason_name(curr));
	rtos->thread_details[thread_num].extra_info_str = strdup(tmp_str);

	return ERROR_OK;
}
Beispiel #10
0
static int nds32_v3m_deassert_reset(struct target *target)
{
	int retval;

	CHECK_RETVAL(nds32_poll(target));

	if (target->state != TARGET_HALTED) {
		/* reset only */
		LOG_WARNING("%s: ran after reset and before halt ...",
				target_name(target));
		retval = target_halt(target);
		if (retval != ERROR_OK)
			return retval;

	}

	return ERROR_OK;
}
Beispiel #11
0
/**
 * Reinitializes DPM state at the beginning of a new debug session
 * or after a reset which may have affected the debug module.
 */
int arm_dpm_initialize(struct arm_dpm *dpm)
{
	/* Disable all breakpoints and watchpoints at startup. */
	if (dpm->bpwp_disable) {
		unsigned i;

		for (i = 0; i < dpm->nbp; i++) {
			dpm->dbp[i].bpwp.number = i;
			(void) dpm->bpwp_disable(dpm, i);
		}
		for (i = 0; i < dpm->nwp; i++) {
			dpm->dwp[i].bpwp.number = 16 + i;
			(void) dpm->bpwp_disable(dpm, 16 + i);
		}
	} else
		LOG_WARNING("%s: can't disable breakpoints and watchpoints",
			target_name(dpm->arm->target));

	return ERROR_OK;
}
Beispiel #12
0
/* Avoid needless I/O ... leave breakpoints and watchpoints alone
 * unless they're removed, or need updating because of single-stepping
 * or running debugger code.
 */
static int dpm_maybe_update_bpwp(struct arm_dpm *dpm, bool bpwp,
	struct dpm_bpwp *xp, int *set_p)
{
	int retval = ERROR_OK;
	bool disable;

	if (!set_p) {
		if (!xp->dirty)
			goto done;
		xp->dirty = false;
		/* removed or startup; we must disable it */
		disable = true;
	} else if (bpwp) {
		if (!xp->dirty)
			goto done;
		/* disabled, but we must set it */
		xp->dirty = disable = false;
		*set_p = true;
	} else {
		if (!*set_p)
			goto done;
		/* set, but we must temporarily disable it */
		xp->dirty = disable = true;
		*set_p = false;
	}

	if (disable)
		retval = dpm->bpwp_disable(dpm, xp->number);
	else
		retval = dpm->bpwp_enable(dpm, xp->number,
				xp->address, xp->control);

	if (retval != ERROR_OK)
		LOG_ERROR("%s: can't %s HW %spoint %d",
			disable ? "disable" : "enable",
			target_name(dpm->arm->target),
			(xp->number < 16) ? "break" : "watch",
			xp->number & 0xf);
done:
	return retval;
}
/*  retrieve core id cluster id  */
int armv8_read_mpidr(struct armv8_common *armv8)
{
	int retval = ERROR_FAIL;
	struct arm_dpm *dpm = armv8->arm.dpm;
	uint32_t mpidr;

	retval = dpm->prepare(dpm);
	if (retval != ERROR_OK)
		goto done;

	retval = dpm->instr_read_data_r0(dpm, armv8_opcode(armv8, READ_REG_MPIDR), &mpidr);
	if (retval != ERROR_OK)
		goto done;
	if (mpidr & 1<<31) {
		armv8->multi_processor_system = (mpidr >> 30) & 1;
		armv8->cluster_id = (mpidr >> 8) & 0xf;
		armv8->cpu_id = mpidr & 0x3;
		LOG_INFO("%s cluster %x core %x %s", target_name(armv8->arm.target),
			armv8->cluster_id,
			armv8->cpu_id,
			armv8->multi_processor_system == 0 ? "multi core" : "single core");
	} else
Beispiel #14
0
static int arm11_assert_reset(struct target *target)
{
	struct arm11_common *arm11 = target_to_arm11(target);

	if (!(target_was_examined(target))) {
		if (jtag_get_reset_config() & RESET_HAS_SRST)
			jtag_add_reset(0, 1);
		else {
			LOG_WARNING("Reset is not asserted because the target is not examined.");
			LOG_WARNING("Use a reset button or power cycle the target.");
			return ERROR_TARGET_NOT_EXAMINED;
		}
	} else {

		/* optionally catch reset vector */
		if (target->reset_halt && !(arm11->vcr & 1))
			CHECK_RETVAL(arm11_sc7_set_vcr(arm11, arm11->vcr | 1));

		/* Issue some kind of warm reset. */
		if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT))
			target_handle_event(target, TARGET_EVENT_RESET_ASSERT);
		else if (jtag_get_reset_config() & RESET_HAS_SRST) {
			/* REVISIT handle "pulls" cases, if there's
			 * hardware that needs them to work.
			 */
			jtag_add_reset(0, 1);
		} else {
			LOG_ERROR("%s: how to reset?", target_name(target));
			return ERROR_FAIL;
		}
	}

	/* registers are now invalid */
	register_cache_invalidate(arm11->arm.core_cache);

	target->state = TARGET_RESET;

	return ERROR_OK;
}
Beispiel #15
0
static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
{
	struct command_context *context;
	struct target *target;
	struct arm *arm;
	int retval;

	context = current_command_context(interp);
	assert(context != NULL);

	target = get_current_target(context);
	if (target == NULL) {
		LOG_ERROR("%s: no current target", __func__);
		return JIM_ERR;
	}
	if (!target_was_examined(target)) {
		LOG_ERROR("%s: not yet examined", target_name(target));
		return JIM_ERR;
	}
	arm = target_to_arm(target);
	if (!is_arm(arm)) {
		LOG_ERROR("%s: not an ARM", target_name(target));
		return JIM_ERR;
	}

	if ((argc < 6) || (argc > 7)) {
		/* FIXME use the command name to verify # params... */
		LOG_ERROR("%s: wrong number of arguments", __func__);
		return JIM_ERR;
	}

	int cpnum;
	uint32_t op1;
	uint32_t op2;
	uint32_t CRn;
	uint32_t CRm;
	uint32_t value;
	long l;

	/* NOTE:  parameter sequence matches ARM instruction set usage:
	 *	MCR	pNUM, op1, rX, CRn, CRm, op2	; write CP from rX
	 *	MRC	pNUM, op1, rX, CRn, CRm, op2	; read CP into rX
	 * The "rX" is necessarily omitted; it uses Tcl mechanisms.
	 */
	retval = Jim_GetLong(interp, argv[1], &l);
	if (retval != JIM_OK)
		return retval;
	if (l & ~0xf) {
		LOG_ERROR("%s: %s %d out of range", __func__,
			"coprocessor", (int) l);
		return JIM_ERR;
	}
	cpnum = l;

	retval = Jim_GetLong(interp, argv[2], &l);
	if (retval != JIM_OK)
		return retval;
	if (l & ~0x7) {
		LOG_ERROR("%s: %s %d out of range", __func__,
			"op1", (int) l);
		return JIM_ERR;
	}
	op1 = l;

	retval = Jim_GetLong(interp, argv[3], &l);
	if (retval != JIM_OK)
		return retval;
	if (l & ~0xf) {
		LOG_ERROR("%s: %s %d out of range", __func__,
			"CRn", (int) l);
		return JIM_ERR;
	}
	CRn = l;

	retval = Jim_GetLong(interp, argv[4], &l);
	if (retval != JIM_OK)
		return retval;
	if (l & ~0xf) {
		LOG_ERROR("%s: %s %d out of range", __func__,
			"CRm", (int) l);
		return JIM_ERR;
	}
	CRm = l;

	retval = Jim_GetLong(interp, argv[5], &l);
	if (retval != JIM_OK)
		return retval;
	if (l & ~0x7) {
		LOG_ERROR("%s: %s %d out of range", __func__,
			"op2", (int) l);
		return JIM_ERR;
	}
	op2 = l;

	value = 0;

	/* FIXME don't assume "mrc" vs "mcr" from the number of params;
	 * that could easily be a typo!  Check both...
	 *
	 * FIXME change the call syntax here ... simplest to just pass
	 * the MRC() or MCR() instruction to be executed.  That will also
	 * let us support the "mrc2" and "mcr2" opcodes (toggling one bit)
	 * if that's ever needed.
	 */
	if (argc == 7) {
		retval = Jim_GetLong(interp, argv[6], &l);
		if (retval != JIM_OK)
			return retval;
		value = l;

		/* NOTE: parameters reordered! */
		/* ARMV4_5_MCR(cpnum, op1, 0, CRn, CRm, op2) */
		retval = arm->mcr(target, cpnum, op1, op2, CRn, CRm, value);
		if (retval != ERROR_OK)
			return JIM_ERR;
	} else {
		/* NOTE: parameters reordered! */
		/* ARMV4_5_MRC(cpnum, op1, 0, CRn, CRm, op2) */
		retval = arm->mrc(target, cpnum, op1, op2, CRn, CRm, &value);
		if (retval != ERROR_OK)
			return JIM_ERR;

		Jim_SetResult(interp, Jim_NewIntObj(interp, value));
	}

	return JIM_OK;
}
Beispiel #16
0
static void
dependGraphOutput( TARGET *t, int depth )
{
    TARGETS	*c;

    if (   (t->flags & T_FLAG_VISITED) != 0
	|| !t->name
	|| !t->boundname)
	return;

    t->flags |= T_FLAG_VISITED;

    switch (t->fate)
    {
      case T_FATE_TOUCHED:
      case T_FATE_MISSING:
      case T_FATE_OUTDATED:
      case T_FATE_UPDATE:
	printf( "->%s%2d Name: %s\n", spaces(depth), depth, target_name(t) );
	break;
      default:
	printf( "  %s%2d Name: %s\n", spaces(depth), depth, target_name(t) );
	break;
    }

    if( strcmp (t->name, t->boundname) )
    {
	printf( "  %s    Loc: %s\n", spaces(depth), t->boundname );
    }

    switch( t->fate )
    {
      case T_FATE_STABLE:
	printf( "  %s       : Stable\n", spaces(depth) );
	break;
      case T_FATE_NEWER:
	printf( "  %s       : Newer\n", spaces(depth) );
	break;
      case T_FATE_ISTMP:
	printf( "  %s       : Up to date temp file\n", spaces(depth) );
      case T_FATE_NEEDTMP:
	printf( "  %s       : Temporary file, to be updated\n", spaces(depth) );
	break;
      case T_FATE_TOUCHED:
        printf( "  %s       : Been touched, updating it\n", spaces(depth) );
	break;
      case T_FATE_MISSING:
	printf( "  %s       : Missing, creating it\n", spaces(depth) );
	break;
      case T_FATE_OUTDATED:
	printf( "  %s       : Outdated, updating it\n", spaces(depth) );
	break;
      case T_FATE_REBUILD:
	printf( "  %s       : Rebuild, Updating it\n", spaces(depth) );
	break;
      case T_FATE_UPDATE:
	printf( "  %s       : Updating it\n", spaces(depth) );
	break;
      case T_FATE_CANTFIND:
	printf( "  %s       : Can't find it\n", spaces(depth) );
	break;
      case T_FATE_CANTMAKE:
	printf( "  %s       : Can't make it\n", spaces(depth) );
	break;
    }

    if( t->flags & ~T_FLAG_VISITED )
    {
	printf( "  %s       : ", spaces(depth) );
	if( t->flags & T_FLAG_TEMP ) printf ("TEMPORARY ");
	if( t->flags & T_FLAG_NOCARE ) printf ("NOCARE ");
	if( t->flags & T_FLAG_NOTFILE ) printf ("NOTFILE ");
	if( t->flags & T_FLAG_TOUCHED ) printf ("TOUCHED ");
	if( t->flags & T_FLAG_LEAVES ) printf ("LEAVES ");
	if( t->flags & T_FLAG_NOUPDATE ) printf ("NOUPDATE ");
	printf( "\n" );
    }

    for( c = t->depends; c; c = c->next )
    {
	printf( "  %s       : Depends on %s (%s)", spaces(depth),
	       target_name(c->target), target_fate[ c->target->fate ] );
    if (c->target->time == t->time)
        printf( " (max time)");
    printf("\n");
    
    }


    for( c = t->depends; c; c = c->next )
    {

	dependGraphOutput( c->target, depth + 1 );
    }
}
Beispiel #17
0
/**
 * Probe EmbeddedICE module and set up local records of its registers.
 * Different versions of the modules have different capabilities, such as
 * hardware support for vector_catch, single stepping, and monitor mode.
 */
struct reg_cache *embeddedice_build_reg_cache(struct target *target,
		struct arm7_9_common *arm7_9)
{
	int retval;
	struct reg_cache *reg_cache = malloc(sizeof(struct reg_cache));
	struct reg *reg_list = NULL;
	struct embeddedice_reg *arch_info = NULL;
	struct arm_jtag *jtag_info = &arm7_9->jtag_info;
	int num_regs = ARRAY_SIZE(eice_regs);
	int i;
	int eice_version = 0;

	/* vector_catch isn't always present */
	if (!arm7_9->has_vector_catch)
		num_regs--;

	/* the actual registers are kept in two arrays */
	reg_list = calloc(num_regs, sizeof(struct reg));
	arch_info = calloc(num_regs, sizeof(struct embeddedice_reg));

	/* fill in values for the reg cache */
	reg_cache->name = "EmbeddedICE registers";
	reg_cache->next = NULL;
	reg_cache->reg_list = reg_list;
	reg_cache->num_regs = num_regs;

	/* FIXME the second watchpoint unit on Feroceon and Dragonite
	 * seems not to work ... we should have a way to not set up
	 * its four registers here!
	 */

	/* set up registers */
	for (i = 0; i < num_regs; i++) {
		reg_list[i].name = eice_regs[i].name;
		reg_list[i].size = eice_regs[i].width;
		reg_list[i].dirty = 0;
		reg_list[i].valid = 0;
		reg_list[i].value = calloc(1, 4);
		reg_list[i].arch_info = &arch_info[i];
		reg_list[i].type = &eice_reg_type;
		arch_info[i].addr = eice_regs[i].addr;
		arch_info[i].jtag_info = jtag_info;
	}

	/* identify EmbeddedICE version by reading DCC control register */
	embeddedice_read_reg(&reg_list[EICE_COMMS_CTRL]);
	retval = jtag_execute_queue();
	if (retval != ERROR_OK) {
		for (i = 0; i < num_regs; i++)
			free(reg_list[i].value);
		free(reg_list);
		free(reg_cache);
		free(arch_info);
		return NULL;
	}

	eice_version = buf_get_u32(reg_list[EICE_COMMS_CTRL].value, 28, 4);
	LOG_INFO("Embedded ICE version %d", eice_version);

	switch (eice_version) {
		case 1:
			/* ARM7TDMI r3, ARM7TDMI-S r3
			 *
			 * REVISIT docs say ARM7TDMI-S r4 uses version 1 but
			 * that it has 6-bit CTRL and 5-bit STAT... doc bug?
			 * ARM7TDMI r4 docs say EICE v4.
			 */
			reg_list[EICE_DBG_CTRL].size = 3;
			reg_list[EICE_DBG_STAT].size = 5;
			break;
		case 2:
			/* ARM9TDMI */
			reg_list[EICE_DBG_CTRL].size = 4;
			reg_list[EICE_DBG_STAT].size = 5;
			arm7_9->has_single_step = 1;
			break;
		case 3:
			LOG_ERROR("EmbeddedICE v%d handling might be broken",
					eice_version);
			reg_list[EICE_DBG_CTRL].size = 6;
			reg_list[EICE_DBG_STAT].size = 5;
			arm7_9->has_single_step = 1;
			arm7_9->has_monitor_mode = 1;
			break;
		case 4:
			/* ARM7TDMI r4 */
			reg_list[EICE_DBG_CTRL].size = 6;
			reg_list[EICE_DBG_STAT].size = 5;
			arm7_9->has_monitor_mode = 1;
			break;
		case 5:
			/* ARM9E-S rev 1 */
			reg_list[EICE_DBG_CTRL].size = 6;
			reg_list[EICE_DBG_STAT].size = 5;
			arm7_9->has_single_step = 1;
			arm7_9->has_monitor_mode = 1;
			break;
		case 6:
			/* ARM7EJ-S, ARM9E-S rev 2, ARM9EJ-S */
			reg_list[EICE_DBG_CTRL].size = 6;
			reg_list[EICE_DBG_STAT].size = 10;
			/* DBG_STAT has MOE bits */
			arm7_9->has_monitor_mode = 1;
			break;
		case 7:
			LOG_ERROR("EmbeddedICE v%d handling might be broken",
					eice_version);
			reg_list[EICE_DBG_CTRL].size = 6;
			reg_list[EICE_DBG_STAT].size = 5;
			arm7_9->has_monitor_mode = 1;
			break;
		default:
			/*
			 * The Feroceon implementation has the version number
			 * in some unusual bits.  Let feroceon.c validate it
			 * and do the appropriate setup itself.
			 */
			if (strcmp(target_type_name(target), "feroceon") == 0 ||
					strcmp(target_type_name(target), "dragonite") == 0)
				break;
			LOG_ERROR("unknown EmbeddedICE version "
				"(comms ctrl: 0x%8.8" PRIx32 ")",
				buf_get_u32(reg_list[EICE_COMMS_CTRL].value, 0, 32));
	}

	/* On Feroceon and Dragonite the second unit is seemingly missing. */
	LOG_INFO("%s: hardware has %d breakpoint/watchpoint unit%s",
			target_name(target), arm7_9->wp_available_max,
			(arm7_9->wp_available_max != 1) ? "s" : "");

	return reg_cache;
}