target.c 118 KB
Newer Older
3001
	{
zwelch's avatar
zwelch committed
3002
		for (i = 0; i < length;i++)
3003
3004
		{
			int val;
zwelch's avatar
zwelch committed
3005
			val = buckets[i];
zwelch's avatar
zwelch committed
3006
			if (val > 65535)
3007
			{
zwelch's avatar
zwelch committed
3008
				val = 65535;
3009
3010
			}
			data[i*2]=val&0xff;
zwelch's avatar
zwelch committed
3011
			data[i*2 + 1]=(val >> 8)&0xff;
3012
3013
		}
		free(buckets);
3014
		writeData(f, data, length * 2);
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
		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 */
3025
COMMAND_HANDLER(handle_profile_command)
3026
{
Zachary T Welch's avatar
Zachary T Welch committed
3027
	struct target *target = get_current_target(cmd_ctx);
3028
	struct timeval timeout, now;
oharboe's avatar
oharboe committed
3029

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

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

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

zwelch's avatar
zwelch committed
3042
3043
	static const int maxSample = 10000;
	uint32_t *samples = malloc(sizeof(uint32_t)*maxSample);
zwelch's avatar
zwelch committed
3044
	if (samples == NULL)
3045
		return ERROR_OK;
oharboe's avatar
oharboe committed
3046

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

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

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

3106
3107
	return ERROR_OK;
}
3108

3109
static int new_int_array_element(Jim_Interp * interp, const char *varname, int idx, uint32_t val)
3110
3111
3112
3113
3114
3115
3116
3117
{
	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
3118

3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
	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)
{
3139
	struct command_context *context;
Zachary T Welch's avatar
Zachary T Welch committed
3140
	struct target *target;
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154

	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
3155
	return 	target_mem2array(interp, target, argc-1, argv + 1);
3156
3157
}

Zachary T Welch's avatar
Zachary T Welch committed
3158
static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, Jim_Obj *const *argv)
3159
{
3160
	long l;
3161
	uint32_t width;
3162
	int len;
3163
3164
3165
	uint32_t addr;
	uint32_t count;
	uint32_t v;
3166
	const char *varname;
3167
	uint8_t buffer[4096];
3168
	int  n, e, retval;
3169
	uint32_t i;
3170
3171
3172

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

3183
	e = Jim_GetLong(interp, argv[1], &l);
3184
3185
3186
3187
	width = l;
	if (e != JIM_OK) {
		return e;
	}
oharboe's avatar
oharboe committed
3188

3189
	e = Jim_GetLong(interp, argv[2], &l);
3190
3191
3192
3193
	addr = l;
	if (e != JIM_OK) {
		return e;
	}
3194
	e = Jim_GetLong(interp, argv[3], &l);
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
	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));
3211
			Jim_AppendStrings(interp, Jim_GetResult(interp), "Invalid width param, must be 8/16/32", NULL);
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
			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
3229
3230
	}

3231
3232
3233
3234
3235
3236
3237
	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));
3238
3239
		sprintf(buf, "mem2array address: 0x%08" PRIx32 " is not aligned for %" PRId32 " byte reads",
				addr,
duane's avatar
duane committed
3240
				width);
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
		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
3253

3254
3255
3256
3257
		count = len; /* in objects.. */
		if (count > (sizeof(buffer)/width)) {
			count = (sizeof(buffer)/width);
		}
oharboe's avatar
oharboe committed
3258

3259
		retval = target_read_memory(target, addr, width, count, buffer);
3260
3261
		if (retval != ERROR_OK) {
			/* BOO !*/
3262
3263
3264
			LOG_ERROR("mem2array: Read @ 0x%08x, w=%d, cnt=%d, failed",
					  (unsigned int)addr,
					  (int)width,
duane's avatar
duane committed
3265
					  (int)count);
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
			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
3289

3290
3291
3292
3293
3294
	Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));

	return JIM_OK;
}

