target.c 118 KB
Newer Older
zwelch's avatar
zwelch committed
3001
			val = buckets[i];
zwelch's avatar
zwelch committed
3002
			if (val > 65535)
3003
			{
zwelch's avatar
zwelch committed
3004
				val = 65535;
3005
3006
			}
			data[i*2]=val&0xff;
zwelch's avatar
zwelch committed
3007
			data[i*2 + 1]=(val >> 8)&0xff;
3008
3009
		}
		free(buckets);
3010
		writeData(f, data, length * 2);
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
		free(data);
	} else
	{
		free(buckets);
	}

	fclose(f);
}

/* profiling samples the CPU PC as quickly as OpenOCD is able, which will be used as a random sampling of PC */
3021
COMMAND_HANDLER(handle_profile_command)
3022
3023
3024
{
	target_t *target = get_current_target(cmd_ctx);
	struct timeval timeout, now;
oharboe's avatar
oharboe committed
3025

3026
	gettimeofday(&timeout, NULL);
zwelch's avatar
zwelch committed
3027
	if (argc != 2)
3028
3029
3030
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
3031
	unsigned offset;
3032
	COMMAND_PARSE_NUMBER(uint, args[0], offset);
3033
3034

	timeval_add_time(&timeout, offset, 0);
oharboe's avatar
oharboe committed
3035

3036
3037
	command_print(cmd_ctx, "Starting profiling. Halting and resuming the target as often as we can...");

zwelch's avatar
zwelch committed
3038
3039
	static const int maxSample = 10000;
	uint32_t *samples = malloc(sizeof(uint32_t)*maxSample);
zwelch's avatar
zwelch committed
3040
	if (samples == NULL)
3041
		return ERROR_OK;
oharboe's avatar
oharboe committed
3042

zwelch's avatar
zwelch committed
3043
	int numSamples = 0;
3044
	/* hopefully it is safe to cache! We want to stop/restart as quickly as possible. */
Zachary T Welch's avatar
Zachary T Welch committed
3045
	struct reg *reg = register_get_by_name(target->reg_cache, "pc", 1);
oharboe's avatar
oharboe committed
3046

3047
3048
	for (;;)
	{
3049
		int retval;
3050
		target_poll(target);
3051
3052
		if (target->state == TARGET_HALTED)
		{
3053
			uint32_t t=*((uint32_t *)reg->value);
3054
			samples[numSamples++]=t;
3055
3056
			retval = target_resume(target, 1, 0, 0, 0); /* current pc, addr = 0, do not handle breakpoints, not debugging */
			target_poll(target);
3057
			alive_sleep(10); /* sleep 10ms, i.e. <100 samples/second. */
3058
3059
		} else if (target->state == TARGET_RUNNING)
		{
3060
			/* We want to quickly sample the PC. */
zwelch's avatar
zwelch committed
3061
			if ((retval = target_halt(target)) != ERROR_OK)
3062
3063
3064
3065
			{
				free(samples);
				return retval;
			}
3066
3067
3068
		} else
		{
			command_print(cmd_ctx, "Target not halted or running");
zwelch's avatar
zwelch committed
3069
			retval = ERROR_OK;
3070
3071
			break;
		}
zwelch's avatar
zwelch committed
3072
		if (retval != ERROR_OK)
3073
3074
3075
		{
			break;
		}
oharboe's avatar
oharboe committed
3076

3077
		gettimeofday(&now, NULL);
zwelch's avatar
zwelch committed
3078
		if ((numSamples >= maxSample) || ((now.tv_sec >= timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec)))
3079
3080
		{
			command_print(cmd_ctx, "Profiling completed. %d samples.", numSamples);
zwelch's avatar
zwelch committed
3081
			if ((retval = target_poll(target)) != ERROR_OK)
3082
3083
3084
3085
			{
				free(samples);
				return retval;
			}
3086
3087
			if (target->state == TARGET_HALTED)
			{
3088
				target_resume(target, 1, 0, 0, 0); /* current pc, addr = 0, do not handle breakpoints, not debugging */
3089
			}
zwelch's avatar
zwelch committed
3090
			if ((retval = target_poll(target)) != ERROR_OK)
3091
3092
3093
3094
			{
				free(samples);
				return retval;
			}
3095
3096
3097
3098
3099
3100
			writeGmon(samples, numSamples, args[1]);
			command_print(cmd_ctx, "Wrote %s", args[1]);
			break;
		}
	}
	free(samples);
oharboe's avatar
oharboe committed
3101

3102
3103
	return ERROR_OK;
}
3104

