target.c 123 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
{
3027
	struct target *target = get_current_target(CMD_CTX);
3028
	struct timeval timeout, now;
oharboe's avatar
oharboe committed
3029

3030
	gettimeofday(&timeout, NULL);
3031
	if (CMD_ARGC != 2)
3032
3033
3034
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
3035
	unsigned offset;
3036
	COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], offset);
3037
3038

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

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

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
		} else
		{
3072
			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
			writeGmon(samples, numSamples, CMD_ARGV[1]);
3100
			command_print(CMD_CTX, "Wrote %s", CMD_ARGV[1]);
3101
3102
3103
3104
			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
	int  n, e, retval;
3168
	uint32_t i;
3169
3170
3171

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

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

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

3230
3231
3232
3233
3234
3235
3236
	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));
3237
3238
		sprintf(buf, "mem2array address: 0x%08" PRIx32 " is not aligned for %" PRId32 " byte reads",
				addr,
duane's avatar
duane committed
3239
				width);
3240
3241
3242
3243
3244
3245
3246
3247
		Jim_AppendStrings(interp, Jim_GetResult(interp), buf , NULL);
		return JIM_ERR;
	}

	/* Transfer loop */

	/* index counter */
	n = 0;
Øyvind Harboe's avatar
Øyvind Harboe committed
3248
3249
3250
3251
3252
3253

	size_t buffersize = 4096;
	uint8_t *buffer = malloc(buffersize);
	if (buffer == NULL)
		return JIM_ERR;

3254
3255
3256
3257
	/* assume ok */
	e = JIM_OK;
	while (len) {
		/* Slurp... in buffer size chunks */
oharboe's avatar
oharboe committed
3258

3259
		count = len; /* in objects.. */
Øyvind Harboe's avatar
Øyvind Harboe committed
3260
3261
		if (count > (buffersize/width)) {
			count = (buffersize/width);
3262
		}
oharboe's avatar
oharboe committed
3263

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

Øyvind Harboe's avatar
Øyvind Harboe committed
3295
3296
	free(buffer);

3297
3298
3299
3300
3301
	Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));

	return JIM_OK;
}

3302
static int get_int_array_element(Jim_Interp * interp, const char *varname, int idx, uint32_t *val)
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
3328
3329
3330
3331
3332
3333
3334
{
	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)
{
3335
	struct command_context *context;
Zachary T Welch's avatar
Zachary T Welch committed
3336
	struct target *target;
3337

3338
	context = Jim_GetAssocData(interp, "context");
zwelch's avatar
zwelch committed
3339
	if (context == NULL) {
3340
3341
3342
3343
		LOG_ERROR("array2mem: no command context");
		return JIM_ERR;
	}
	target = get_current_target(context);
zwelch's avatar
zwelch committed
3344
	if (target == NULL) {
3345
3346
3347
		LOG_ERROR("array2mem: no current target");
		return JIM_ERR;
	}
3348

3349
	return target_array2mem(interp,target, argc-1, argv + 1);
3350
}
Zachary T Welch's avatar
Zachary T Welch committed
3351
static int target_array2mem(Jim_Interp *interp, struct target *target, int argc, Jim_Obj *const *argv)
3352
{
3353
	long l;
3354
	uint32_t width;
3355
	int len;
3356
3357
3358
	uint32_t addr;
	uint32_t count;
	uint32_t v;
3359
	const char *varname;
3360
	int  n, e, retval;
3361
	uint32_t i;
3362
3363
3364

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

3375
	e = Jim_GetLong(interp, argv[1], &l);
3376
3377
3378
3379
	width = l;
	if (e != JIM_OK) {
		return e;
	}
oharboe's avatar
oharboe committed
3380

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

3423
3424
3425
3426
3427
3428
3429
	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));
3430
3431
		sprintf(buf, "array2mem address: 0x%08x is not aligned for %d byte reads",
				(unsigned int)addr,
duane's avatar
duane committed
3432
				(int)width);
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
		Jim_AppendStrings(interp, Jim_GetResult(interp), buf , NULL);
		return JIM_ERR;
	}

	/* Transfer loop */

	/* index counter */
	n = 0;
	/* assume ok */
	e = JIM_OK;