3295
static int get_int_array_element(Jim_Interp * interp, const char *varname, int idx, uint32_t *val)
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
3325
3326
3327
{
	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)
{
3328
	struct command_context *context;
Zachary T Welch's avatar
Zachary T Welch committed
3329
	struct target *target;
3330

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

3342
	return target_array2mem(interp,target, argc-1, argv + 1);
3343
}
Zachary T Welch's avatar
Zachary T Welch committed
3344
static int target_array2mem(Jim_Interp *interp, struct target *target, int argc, Jim_Obj *const *argv)
3345
{
3346
	long l;
3347
	uint32_t width;
3348
	int len;
3349
3350
3351
	uint32_t addr;
	uint32_t count;
	uint32_t v;
3352
	const char *varname;
3353
	uint8_t buffer[4096];
3354
	int  n, e, retval;
3355
	uint32_t i;
3356
3357
3358

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

3369
	e = Jim_GetLong(interp, argv[1], &l);
3370
3371
3372
3373
	width = l;
	if (e != JIM_OK) {
		return e;
	}
oharboe's avatar
oharboe committed
3374

3375
	e = Jim_GetLong(interp, argv[2], &l);
3376
3377
3378
3379
	addr = l;
	if (e != JIM_OK) {
		return e;
	}
3380
	e = Jim_GetLong(interp, argv[3], &l);
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
	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));
3397
			Jim_AppendStrings(interp, Jim_GetResult(interp), "Invalid width param, must be 8/16/32", NULL);
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
			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
3415
3416
	}

3417
3418
3419
3420
3421
3422
3423
	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));
3424
3425
		sprintf(buf, "array2mem address: 0x%08x is not aligned for %d byte reads",
				(unsigned int)addr,
duane's avatar
duane committed
3426
				(int)width);
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
		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
3439

3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
		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
3462
		retval = target_write_memory(target, addr, width, count, buffer);
3463
3464
		if (retval != ERROR_OK) {
			/* BOO !*/
3465
3466
3467
			LOG_ERROR("array2mem: Write @ 0x%08x, w=%d, cnt=%d, failed",
					  (unsigned int)addr,
					  (int)width,
duane's avatar
duane committed
3468
					  (int)count);
3469
			Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
3470
			Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: cannot read memory", NULL);
3471
3472
3473
3474
			e = JIM_ERR;
			len = 0;
		}
	}
oharboe's avatar
oharboe committed
3475

3476
3477
3478
3479
	Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));

	return JIM_OK;
}
3480

3481
void target_all_handle_event(enum target_event e)
3482
{
Zachary T Welch's avatar
Zachary T Welch committed
3483
	struct target *target;
3484

3485
	LOG_DEBUG("**all*targets: event: %d, %s",
duane's avatar
duane committed
3486
			   (int)e,
3487
			   Jim_Nvp_value2name_simple(nvp_target_event, e)->name);
3488
3489

	target = all_targets;
zwelch's avatar
zwelch committed
3490
	while (target) {
3491
		target_handle_event(target, e);
3492
3493
3494
3495
		target = target->next;
	}
}

3496
3497
3498
3499

/* FIX? should we propagate errors here rather than printing them
 * and continuing?
 */
Zachary T Welch's avatar
Zachary T Welch committed
3500
void target_handle_event(struct target *target, enum target_event e)
3501
{
3502
	struct target_event_action *teap;
3503

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

enum target_cfg_param {
	TCFG_TYPE,
3523
	TCFG_EVENT,
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
	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 },
3543

3544
3545
	{ .name = NULL, .value = -1 }
};
3546