3105
static int new_int_array_element(Jim_Interp * interp, const char *varname, int idx, uint32_t val)
3106
3107
3108
3109
3110
3111
3112
3113
{
	char *namebuf;
	Jim_Obj *nameObjPtr, *valObjPtr;
	int result;

	namebuf = alloc_printf("%s(%d)", varname, idx);
	if (!namebuf)
		return JIM_ERR;
oharboe's avatar
oharboe committed
3114

3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
	nameObjPtr = Jim_NewStringObj(interp, namebuf, -1);
	valObjPtr = Jim_NewIntObj(interp, val);
	if (!nameObjPtr || !valObjPtr)
	{
		free(namebuf);
		return JIM_ERR;
	}

	Jim_IncrRefCount(nameObjPtr);
	Jim_IncrRefCount(valObjPtr);
	result = Jim_SetVariable(interp, nameObjPtr, valObjPtr);
	Jim_DecrRefCount(interp, nameObjPtr);
	Jim_DecrRefCount(interp, valObjPtr);
	free(namebuf);
	/* printf("%s(%d) <= 0%08x\n", varname, idx, val); */
	return result;
}

static int jim_mem2array(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
	command_context_t *context;
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
	target_t *target;

	context = Jim_GetAssocData(interp, "context");
	if (context == NULL)
	{
		LOG_ERROR("mem2array: no command context");
		return JIM_ERR;
	}
	target = get_current_target(context);
	if (target == NULL)
	{
		LOG_ERROR("mem2array: no current target");
		return JIM_ERR;
	}

zwelch's avatar
zwelch committed
3151
	return 	target_mem2array(interp, target, argc-1, argv + 1);
3152
3153
3154
3155
}

static int target_mem2array(Jim_Interp *interp, target_t *target, int argc, Jim_Obj *const *argv)
{
3156
	long l;
3157
	uint32_t width;
3158
	int len;
3159
3160
3161
	uint32_t addr;
	uint32_t count;
	uint32_t v;
3162
	const char *varname;
3163
	uint8_t buffer[4096];
3164
	int  n, e, retval;
3165
	uint32_t i;
3166
3167
3168

	/* argv[1] = name of array to receive the data
	 * argv[2] = desired width
oharboe's avatar
oharboe committed
3169
	 * argv[3] = memory address
3170
3171
	 * argv[4] = count of times to read
	 */
3172
	if (argc != 4) {
3173
3174
3175
		Jim_WrongNumArgs(interp, 1, argv, "varname width addr nelems");
		return JIM_ERR;
	}
3176
	varname = Jim_GetString(argv[0], &len);
3177
3178
	/* given "foo" get space for worse case "foo(%d)" .. add 20 */

3179
	e = Jim_GetLong(interp, argv[1], &l);
3180
3181
3182
3183
	width = l;
	if (e != JIM_OK) {
		return e;
	}
oharboe's avatar
oharboe committed
3184

3185
	e = Jim_GetLong(interp, argv[2], &l);
3186
3187
3188
3189
	addr = l;
	if (e != JIM_OK) {
		return e;
	}
3190
	e = Jim_GetLong(interp, argv[3], &l);
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
	len = l;
	if (e != JIM_OK) {
		return e;
	}
	switch (width) {
		case 8:
			width = 1;
			break;
		case 16:
			width = 2;
			break;
		case 32:
			width = 4;
			break;
		default:
			Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
3207
			Jim_AppendStrings(interp, Jim_GetResult(interp), "Invalid width param, must be 8/16/32", NULL);
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
			return JIM_ERR;
	}
	if (len == 0) {
		Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
		Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: zero width read?", NULL);
		return JIM_ERR;
	}
	if ((addr + (len * width)) < addr) {
		Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
		Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: addr + len - wraps to zero?", NULL);
		return JIM_ERR;
	}
	/* absurd transfer size? */
	if (len > 65536) {
		Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
		Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: absurd > 64K item request", NULL);
		return JIM_ERR;
oharboe's avatar
oharboe committed
3225
3226
	}

3227
3228
3229
3230
3231
3232
3233
	if ((width == 1) ||
		((width == 2) && ((addr & 1) == 0)) ||
		((width == 4) && ((addr & 3) == 0))) {
		/* all is well */
	} else {
		char buf[100];
		Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
3234
3235
		sprintf(buf, "mem2array address: 0x%08" PRIx32 " is not aligned for %" PRId32 " byte reads",
				addr,
duane's avatar
duane committed
3236
				width);
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
		Jim_AppendStrings(interp, Jim_GetResult(interp), buf , NULL);
		return JIM_ERR;
	}

	/* Transfer loop */

	/* index counter */
	n = 0;
	/* assume ok */
	e = JIM_OK;
	while (len) {
		/* Slurp... in buffer size chunks */
oharboe's avatar
oharboe committed
3249

3250
3251
3252
3253
		count = len; /* in objects.. */
		if (count > (sizeof(buffer)/width)) {
			count = (sizeof(buffer)/width);
		}
oharboe's avatar
oharboe committed
3254

3255
		retval = target_read_memory(target, addr, width, count, buffer);
3256
3257
		if (retval != ERROR_OK) {
			/* BOO !*/
3258
3259
3260
			LOG_ERROR("mem2array: Read @ 0x%08x, w=%d, cnt=%d, failed",
					  (unsigned int)addr,
					  (int)width,
duane's avatar
duane committed
3261
					  (int)count);
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
			Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
			Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: cannot read memory", NULL);
			e = JIM_ERR;
			len = 0;
		} else {
			v = 0; /* shut up gcc */
			for (i = 0 ;i < count ;i++, n++) {
				switch (width) {
					case 4:
						v = target_buffer_get_u32(target, &buffer[i*width]);
						break;
					case 2:
						v = target_buffer_get_u16(target, &buffer[i*width]);
						break;
					case 1:
						v = buffer[i] & 0x0ff;
						break;
				}
				new_int_array_element(interp, varname, n, v);
			}
			len -= count;
		}
	}
oharboe's avatar
oharboe committed
3285

3286
3287
3288
3289
3290
	Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));

	return JIM_OK;
}