Øyvind Harboe's avatar
Øyvind Harboe committed
3443
3444
3445
3446
3447
3448

	size_t buffersize = 4096;
	uint8_t *buffer = malloc(buffersize);
	if (buffer == NULL)
		return JIM_ERR;

3449
3450
	while (len) {
		/* Slurp... in buffer size chunks */
oharboe's avatar
oharboe committed
3451

3452
		count = len; /* in objects.. */
Øyvind Harboe's avatar
Øyvind Harboe committed
3453
3454
		if (count > (buffersize/width)) {
			count = (buffersize/width);
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
		}

		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
3474
		retval = target_write_memory(target, addr, width, count, buffer);
3475
3476
		if (retval != ERROR_OK) {
			/* BOO !*/
3477
3478
3479
			LOG_ERROR("array2mem: Write @ 0x%08x, w=%d, cnt=%d, failed",
					  (unsigned int)addr,
					  (int)width,
duane's avatar
duane committed
3480
					  (int)count);
3481
			Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
3482
			Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: cannot read memory", NULL);
3483
3484
3485
3486
			e = JIM_ERR;
			len = 0;
		}
	}
oharboe's avatar
oharboe committed
3487

Øyvind Harboe's avatar
Øyvind Harboe committed
3488
3489
	free(buffer);

3490
3491
3492
3493
	Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));

	return JIM_OK;
}
3494

3495
void target_all_handle_event(enum target_event e)
3496
{
Zachary T Welch's avatar
Zachary T Welch committed
3497
	struct target *target;
3498

3499
	LOG_DEBUG("**all*targets: event: %d, %s",
duane's avatar
duane committed
3500
			   (int)e,
3501
			   Jim_Nvp_value2name_simple(nvp_target_event, e)->name);
3502
3503

	target = all_targets;
zwelch's avatar
zwelch committed
3504
	while (target) {
3505
		target_handle_event(target, e);
3506
3507
3508
3509
		target = target->next;
	}
}

3510
3511
3512
3513

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

dbrownell's avatar
dbrownell committed
3518
	for (teap = target->event_action; teap != NULL; teap = teap->next) {
zwelch's avatar
zwelch committed
3519
		if (teap->event == e) {
3520
			LOG_DEBUG("target: (%d) %s (%s) event: %d (%s) action: %s",
3521
					   target->target_number,
3522
					   target_name(target),
3523
					   target_type_name(target),
3524
					   e,
3525
3526
					   Jim_Nvp_value2name_simple(nvp_target_event, e)->name,
					   Jim_GetString(teap->body, NULL));
3527
			if (Jim_EvalObj(teap->interp, teap->body) != JIM_OK)
3528
			{
3529
				Jim_PrintErrorMessage(teap->interp);
3530
			}
3531
3532
3533
3534
		}
	}
}

3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
/**
 * Returns true only if the target has a handler for the specified event.
 */
bool target_has_event_action(struct target *target, enum target_event event)
{
	struct target_event_action *teap;

	for (teap = target->event_action; teap != NULL; teap = teap->next) {
		if (teap->event == event)
			return true;
	}
	return false;
}

3549
3550
enum target_cfg_param {
	TCFG_TYPE,
3551
	TCFG_EVENT,
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
	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 },
3571

3572
3573
	{ .name = NULL, .value = -1 }
};
3574