Zachary T Welch's avatar
Zachary T Welch committed
3547
static int target_configure(Jim_GetOptInfo *goi, struct target *target)
3548
3549
3550
3551
3552
3553
3554
3555
{
	Jim_Nvp *n;
	Jim_Obj *o;
	jim_wide w;
	char *cp;
	int e;

	/* parse config or cget options ... */
zwelch's avatar
zwelch committed
3556
	while (goi->argc > 0) {
3557
3558
		Jim_SetEmptyResult(goi->interp);
		/* Jim_GetOpt_Debug(goi); */
3559

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

3601
			e = Jim_GetOpt_Nvp(goi, nvp_target_event, &n);
zwelch's avatar
zwelch committed
3602
			if (e != JIM_OK) {
3603
				Jim_GetOpt_NvpUnknown(goi, nvp_target_event, 1);
3604
3605
3606
				return e;
			}

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

3619
			{
3620
				struct target_event_action *teap;
3621

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

zwelch's avatar
zwelch committed
3631
				if (goi->isconfigure) {
3632
					bool replace = true;
zwelch's avatar
zwelch committed
3633
					if (teap == NULL) {
3634
						/* create new */
3635
						teap = calloc(1, sizeof(*teap));
3636
						replace = false;
3637
3638
					}
					teap->event = n->value;
3639
					Jim_GetOpt_Obj(goi, &o);
zwelch's avatar
zwelch committed
3640
					if (teap->body) {
3641
						Jim_DecrRefCount(interp, teap->body);
3642
					}
3643
					teap->body  = Jim_DuplicateObj(goi->interp, o);
3644
					/*
3645
					 * FIXME:
3646
3647
3648
3649
3650
3651
3652
3653
					 *     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.
					 */
3654
					Jim_IncrRefCount(teap->body);
3655

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

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

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

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

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

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

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


3816
		/* done - we return */
3817
3818
3819
3820
	return JIM_OK;
}

/** this is the 'tcl' handler for the target specific command */
3821
static int tcl_target_func(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3822
3823
3824
3825
{
	Jim_GetOptInfo goi;
	jim_wide a,b,c;
	int x,y,z;
3826
	uint8_t  target_buf[32];
3827
	Jim_Nvp *n;
Zachary T Welch's avatar
Zachary T Welch committed
3828
	struct target *target;
3829
	struct command_context *cmd_ctx;
3830
3831
3832
3833
3834
	int e;

	enum {
		TS_CMD_CONFIGURE,
		TS_CMD_CGET,
3835

3836
3837
3838
3839
		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,
3840
		TS_CMD_EXAMINE,
3841
3842
3843
3844
3845
3846
		TS_CMD_POLL,
		TS_CMD_RESET,
		TS_CMD_HALT,
		TS_CMD_WAITSTATE,
		TS_CMD_EVENTLIST,
		TS_CMD_CURSTATE,
3847
		TS_CMD_INVOKE_EVENT,
3848
	};
3849

3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
	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 },
3869
		{ .name = "invoke-event", .value = TS_CMD_INVOKE_EVENT },
3870
3871
3872
3873
3874

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

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

3877
	target = Jim_CmdPrivData(goi.interp);
3878
3879
3880
	cmd_ctx = Jim_GetAssocData(goi.interp, "context");

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

zwelch's avatar
zwelch committed
3889
	switch (n->value) {
3890
	case TS_CMD_CONFIGURE:
zwelch's avatar
zwelch committed
3891
		if (goi.argc < 2) {
3892
			Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, "missing: -option VALUE ...");
3893
3894
3895
			return JIM_ERR;
		}
		goi.isconfigure = 1;
3896
		return target_configure(&goi, target);
3897
3898
	case TS_CMD_CGET:
		// some things take params
zwelch's avatar
zwelch committed
3899
		if (goi.argc < 1) {
3900
			Jim_WrongNumArgs(goi.interp, 0, goi.argv, "missing: ?-option?");
3901
3902
3903
			return JIM_ERR;
		}
		goi.isconfigure = 0;
3904
		return target_configure(&goi, target);
3905
3906
3907
3908
3909
3910
3911
3912
3913
		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.
		 */
3914

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

3923
		e = Jim_GetOpt_Wide(&goi, &a);
zwelch's avatar
zwelch committed
3924
		if (e != JIM_OK) {
3925
3926
3927
			goto mwx_error;
		}

3928
		e = Jim_GetOpt_Wide(&goi, &b);
zwelch's avatar
zwelch committed
3929
		if (e != JIM_OK) {
3930
3931
			goto mwx_error;
		}
zwelch's avatar
zwelch committed
3932
		if (goi.argc == 3) {
3933
			e = Jim_GetOpt_Wide(&goi, &c);
zwelch's avatar
zwelch committed
3934
			if (e != JIM_OK) {
3935
3936
3937
3938
3939