3291
static int get_int_array_element(Jim_Interp * interp, const char *varname, int idx, uint32_t *val)
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
{
	char *namebuf;
	Jim_Obj *nameObjPtr, *valObjPtr;
	int result;
	long l;

	namebuf = alloc_printf("%s(%d)", varname, idx);
	if (!namebuf)
		return JIM_ERR;

	nameObjPtr = Jim_NewStringObj(interp, namebuf, -1);
	if (!nameObjPtr)
	{
		free(namebuf);
		return JIM_ERR;
	}

	Jim_IncrRefCount(nameObjPtr);
	valObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_ERRMSG);
	Jim_DecrRefCount(interp, nameObjPtr);
	free(namebuf);
	if (valObjPtr == NULL)
		return JIM_ERR;

	result = Jim_GetLong(interp, valObjPtr, &l);
	/* printf("%s(%d) => 0%08x\n", varname, idx, val); */
	*val = l;
	return result;
}

static int jim_array2mem(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
	command_context_t *context;
3325
	target_t *target;
3326

3327
	context = Jim_GetAssocData(interp, "context");
zwelch's avatar
zwelch committed
3328
	if (context == NULL) {
3329
3330
3331
3332
		LOG_ERROR("array2mem: no command context");
		return JIM_ERR;
	}
	target = get_current_target(context);
zwelch's avatar
zwelch committed
3333
	if (target == NULL) {
3334
3335
3336
		LOG_ERROR("array2mem: no current target");
		return JIM_ERR;
	}
3337

3338
	return target_array2mem(interp,target, argc-1, argv + 1);
3339
3340
3341
}
static int target_array2mem(Jim_Interp *interp, target_t *target, int argc, Jim_Obj *const *argv)
{
3342
	long l;
3343
	uint32_t width;
3344
	int len;
3345
3346
3347
	uint32_t addr;
	uint32_t count;
	uint32_t v;
3348
	const char *varname;
3349
	uint8_t buffer[4096];
3350
	int  n, e, retval;
3351
	uint32_t i;
3352
3353
3354

	/* argv[1] = name of array to get the data
	 * argv[2] = desired width
oharboe's avatar
oharboe committed
3355
	 * argv[3] = memory address
3356
3357
	 * argv[4] = count to write
	 */
3358
	if (argc != 4) {
3359
3360
3361
		Jim_WrongNumArgs(interp, 1, argv, "varname width addr nelems");
		return JIM_ERR;
	}
3362
	varname = Jim_GetString(argv[0], &len);
3363
3364
	/* given "foo" get space for worse case "foo(%d)" .. add 20 */

3365
	e = Jim_GetLong(interp, argv[1], &l);
3366
3367
3368
3369
	width = l;
	if (e != JIM_OK) {
		return e;
	}
oharboe's avatar
oharboe committed
3370

3371
	e = Jim_GetLong(interp, argv[2], &l);
3372
3373
3374
3375
	addr = l;
	if (e != JIM_OK) {
		return e;
	}
3376
	e = Jim_GetLong(interp, argv[3], &l);
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
	len = l;
	if (e != JIM_OK) {
		return e;
	}
	switch (width) {
		case 8:
			width = 1;
			break;
		case 16:
			width = 2;
			break;
		case 32:
			width = 4;
			break;
		default:
			Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
3393
			Jim_AppendStrings(interp, Jim_GetResult(interp), "Invalid width param, must be 8/16/32", NULL);
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
			return JIM_ERR;
	}
	if (len == 0) {
		Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
		Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: zero width read?", NULL);
		return JIM_ERR;
	}
	if ((addr + (len * width)) < addr) {
		Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
		Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: addr + len - wraps to zero?", NULL);
		return JIM_ERR;
	}
	/* absurd transfer size? */
	if (len > 65536) {
		Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
		Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: absurd > 64K item request", NULL);
		return JIM_ERR;
oharboe's avatar
oharboe committed
3411
3412
	}

3413
3414
3415
3416
3417
3418
3419
	if ((width == 1) ||
		((width == 2) && ((addr & 1) == 0)) ||
		((width == 4) && ((addr & 3) == 0))) {
		/* all is well */
	} else {
		char buf[100];
		Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
3420
3421
		sprintf(buf, "array2mem address: 0x%08x is not aligned for %d byte reads",
				(unsigned int)addr,
duane's avatar
duane committed
3422
				(int)width);
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
		Jim_AppendStrings(interp, Jim_GetResult(interp), buf , NULL);
		return JIM_ERR;
	}

	/* Transfer loop */

	/* index counter */
	n = 0;
	/* assume ok */
	e = JIM_OK;
	while (len) {
		/* Slurp... in buffer size chunks */
oharboe's avatar
oharboe committed
3435

3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
		count = len; /* in objects.. */
		if (count > (sizeof(buffer)/width)) {
			count = (sizeof(buffer)/width);
		}

		v = 0; /* shut up gcc */
		for (i = 0 ;i < count ;i++, n++) {
			get_int_array_element(interp, varname, n, &v);
			switch (width) {
			case 4:
				target_buffer_set_u32(target, &buffer[i*width], v);
				break;
			case 2:
				target_buffer_set_u16(target, &buffer[i*width], v);
				break;
			case 1:
				buffer[i] = v & 0x0ff;
				break;
			}
		}
		len -= count;

zwelch's avatar
zwelch committed
3458
		retval = target_write_memory(target, addr, width, count, buffer);
3459
3460
		if (retval != ERROR_OK) {
			/* BOO !*/
3461
3462
3463
			LOG_ERROR("array2mem: Write @ 0x%08x, w=%d, cnt=%d, failed",
					  (unsigned int)addr,
					  (int)width,
duane's avatar
duane committed
3464
					  (int)count);
3465
			Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
3466
			Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: cannot read memory", NULL);
3467
3468
3469
3470
			e = JIM_ERR;
			len = 0;
		}
	}
oharboe's avatar
oharboe committed
3471

3472
3473
3474
3475
	Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));

	return JIM_OK;
}
3476