Zachary T Welch's avatar
Zachary T Welch committed
3575
static int target_configure(Jim_GetOptInfo *goi, struct target *target)
3576
3577
3578
3579
3580
3581
3582
3583
{
	Jim_Nvp *n;
	Jim_Obj *o;
	jim_wide w;
	char *cp;
	int e;

	/* parse config or cget options ... */
zwelch's avatar
zwelch committed
3584
	while (goi->argc > 0) {
3585
3586
		Jim_SetEmptyResult(goi->interp);
		/* Jim_GetOpt_Debug(goi); */
3587

zwelch's avatar
zwelch committed
3588
		if (target->type->target_jim_configure) {
3589
3590
			/* target defines a configure function */
			/* target gets first dibs on parameters */
3591
			e = (*(target->type->target_jim_configure))(target, goi);
zwelch's avatar
zwelch committed
3592
			if (e == JIM_OK) {
3593
3594
3595
				/* more? */
				continue;
			}
zwelch's avatar
zwelch committed
3596
			if (e == JIM_ERR) {
3597
3598
3599
3600
3601
				/* An error */
				return e;
			}
			/* otherwise we 'continue' below */
		}
3602
		e = Jim_GetOpt_Nvp(goi, nvp_config_opts, &n);
zwelch's avatar
zwelch committed
3603
		if (e != JIM_OK) {
3604
			Jim_GetOpt_NvpUnknown(goi, nvp_config_opts, 0);
3605
3606
			return e;
		}
zwelch's avatar
zwelch committed
3607
		switch (n->value) {
3608
3609
		case TCFG_TYPE:
			/* not setable */
zwelch's avatar
zwelch committed
3610
			if (goi->isconfigure) {
3611
3612
				Jim_SetResult_sprintf(goi->interp,
						"not settable: %s", n->name);
3613
3614
3615
				return JIM_ERR;
			} else {
			no_params:
zwelch's avatar
zwelch committed
3616
				if (goi->argc != 0) {
3617
3618
3619
					Jim_WrongNumArgs(goi->interp,
							goi->argc, goi->argv,
							"NO PARAMS");
3620
3621
3622
					return JIM_ERR;
				}
			}
3623
3624
			Jim_SetResultString(goi->interp,
					target_type_name(target), -1);
3625
3626
3627
			/* loop for more */
			break;
		case TCFG_EVENT:
zwelch's avatar
zwelch committed
3628
			if (goi->argc == 0) {
3629
				Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name? ...");
3630
3631
3632
				return JIM_ERR;
			}

3633
			e = Jim_GetOpt_Nvp(goi, nvp_target_event, &n);
zwelch's avatar
zwelch committed
3634
			if (e != JIM_OK) {
3635
				Jim_GetOpt_NvpUnknown(goi, nvp_target_event, 1);
3636
3637
3638
				return e;
			}

zwelch's avatar
zwelch committed
3639
3640
			if (goi->isconfigure) {
				if (goi->argc != 1) {
3641
					Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name? ?EVENT-BODY?");
3642
					return JIM_ERR;
3643
				}
3644
			} else {
zwelch's avatar
zwelch committed
3645
				if (goi->argc != 0) {
3646
3647
3648
3649
3650
					Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name?");
					return JIM_ERR;
				}
			}

3651
			{
3652
				struct target_event_action *teap;
3653

3654
3655
				teap = target->event_action;
				/* replace existing? */
zwelch's avatar
zwelch committed
3656
3657
				while (teap) {
					if (teap->event == (enum target_event)n->value) {
3658
3659
3660
3661
						break;
					}
					teap = teap->next;
				}
3662

zwelch's avatar
zwelch committed
3663
				if (goi->isconfigure) {
3664
					bool replace = true;
zwelch's avatar
zwelch committed
3665
					if (teap == NULL) {
3666
						/* create new */
3667
						teap = calloc(1, sizeof(*teap));
3668
						replace = false;
3669
3670
					}
					teap->event = n->value;
3671
					teap->interp = goi->interp;
3672
					Jim_GetOpt_Obj(goi, &o);
zwelch's avatar
zwelch committed
3673
					if (teap->body) {
3674
						Jim_DecrRefCount(teap->interp, teap->body);
3675
					}
3676
					teap->body  = Jim_DuplicateObj(goi->interp, o);
3677
					/*
3678
					 * FIXME:
3679
3680
3681
3682
3683
3684
3685
3686
					 *     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.
					 */
3687
					Jim_IncrRefCount(teap->body);
3688

3689
3690
3691
3692
3693
3694
					if (!replace)
					{
						/* add to head of event list */
						teap->next = target->event_action;
						target->event_action = teap;
					}
3695
3696
3697
					Jim_SetEmptyResult(goi->interp);
				} else {
					/* get */
zwelch's avatar
zwelch committed
3698
					if (teap == NULL) {
3699
						Jim_SetEmptyResult(goi->interp);
3700
					} else {
3701
						Jim_SetResult(goi->interp, Jim_DuplicateObj(goi->interp, teap->body));
3702
3703
3704
3705
3706
3707
3708
					}
				}
			}
			/* loop for more */
			break;

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

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

		case TCFG_WORK_AREA_SIZE:
zwelch's avatar
zwelch committed
3745
			if (goi->isconfigure) {
3746
				target_free_all_working_areas(target);
3747
				e = Jim_GetOpt_Wide(goi, &w);
zwelch's avatar
zwelch committed
3748
				if (e != JIM_OK) {
3749
3750
3751
3752
					return e;
				}
				target->working_area_size = w;
			} else {
zwelch's avatar
zwelch committed
3753
				if (goi->argc != 0) {
3754
3755
					goto no_params;
				}
3756
			}
3757
			Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->working_area_size));
3758
3759
3760
3761
			/* loop for more */
			break;

		case TCFG_WORK_AREA_BACKUP:
zwelch's avatar
zwelch committed
3762
			if (goi->isconfigure) {
3763
				target_free_all_working_areas(target);
3764
				e = Jim_GetOpt_Wide(goi, &w);
zwelch's avatar
zwelch committed
3765
				if (e != JIM_OK) {
3766
3767
3768
3769
3770
					return e;
				}
				/* make this exactly 1 or 0 */
				target->backup_working_area = (!!w);
			} else {
zwelch's avatar
zwelch committed
3771
				if (goi->argc != 0) {
3772
3773
					goto no_params;
				}
3774
			}
3775
			Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->backup_working_area));