3477
void target_all_handle_event(enum target_event e)
3478
3479
3480
{
	target_t *target;

3481
	LOG_DEBUG("**all*targets: event: %d, %s",
duane's avatar
duane committed
3482
			   (int)e,
3483
			   Jim_Nvp_value2name_simple(nvp_target_event, e)->name);
3484
3485

	target = all_targets;
zwelch's avatar
zwelch committed
3486
	while (target) {
3487
		target_handle_event(target, e);
3488
3489
3490
3491
		target = target->next;
	}
}

3492
3493
3494
3495

/* FIX? should we propagate errors here rather than printing them
 * and continuing?
 */
3496
void target_handle_event(target_t *target, enum target_event e)
3497
{
3498
	struct target_event_action *teap;
3499

dbrownell's avatar
dbrownell committed
3500
	for (teap = target->event_action; teap != NULL; teap = teap->next) {
zwelch's avatar
zwelch committed
3501
		if (teap->event == e) {
3502
			LOG_DEBUG("target: (%d) %s (%s) event: %d (%s) action: %s",
3503
3504
					   target->target_number,
					   target->cmd_name,
zwelch's avatar
zwelch committed
3505
					   target_get_name(target),
3506
					   e,
3507
3508
3509
					   Jim_Nvp_value2name_simple(nvp_target_event, e)->name,
					   Jim_GetString(teap->body, NULL));
			if (Jim_EvalObj(interp, teap->body) != JIM_OK)
3510
3511
3512
			{
				Jim_PrintErrorMessage(interp);
			}
3513
3514
3515
3516
3517
3518
		}
	}
}

enum target_cfg_param {
	TCFG_TYPE,
3519
	TCFG_EVENT,
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
	TCFG_WORK_AREA_VIRT,
	TCFG_WORK_AREA_PHYS,
	TCFG_WORK_AREA_SIZE,
	TCFG_WORK_AREA_BACKUP,
	TCFG_ENDIAN,
	TCFG_VARIANT,
	TCFG_CHAIN_POSITION,
};

static Jim_Nvp nvp_config_opts[] = {
	{ .name = "-type",             .value = TCFG_TYPE },
	{ .name = "-event",            .value = TCFG_EVENT },
	{ .name = "-work-area-virt",   .value = TCFG_WORK_AREA_VIRT },
	{ .name = "-work-area-phys",   .value = TCFG_WORK_AREA_PHYS },
	{ .name = "-work-area-size",   .value = TCFG_WORK_AREA_SIZE },
	{ .name = "-work-area-backup", .value = TCFG_WORK_AREA_BACKUP },
	{ .name = "-endian" ,          .value = TCFG_ENDIAN },
	{ .name = "-variant",          .value = TCFG_VARIANT },
	{ .name = "-chain-position",   .value = TCFG_CHAIN_POSITION },
3539

3540
3541
	{ .name = NULL, .value = -1 }
};
3542

3543
static int target_configure(Jim_GetOptInfo *goi, target_t *target)
3544
3545
3546
3547
3548
3549
3550
3551
{
	Jim_Nvp *n;
	Jim_Obj *o;
	jim_wide w;
	char *cp;
	int e;

	/* parse config or cget options ... */
zwelch's avatar
zwelch committed
3552
	while (goi->argc > 0) {
3553
3554
		Jim_SetEmptyResult(goi->interp);
		/* Jim_GetOpt_Debug(goi); */
3555

zwelch's avatar
zwelch committed
3556
		if (target->type->target_jim_configure) {
3557
3558
			/* target defines a configure function */
			/* target gets first dibs on parameters */
3559
			e = (*(target->type->target_jim_configure))(target, goi);
zwelch's avatar
zwelch committed
3560
			if (e == JIM_OK) {
3561
3562
3563
				/* more? */
				continue;
			}
zwelch's avatar
zwelch committed
3564
			if (e == JIM_ERR) {
3565
3566
3567
3568
3569
				/* An error */
				return e;
			}
			/* otherwise we 'continue' below */
		}
3570
		e = Jim_GetOpt_Nvp(goi, nvp_config_opts, &n);
zwelch's avatar
zwelch committed
3571
		if (e != JIM_OK) {
3572
			Jim_GetOpt_NvpUnknown(goi, nvp_config_opts, 0);
3573
3574
			return e;
		}
zwelch's avatar
zwelch committed
3575
		switch (n->value) {
3576
3577
		case TCFG_TYPE:
			/* not setable */
zwelch's avatar
zwelch committed
3578
			if (goi->isconfigure) {
3579
				Jim_SetResult_sprintf(goi->interp, "not setable: %s", n->name);
3580
3581
3582
				return JIM_ERR;
			} else {
			no_params:
zwelch's avatar
zwelch committed
3583
				if (goi->argc != 0) {
3584
					Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "NO PARAMS");
3585
3586
3587
					return JIM_ERR;
				}
			}
3588
			Jim_SetResultString(goi->interp, target_get_name(target), -1);
3589
3590
3591
			/* loop for more */
			break;
		case TCFG_EVENT:
zwelch's avatar
zwelch committed
3592
			if (goi->argc == 0) {
3593
				Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name? ...");
3594
3595
3596
				return JIM_ERR;
			}

3597
			e = Jim_GetOpt_Nvp(goi, nvp_target_event, &n);
zwelch's avatar
zwelch committed
3598
			if (e != JIM_OK) {
3599
				Jim_GetOpt_NvpUnknown(goi, nvp_target_event, 1);
3600
3601
3602
				return e;
			}

zwelch's avatar
zwelch committed
3603
3604
			if (goi->isconfigure) {
				if (goi->argc != 1) {
3605
					Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name? ?EVENT-BODY?");
3606
					return JIM_ERR;
3607
				}
3608
			} else {
zwelch's avatar
zwelch committed
3609
				if (goi->argc != 0) {
3610
3611
3612
3613
3614
					Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name?");
					return JIM_ERR;
				}
			}

3615
			{
3616
				struct target_event_action *teap;
3617

3618
3619
				teap = target->event_action;
				/* replace existing? */
zwelch's avatar
zwelch committed
3620
3621
				while (teap) {
					if (teap->event == (enum target_event)n->value) {
3622
3623
3624
3625
						break;
					}
					teap = teap->next;
				}
3626

zwelch's avatar
zwelch committed
3627
				if (goi->isconfigure) {
3628
					bool replace = true;
zwelch's avatar
zwelch committed
3629
					if (teap == NULL) {
3630
						/* create new */
3631
						teap = calloc(1, sizeof(*teap));
3632
						replace = false;
3633
3634
					}
					teap->event = n->value;
3635
					Jim_GetOpt_Obj(goi, &o);
zwelch's avatar
zwelch committed
3636
					if (teap->body) {
3637
						Jim_DecrRefCount(interp, teap->body);
3638
					}
3639
					teap->body  = Jim_DuplicateObj(goi->interp, o);
3640
					/*
3641
					 * FIXME:
3642
3643
3644
3645
3646
3647
3648
3649
					 *     Tcl/TK - "tk events" have a nice feature.
					 *     See the "BIND" command.
					 *    We should support that here.
					 *     You can specify %X and %Y in the event code.
					 *     The idea is: %T - target name.
					 *     The idea is: %N - target number
					 *     The idea is: %E - event name.
					 */
3650
					Jim_IncrRefCount(teap->body);
3651

3652
3653
3654
3655
3656
3657
					if (!replace)
					{
						/* add to head of event list */
						teap->next = target->event_action;
						target->event_action = teap;
					}
3658
3659
3660
					Jim_SetEmptyResult(goi->interp);
				} else {
					/* get */
zwelch's avatar
zwelch committed
3661
					if (teap == NULL) {
3662
						Jim_SetEmptyResult(goi->interp);
3663
					} else {
3664
						Jim_SetResult(goi->interp, Jim_DuplicateObj(goi->interp, teap->body));
3665
3666
3667
3668
3669
3670
3671
					}
				}
			}
			/* loop for more */
			break;

		case TCFG_WORK_AREA_VIRT:
zwelch's avatar
zwelch committed
3672
			if (goi->isconfigure) {
3673
				target_free_all_working_areas(target);
3674
				e = Jim_GetOpt_Wide(goi, &w);
zwelch's avatar
zwelch committed
3675
				if (e != JIM_OK) {
3676
3677
3678
					return e;
				}
				target->working_area_virt = w;
3679
				target->working_area_virt_spec = true;
3680
			} else {
zwelch's avatar
zwelch committed
3681
				if (goi->argc != 0) {
3682
3683
					goto no_params;
				}
3684
			}
3685
			Jim_SetResult(interp, Jim_NewIntObj(goi->interp, target->working_area_virt));
3686
3687
			/* loop for more */
			break;
3688

3689
		case TCFG_WORK_AREA_PHYS:
zwelch's avatar
zwelch committed
3690
			if (goi->isconfigure) {
3691
				target_free_all_working_areas(target);
3692
				e = Jim_GetOpt_Wide(goi, &w);
zwelch's avatar
zwelch committed
3693
				if (e != JIM_OK) {
3694
3695
3696
					return e;
				}
				target->working_area_phys = w;
3697
				target->working_area_phys_spec = true;
3698
			} else {
zwelch's avatar
zwelch committed
3699
				if (goi->argc != 0) {
3700
3701
					goto no_params;
				}
3702
			}
3703
			Jim_SetResult(interp, Jim_NewIntObj(goi->interp, target->working_area_phys));
3704
3705
3706
3707
			/* loop for more */
			break;

		case TCFG_WORK_AREA_SIZE:
zwelch's avatar
zwelch committed
3708
			if (goi->isconfigure) {
3709
				target_free_all_working_areas(target);
3710
				e = Jim_GetOpt_Wide(goi, &w);
zwelch's avatar
zwelch committed
3711
				if (e != JIM_OK) {
3712
3713
3714
3715
					return e;
				}
				target->working_area_size = w;
			} else {
zwelch's avatar
zwelch committed
3716
				if (goi->argc != 0) {
3717
3718
					goto no_params;
				}
3719
			}
3720
			Jim_SetResult(interp, Jim_NewIntObj(goi->interp, target->working_area_size));
3721
3722
3723
3724
			/* loop for more */
			break;

		case TCFG_WORK_AREA_BACKUP:
zwelch's avatar
zwelch committed
3725
			if (goi->isconfigure) {
3726
				target_free_all_working_areas(target);
3727
				e = Jim_GetOpt_Wide(goi, &w);
zwelch's avatar
zwelch committed
3728
				if (e != JIM_OK) {
3729
3730
3731
3732
3733
					return e;
				}
				/* make this exactly 1 or 0 */
				target->backup_working_area = (!!w);
			} else {
zwelch's avatar
zwelch committed
3734
				if (goi->argc != 0) {
3735
3736
					goto no_params;
				}
3737
			}
3738
			Jim_SetResult(interp, Jim_NewIntObj(goi->interp, target->backup_working_area));
3739
3740
3741
3742
			/* loop for more e*/
			break;

		case TCFG_ENDIAN:
zwelch's avatar
zwelch committed
3743
			if (goi->isconfigure) {
3744
				e = Jim_GetOpt_Nvp(goi, nvp_target_endian, &n);
zwelch's avatar
zwelch committed
3745
				if (e != JIM_OK) {
3746
					Jim_GetOpt_NvpUnknown(goi, nvp_target_endian, 1);
3747
3748
3749
3750
					return e;
				}
				target->endianness = n->value;
			} else {
zwelch's avatar
zwelch committed
3751
				if (goi->argc != 0) {
3752
3753
3754
					goto no_params;
				}
			}
3755
			n = Jim_Nvp_value2name_simple(nvp_target_endian, target->endianness);
zwelch's avatar
zwelch committed
3756
			if (n->name == NULL) {
3757
				target->endianness = TARGET_LITTLE_ENDIAN;
3758
				n = Jim_Nvp_value2name_simple(nvp_target_endian, target->endianness);
3759
			}
3760
			Jim_SetResultString(goi->interp, n->name, -1);
3761
3762
3763
3764
			/* loop for more */
			break;

		case TCFG_VARIANT:
zwelch's avatar
zwelch committed
3765
3766
			if (goi->isconfigure) {
				if (goi->argc < 1) {
3767
					Jim_SetResult_sprintf(goi->interp,
3768
										   "%s ?STRING?",
3769
										   n->name);
3770
3771
					return JIM_ERR;
				}
zwelch's avatar
zwelch committed
3772
				if (target->variant) {
3773
3774
					free((void *)(target->variant));
				}
3775
				e = Jim_GetOpt_String(goi, &cp, NULL);
3776
3777
				target->variant = strdup(cp);
			} else {
zwelch's avatar
zwelch committed
3778
				if (goi->argc != 0) {
3779
3780
					goto no_params;
				}
3781
			}
3782
			Jim_SetResultString(goi->interp, target->variant,-1);
3783
3784
3785
			/* loop for more */
			break;
		case TCFG_CHAIN_POSITION:
zwelch's avatar
zwelch committed
3786
			if (goi->isconfigure) {
3787
				Jim_Obj *o;
3788
				struct jtag_tap *tap;
3789
				target_free_all_working_areas(target);
3790
				e = Jim_GetOpt_Obj(goi, &o);
zwelch's avatar
zwelch committed
3791
				if (e != JIM_OK) {
3792
3793
					return e;
				}
3794
				tap = jtag_tap_by_jim_obj(goi->interp, o);
zwelch's avatar
zwelch committed
3795
				if (tap == NULL) {
3796
					return JIM_ERR;
3797
				}
3798
				/* make this exactly 1 or 0 */
3799
				target->tap = tap;
3800
			} else {
zwelch's avatar
zwelch committed
3801
				if (goi->argc != 0) {
3802
3803
					goto no_params;
				}
3804
			}
3805
			Jim_SetResultString(interp, target->tap->dotted_name, -1);
3806
3807
3808
			/* loop for more e*/
			break;
		}
3809
	} /* while (goi->argc) */