3776
3777
3778
3779
			/* loop for more e*/
			break;

		case TCFG_ENDIAN:
zwelch's avatar
zwelch committed
3780
			if (goi->isconfigure) {
3781
				e = Jim_GetOpt_Nvp(goi, nvp_target_endian, &n);
zwelch's avatar
zwelch committed
3782
				if (e != JIM_OK) {
3783
					Jim_GetOpt_NvpUnknown(goi, nvp_target_endian, 1);
3784
3785
3786
3787
					return e;
				}
				target->endianness = n->value;
			} else {
zwelch's avatar
zwelch committed
3788
				if (goi->argc != 0) {
3789
3790
3791
					goto no_params;
				}
			}
3792
			n = Jim_Nvp_value2name_simple(nvp_target_endian, target->endianness);
zwelch's avatar
zwelch committed
3793
			if (n->name == NULL) {
3794
				target->endianness = TARGET_LITTLE_ENDIAN;
3795
				n = Jim_Nvp_value2name_simple(nvp_target_endian, target->endianness);
3796
			}
3797
			Jim_SetResultString(goi->interp, n->name, -1);
3798
3799
3800
3801
			/* loop for more */
			break;

		case TCFG_VARIANT:
zwelch's avatar
zwelch committed
3802
3803
			if (goi->isconfigure) {
				if (goi->argc < 1) {
3804
					Jim_SetResult_sprintf(goi->interp,
3805
										   "%s ?STRING?",
3806
										   n->name);
3807
3808
					return JIM_ERR;
				}
zwelch's avatar
zwelch committed
3809
				if (target->variant) {
3810
3811
					free((void *)(target->variant));
				}
3812
				e = Jim_GetOpt_String(goi, &cp, NULL);
3813
3814
				target->variant = strdup(cp);
			} else {
zwelch's avatar
zwelch committed
3815
				if (goi->argc != 0) {
3816
3817
					goto no_params;
				}
3818
			}
3819
			Jim_SetResultString(goi->interp, target->variant,-1);
3820
3821
3822
			/* loop for more */
			break;
		case TCFG_CHAIN_POSITION:
zwelch's avatar
zwelch committed
3823
			if (goi->isconfigure) {
3824
				Jim_Obj *o;
3825
				struct jtag_tap *tap;
3826
				target_free_all_working_areas(target);
3827
				e = Jim_GetOpt_Obj(goi, &o);
zwelch's avatar
zwelch committed
3828
				if (e != JIM_OK) {
3829
3830
					return e;
				}
3831
				tap = jtag_tap_by_jim_obj(goi->interp, o);
zwelch's avatar
zwelch committed
3832
				if (tap == NULL) {
3833
					return JIM_ERR;
3834
				}
3835
				/* make this exactly 1 or 0 */
3836
				target->tap = tap;
3837
			} else {
zwelch's avatar
zwelch committed
3838
				if (goi->argc != 0) {
3839
3840
					goto no_params;
				}
3841
			}