3810
3811


3812
		/* done - we return */
3813
3814
3815
3816
	return JIM_OK;
}

/** this is the 'tcl' handler for the target specific command */
3817
static int tcl_target_func(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3818
3819
3820
3821
{
	Jim_GetOptInfo goi;
	jim_wide a,b,c;
	int x,y,z;
3822
	uint8_t  target_buf[32];
3823
3824
3825
3826
3827
3828
3829
3830
	Jim_Nvp *n;
	target_t *target;
	struct command_context_s *cmd_ctx;
	int e;

	enum {
		TS_CMD_CONFIGURE,
		TS_CMD_CGET,
3831

3832
3833
3834
3835
		TS_CMD_MWW, TS_CMD_MWH, TS_CMD_MWB,
		TS_CMD_MDW, TS_CMD_MDH, TS_CMD_MDB,
		TS_CMD_MRW, TS_CMD_MRH, TS_CMD_MRB,
		TS_CMD_MEM2ARRAY, TS_CMD_ARRAY2MEM,
3836
		TS_CMD_EXAMINE,
3837
3838
3839
3840
3841
3842
		TS_CMD_POLL,
		TS_CMD_RESET,
		TS_CMD_HALT,
		TS_CMD_WAITSTATE,
		TS_CMD_EVENTLIST,
		TS_CMD_CURSTATE,
3843
		TS_CMD_INVOKE_EVENT,
3844
	};
3845

3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
	static const Jim_Nvp target_options[] = {
		{ .name = "configure", .value = TS_CMD_CONFIGURE },
		{ .name = "cget", .value = TS_CMD_CGET },
		{ .name = "mww", .value = TS_CMD_MWW },
		{ .name = "mwh", .value = TS_CMD_MWH },
		{ .name = "mwb", .value = TS_CMD_MWB },
		{ .name = "mdw", .value = TS_CMD_MDW },
		{ .name = "mdh", .value = TS_CMD_MDH },
		{ .name = "mdb", .value = TS_CMD_MDB },
		{ .name = "mem2array", .value = TS_CMD_MEM2ARRAY },
		{ .name = "array2mem", .value = TS_CMD_ARRAY2MEM },
		{ .name = "eventlist", .value = TS_CMD_EVENTLIST },
		{ .name = "curstate",  .value = TS_CMD_CURSTATE },

		{ .name = "arp_examine", .value = TS_CMD_EXAMINE },
		{ .name = "arp_poll", .value = TS_CMD_POLL },
		{ .name = "arp_reset", .value = TS_CMD_RESET },
		{ .name = "arp_halt", .value = TS_CMD_HALT },
		{ .name = "arp_waitstate", .value = TS_CMD_WAITSTATE },
3865
		{ .name = "invoke-event", .value = TS_CMD_INVOKE_EVENT },
3866
3867
3868
3869
3870

		{ .name = NULL, .value = -1 },
	};

	/* go past the "command" */
3871
	Jim_GetOpt_Setup(&goi, interp, argc-1, argv + 1);
3872

3873
	target = Jim_CmdPrivData(goi.interp);
3874
3875
3876
	cmd_ctx = Jim_GetAssocData(goi.interp, "context");

	/* commands here are in an NVP table */
3877
	e = Jim_GetOpt_Nvp(&goi, target_options, &n);
zwelch's avatar
zwelch committed
3878
	if (e != JIM_OK) {
3879
		Jim_GetOpt_NvpUnknown(&goi, target_options, 0);
3880
3881
		return e;
	}
3882
	/* Assume blank result */
3883
	Jim_SetEmptyResult(goi.interp);
3884

zwelch's avatar
zwelch committed
3885
	switch (n->value) {
3886
	case TS_CMD_CONFIGURE:
zwelch's avatar
zwelch committed
3887
		if (goi.argc < 2) {
3888
			Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, "missing: -option VALUE ...");
3889
3890
3891
			return JIM_ERR;
		}
		goi.isconfigure = 1;
3892
		return target_configure(&goi, target);
3893
3894
	case TS_CMD_CGET:
		// some things take params
zwelch's avatar
zwelch committed
3895
		if (goi.argc < 1) {
3896
			Jim_WrongNumArgs(goi.interp, 0, goi.argv, "missing: ?-option?");
3897
3898
3899
			return JIM_ERR;
		}
		goi.isconfigure = 0;
3900
		return target_configure(&goi, target);
3901
3902
3903
3904
3905
3906
3907
3908
3909
		break;
	case TS_CMD_MWW:
	case TS_CMD_MWH:
	case TS_CMD_MWB:
		/* argv[0] = cmd
		 * argv[1] = address
		 * argv[2] = data
		 * argv[3] = optional count.
		 */
3910

zwelch's avatar
zwelch committed
3911
		if ((goi.argc == 2) || (goi.argc == 3)) {
3912
3913
3914
			/* all is well */
		} else {
		mwx_error:
3915
			Jim_SetResult_sprintf(goi.interp, "expected: %s ADDR DATA [COUNT]", n->name);
3916
3917
			return JIM_ERR;
		}
3918

3919
		e = Jim_GetOpt_Wide(&goi, &a);
zwelch's avatar
zwelch committed
3920
		if (e != JIM_OK) {
3921
3922
3923
			goto mwx_error;
		}

3924
		e = Jim_GetOpt_Wide(&goi, &b);
zwelch's avatar
zwelch committed
3925
		if (e != JIM_OK) {
3926
3927
			goto mwx_error;
		}
zwelch's avatar
zwelch committed
3928
		if (goi.argc == 3) {
3929
			e = Jim_GetOpt_Wide(&goi, &c);
zwelch's avatar
zwelch committed
3930
			if (e != JIM_OK) {
3931
3932
3933
3934
3935
				goto mwx_error;
			}
		} else {
			c = 1;
		}
3936

zwelch's avatar
zwelch committed
3937
		switch (n->value) {
3938
		case TS_CMD_MWW:
3939
			target_buffer_set_u32(target, target_buf, b);
3940
3941
3942
			b = 4;
			break;
		case TS_CMD_MWH:
3943
			target_buffer_set_u16(target, target_buf, b);
3944
3945
3946
			b = 2;
			break;
		case TS_CMD_MWB:
3947
			target_buffer_set_u8(target, target_buf, b);
3948
3949
3950
			b = 1;
			break;
		}
zwelch's avatar
zwelch committed
3951
		for (x = 0 ; x < c ; x++) {
3952
			e = target_write_memory(target, a, b, 1, target_buf);
zwelch's avatar
zwelch committed
3953
			if (e != ERROR_OK) {
3954
				Jim_SetResult_sprintf(interp