3842
			Jim_SetResultString(goi->interp, target->tap->dotted_name, -1);
3843
3844
3845
			/* loop for more e*/
			break;
		}
3846
	} /* while (goi->argc) */
3847
3848


3849
		/* done - we return */
3850
3851
3852
	return JIM_OK;
}

3853
static int jim_target_configure(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3854
3855
{
	Jim_GetOptInfo goi;
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
	Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1);
	goi.isconfigure = strcmp(Jim_GetString(argv[0], NULL), "configure") == 0;
	int need_args = 1 + goi.isconfigure;
	if (goi.argc < need_args)
	{
		Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv,
			goi.isconfigure
				? "missing: -option VALUE ..."
				: "missing: -option ...");
		return JIM_ERR;
	}
	struct target *target = Jim_CmdPrivData(goi.interp);
	return target_configure(&goi, target);
}
3870

3871
3872
3873
static int jim_target_mw(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
	const char *cmd_name = Jim_GetString(argv[0], NULL);
3874

3875
3876
	Jim_GetOptInfo goi;
	Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1);
3877

3878
3879
3880
3881
3882
3883
	if (goi.argc != 2 && goi.argc != 3)
	{
		Jim_SetResult_sprintf(goi.interp,
				"usage: %s <address> <data> [<count>]", cmd_name);
		return JIM_ERR;
	}
3884

3885
3886
3887
3888
	jim_wide a;
	int e = Jim_GetOpt_Wide(&goi, &a);
	if (e != JIM_OK)
		return e;
3889

3890
3891
3892
	jim_wide b;
	e = Jim_GetOpt_Wide(&goi, &b);
	if (e != JIM_OK)
3893
		return e;
3894
3895
3896
3897
3898
3899
3900

	jim_wide c = 1;
	if (goi.argc == 3)
	{
		e = Jim_GetOpt_Wide(&goi, &c);
		if (e != JIM_OK)
			return e;
3901
3902
	}

3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
	struct target *target = Jim_CmdPrivData(goi.interp);
	uint8_t  target_buf[32];
	if (strcasecmp(cmd_name, "mww") == 0) {
		target_buffer_set_u32(target, target_buf, b);
		b = 4;
	}
	else if (strcasecmp(cmd_name, "mwh") == 0) {
		target_buffer_set_u16(target, target_buf, b);
		b = 2;
	}
	else if (strcasecmp(cmd_name, "mwb") == 0) {
		target_buffer_set_u8(target, target_buf, b);
		b = 1;
	} else {
		LOG_ERROR("command '%s' unknown: ", cmd_name);
		return JIM_ERR;
	}
3920

3921
3922
3923
3924
3925
3926
3927
	for (jim_wide x = 0; x < c; x++)
	{
		e = target_write_memory(target, a, b, 1, target_buf);
		if (e != ERROR_OK)
		{
			Jim_SetResult_sprintf(interp,
					"Error writing @ 0x%08x: %d\n", (int)(a), e);
3928
3929
			return JIM_ERR;
		}
3930
3931
3932
3933
3934
		/* b = width */
		a = a + b;
	}
	return JIM_OK;
}
3935

3936
3937
3938
static int jim_target_md(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
	const char *cmd_name = Jim_GetString(argv[0], NULL);
3939

3940
3941
	Jim_GetOptInfo goi;
	Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1);
3942

3943
3944
3945
3946
3947
3948
	if ((goi.argc == 2) || (goi.argc == 3))
	{
		Jim_SetResult_sprintf(goi.interp,
				"usage: %s <address> [<count>]", cmd_name);
		return JIM_ERR;
	}
3949

3950
3951
3952
3953
3954
3955
3956
3957
	jim_wide a;
	int e = Jim_GetOpt_Wide(&goi, &a);
	if (e != JIM_OK) {
		return JIM_ERR;
	}
	jim_wide c;
	if (goi.argc) {
		e = Jim_GetOpt_Wide(&goi, &c);
zwelch's avatar
zwelch committed
3958
		if (e != JIM_OK) {
3959
3960
			return JIM_ERR;
		}