target.c 121 KB
Newer Older
3001

3002
3003
	return retval;
}
3004

3005
3006
static void writeData(FILE *f, const void *data, size_t len)
{
3007
	size_t written = fwrite(data, 1, len, f);
3008
	if (written != len)
3009
		LOG_ERROR("failed to write %zu bytes: %s", len, strerror(errno));
3010
3011
}

3012
3013
3014
static void writeLong(FILE *f, int l)
{
	int i;
zwelch's avatar
zwelch committed
3015
	for (i = 0; i < 4; i++)
3016
	{
zwelch's avatar
zwelch committed
3017
		char c = (l >> (i*8))&0xff;
3018
		writeData(f, &c, 1);
3019
	}
oharboe's avatar
oharboe committed
3020

3021
}
3022

3023
3024
static void writeString(FILE *f, char *s)
{
3025
	writeData(f, s, strlen(s));
3026
3027
}

3028
/* Dump a gmon.out histogram file. */
3029
static void writeGmon(uint32_t *samples, uint32_t sampleNum, char *filename)
3030
{
3031
	uint32_t i;
zwelch's avatar
zwelch committed
3032
	FILE *f = fopen(filename, "w");
zwelch's avatar
zwelch committed
3033
	if (f == NULL)
3034
		return;
3035
	writeString(f, "gmon");
3036
3037
3038
3039
	writeLong(f, 0x00000001); /* Version */
	writeLong(f, 0); /* padding */
	writeLong(f, 0); /* padding */
	writeLong(f, 0); /* padding */
oharboe's avatar
oharboe committed
3040

3041
	uint8_t zero = 0;  /* GMON_TAG_TIME_HIST */
3042
	writeData(f, &zero, 1);
3043

3044
	/* figure out bucket size */
zwelch's avatar
zwelch committed
3045
3046
	uint32_t min = samples[0];
	uint32_t max = samples[0];
zwelch's avatar
zwelch committed
3047
	for (i = 0; i < sampleNum; i++)
3048
	{
zwelch's avatar
zwelch committed
3049
		if (min > samples[i])
3050
		{
zwelch's avatar
zwelch committed
3051
			min = samples[i];
3052
		}
zwelch's avatar
zwelch committed
3053
		if (max < samples[i])
3054
		{
zwelch's avatar
zwelch committed
3055
			max = samples[i];
3056
3057
3058
		}
	}

zwelch's avatar
zwelch committed
3059
	int addressSpace = (max-min + 1);
oharboe's avatar
oharboe committed
3060

3061
3062
	static const uint32_t maxBuckets = 256 * 1024; /* maximum buckets. */
	uint32_t length = addressSpace;
3063
3064
	if (length > maxBuckets)
	{
zwelch's avatar
zwelch committed
3065
		length = maxBuckets;
3066
	}
zwelch's avatar
zwelch committed
3067
	int *buckets = malloc(sizeof(int)*length);
zwelch's avatar
zwelch committed
3068
	if (buckets == NULL)
3069
3070
3071
3072
3073
	{
		fclose(f);
		return;
	}
	memset(buckets, 0, sizeof(int)*length);
zwelch's avatar
zwelch committed
3074
	for (i = 0; i < sampleNum;i++)
3075
	{
zwelch's avatar
zwelch committed
3076
3077
3078
3079
3080
		uint32_t address = samples[i];
		long long a = address-min;
		long long b = length-1;
		long long c = addressSpace-1;
		int index = (a*b)/c; /* danger!!!! int32 overflows */
3081
3082
		buckets[index]++;
	}
oharboe's avatar
oharboe committed
3083

3084
3085
3086
3087
3088
	/* append binary memory gmon.out &profile_hist_hdr ((char*)&profile_hist_hdr + sizeof(struct gmon_hist_hdr)) */
	writeLong(f, min); 			/* low_pc */
	writeLong(f, max);			/* high_pc */
	writeLong(f, length);		/* # of samples */
	writeLong(f, 64000000); 	/* 64MHz */
3089
	writeString(f, "seconds");
zwelch's avatar
zwelch committed
3090
	for (i = 0; i < (15-strlen("seconds")); i++)
3091
		writeData(f, &zero, 1);
3092
	writeString(f, "s");
oharboe's avatar
oharboe committed
3093

3094
	/*append binary memory gmon.out profile_hist_data (profile_hist_data + profile_hist_hdr.hist_size) */
oharboe's avatar
oharboe committed
3095

zwelch's avatar
zwelch committed
3096
	char *data = malloc(2*length);
zwelch's avatar
zwelch committed
3097
	if (data != NULL)
3098
	{
zwelch's avatar
zwelch committed
3099
		for (i = 0; i < length;i++)
3100
3101
		{
			int val;
zwelch's avatar
zwelch committed
3102
			val = buckets[i];
zwelch's avatar
zwelch committed
3103
			if (val > 65535)
3104
			{
zwelch's avatar
zwelch committed
3105
				val = 65535;
3106
3107
			}
			data[i*2]=val&0xff;
zwelch's avatar
zwelch committed
3108
			data[i*2 + 1]=(val >> 8)&0xff;
3109
3110
		}
		free(buckets);
3111
		writeData(f, data, length * 2);
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
		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 */
3122
static int handle_profile_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
3123
3124
3125
{
	target_t *target = get_current_target(cmd_ctx);
	struct timeval timeout, now;
oharboe's avatar
oharboe committed
3126

3127
	gettimeofday(&timeout, NULL);
zwelch's avatar
zwelch committed
3128
	if (argc != 2)
3129
3130
3131
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
3132
	unsigned offset;
3133
	COMMAND_PARSE_NUMBER(uint, args[0], offset);
3134
3135

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

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

zwelch's avatar
zwelch committed
3139
3140
	static const int maxSample = 10000;
	uint32_t *samples = malloc(sizeof(uint32_t)*maxSample);
zwelch's avatar
zwelch committed
3141
	if (samples == NULL)
3142
		return ERROR_OK;
oharboe's avatar
oharboe committed
3143

zwelch's avatar
zwelch committed
3144
	int numSamples = 0;
3145
	/* hopefully it is safe to cache! We want to stop/restart as quickly as possible. */
3146
	reg_t *reg = register_get_by_name(target->reg_cache, "pc", 1);
oharboe's avatar
oharboe committed
3147

3148
3149
	for (;;)
	{
3150
		int retval;
3151
		target_poll(target);
3152
3153
		if (target->state == TARGET_HALTED)
		{
3154
			uint32_t t=*((uint32_t *)reg->value);
3155
			samples[numSamples++]=t;
3156
3157
			retval = target_resume(target, 1, 0, 0, 0); /* current pc, addr = 0, do not handle breakpoints, not debugging */
			target_poll(target);
3158
			alive_sleep(10); /* sleep 10ms, i.e. <100 samples/second. */
3159
3160
		} else if (target->state == TARGET_RUNNING)
		{
3161
			/* We want to quickly sample the PC. */
zwelch's avatar
zwelch committed
3162
			if ((retval = target_halt(target)) != ERROR_OK)
3163
3164
3165
3166
			{
				free(samples);
				return retval;
			}
3167
3168
3169
		} else
		{
			command_print(cmd_ctx, "Target not halted or running");
zwelch's avatar
zwelch committed
3170
			retval = ERROR_OK;
3171
3172
			break;
		}
zwelch's avatar
zwelch committed
3173
		if (retval != ERROR_OK)
3174
3175
3176
		{
			break;
		}
oharboe's avatar
oharboe committed
3177

3178
		gettimeofday(&now, NULL);
zwelch's avatar
zwelch committed
3179
		if ((numSamples >= maxSample) || ((now.tv_sec >= timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec)))
3180
3181
		{
			command_print(cmd_ctx, "Profiling completed. %d samples.", numSamples);
zwelch's avatar
zwelch committed
3182
			if ((retval = target_poll(target)) != ERROR_OK)
3183
3184
3185
3186
			{
				free(samples);
				return retval;
			}
3187
3188
			if (target->state == TARGET_HALTED)
			{
3189
				target_resume(target, 1, 0, 0, 0); /* current pc, addr = 0, do not handle breakpoints, not debugging */
3190
			}
zwelch's avatar
zwelch committed
3191
			if ((retval = target_poll(target)) != ERROR_OK)
3192
3193
3194
3195
			{
				free(samples);
				return retval;
			}
3196
3197
3198
3199
3200
3201
			writeGmon(samples, numSamples, args[1]);
			command_print(cmd_ctx, "Wrote %s", args[1]);
			break;
		}
	}
	free(samples);
oharboe's avatar
oharboe committed
3202

3203
3204
	return ERROR_OK;
}
3205

3206
static int new_int_array_element(Jim_Interp * interp, const char *varname, int idx, uint32_t val)
3207
3208
3209
3210
3211
3212
3213
3214
{
	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
3215

3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
	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;
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
	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
3252
	return 	target_mem2array(interp, target, argc-1, argv + 1);
3253
3254
3255
3256
}

static int target_mem2array(Jim_Interp *interp, target_t *target, int argc, Jim_Obj *const *argv)
{
3257
	long l;
3258
	uint32_t width;
3259
	int len;
3260
3261
3262
	uint32_t addr;
	uint32_t count;
	uint32_t v;
3263
	const char *varname;
3264
	uint8_t buffer[4096];
3265
	int  n, e, retval;
3266
	uint32_t i;
3267
3268
3269

	/* argv[1] = name of array to receive the data
	 * argv[2] = desired width
oharboe's avatar
oharboe committed
3270
	 * argv[3] = memory address
3271
3272
	 * argv[4] = count of times to read
	 */
3273
	if (argc != 4) {
3274
3275
3276
		Jim_WrongNumArgs(interp, 1, argv, "varname width addr nelems");
		return JIM_ERR;
	}
3277
	varname = Jim_GetString(argv[0], &len);
3278
3279
	/* given "foo" get space for worse case "foo(%d)" .. add 20 */

3280
	e = Jim_GetLong(interp, argv[1], &l);
3281
3282
3283
3284
	width = l;
	if (e != JIM_OK) {
		return e;
	}
oharboe's avatar
oharboe committed
3285

3286
	e = Jim_GetLong(interp, argv[2], &l);
3287
3288
3289
3290
	addr = l;
	if (e != JIM_OK) {
		return e;
	}
3291
	e = Jim_GetLong(interp, argv[3], &l);
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
	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));
3308
			Jim_AppendStrings(interp, Jim_GetResult(interp), "Invalid width param, must be 8/16/32", NULL);
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
			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
3326
3327
	}

3328
3329
3330
3331
3332
3333
3334
	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));
3335
3336
		sprintf(buf, "mem2array address: 0x%08" PRIx32 " is not aligned for %" PRId32 " byte reads",
				addr,
duane's avatar
duane committed
3337
				width);
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
		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
3350

3351
3352
3353
3354
		count = len; /* in objects.. */
		if (count > (sizeof(buffer)/width)) {
			count = (sizeof(buffer)/width);
		}
oharboe's avatar
oharboe committed
3355

3356
		retval = target_read_memory(target, addr, width, count, buffer);
3357
3358
		if (retval != ERROR_OK) {
			/* BOO !*/
3359
3360
3361
			LOG_ERROR("mem2array: Read @ 0x%08x, w=%d, cnt=%d, failed",
					  (unsigned int)addr,
					  (int)width,
duane's avatar
duane committed
3362
					  (int)count);
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
			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
3386

3387
3388
3389
3390
3391
	Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));

	return JIM_OK;
}

3392
static int get_int_array_element(Jim_Interp * interp, const char *varname, int idx, uint32_t *val)
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
{
	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;
3426
	target_t *target;
3427

3428
	context = Jim_GetAssocData(interp, "context");
zwelch's avatar
zwelch committed
3429
	if (context == NULL) {
3430
3431
3432
3433
		LOG_ERROR("array2mem: no command context");
		return JIM_ERR;
	}
	target = get_current_target(context);
zwelch's avatar
zwelch committed
3434
	if (target == NULL) {
3435
3436
3437
		LOG_ERROR("array2mem: no current target");
		return JIM_ERR;
	}
3438

3439
	return target_array2mem(interp,target, argc-1, argv + 1);
3440
3441
3442
}
static int target_array2mem(Jim_Interp *interp, target_t *target, int argc, Jim_Obj *const *argv)
{
3443
	long l;
3444
	uint32_t width;
3445
	int len;
3446
3447
3448
	uint32_t addr;
	uint32_t count;
	uint32_t v;
3449
	const char *varname;
3450
	uint8_t buffer[4096];
3451
	int  n, e, retval;
3452
	uint32_t i;
3453
3454
3455

	/* argv[1] = name of array to get the data
	 * argv[2] = desired width
oharboe's avatar
oharboe committed
3456
	 * argv[3] = memory address
3457
3458
	 * argv[4] = count to write
	 */
3459
	if (argc != 4) {
3460
3461
3462
		Jim_WrongNumArgs(interp, 1, argv, "varname width addr nelems");
		return JIM_ERR;
	}
3463
	varname = Jim_GetString(argv[0], &len);
3464
3465
	/* given "foo" get space for worse case "foo(%d)" .. add 20 */

3466
	e = Jim_GetLong(interp, argv[1], &l);
3467
3468
3469
3470
	width = l;
	if (e != JIM_OK) {
		return e;
	}
oharboe's avatar
oharboe committed
3471

3472
	e = Jim_GetLong(interp, argv[2], &l);
3473
3474
3475
3476
	addr = l;
	if (e != JIM_OK) {
		return e;
	}
3477
	e = Jim_GetLong(interp, argv[3], &l);
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
	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));
3494
			Jim_AppendStrings(interp, Jim_GetResult(interp), "Invalid width param, must be 8/16/32", NULL);
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
			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
3512
3513
	}

3514
3515
3516
3517
3518
3519
3520
	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));
3521
3522
		sprintf(buf, "array2mem address: 0x%08x is not aligned for %d byte reads",
				(unsigned int)addr,
duane's avatar
duane committed
3523
				(int)width);
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
		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
3536

3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
		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
3559
		retval = target_write_memory(target, addr, width, count, buffer);
3560
3561
		if (retval != ERROR_OK) {
			/* BOO !*/
3562
3563
3564
			LOG_ERROR("array2mem: Write @ 0x%08x, w=%d, cnt=%d, failed",
					  (unsigned int)addr,
					  (int)width,
duane's avatar
duane committed
3565
					  (int)count);
3566
			Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
3567
			Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: cannot read memory", NULL);
3568
3569
3570
3571
			e = JIM_ERR;
			len = 0;
		}
	}
oharboe's avatar
oharboe committed
3572

3573
3574
3575
3576
	Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));

	return JIM_OK;
}
3577

3578
void target_all_handle_event(enum target_event e)
3579
3580
3581
{
	target_t *target;

3582
	LOG_DEBUG("**all*targets: event: %d, %s",
duane's avatar
duane committed
3583
			   (int)e,
3584
			   Jim_Nvp_value2name_simple(nvp_target_event, e)->name);
3585
3586

	target = all_targets;
zwelch's avatar
zwelch committed
3587
	while (target) {
3588
		target_handle_event(target, e);
3589
3590
3591
3592
		target = target->next;
	}
}

3593
3594
3595
3596

/* FIX? should we propagate errors here rather than printing them
 * and continuing?
 */
3597
void target_handle_event(target_t *target, enum target_event e)
3598
3599
3600
{
	target_event_action_t *teap;

dbrownell's avatar
dbrownell committed
3601
	for (teap = target->event_action; teap != NULL; teap = teap->next) {
zwelch's avatar
zwelch committed
3602
		if (teap->event == e) {
3603
			LOG_DEBUG("target: (%d) %s (%s) event: %d (%s) action: %s",
3604
3605
					   target->target_number,
					   target->cmd_name,
zwelch's avatar
zwelch committed
3606
					   target_get_name(target),
3607
					   e,
3608
3609
3610
					   Jim_Nvp_value2name_simple(nvp_target_event, e)->name,
					   Jim_GetString(teap->body, NULL));
			if (Jim_EvalObj(interp, teap->body) != JIM_OK)
3611
3612
3613
			{
				Jim_PrintErrorMessage(interp);
			}
3614
3615
3616
3617
3618
3619
		}
	}
}

enum target_cfg_param {
	TCFG_TYPE,
3620
	TCFG_EVENT,
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
	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 },
3640

3641
3642
	{ .name = NULL, .value = -1 }
};
3643

3644
static int target_configure(Jim_GetOptInfo *goi, target_t *target)
3645
3646
3647
3648
3649
3650
3651
3652
{
	Jim_Nvp *n;
	Jim_Obj *o;
	jim_wide w;
	char *cp;
	int e;

	/* parse config or cget options ... */
zwelch's avatar
zwelch committed
3653
	while (goi->argc > 0) {
3654
3655
		Jim_SetEmptyResult(goi->interp);
		/* Jim_GetOpt_Debug(goi); */
3656

zwelch's avatar
zwelch committed
3657
		if (target->type->target_jim_configure) {
3658
3659
			/* target defines a configure function */
			/* target gets first dibs on parameters */
3660
			e = (*(target->type->target_jim_configure))(target, goi);
zwelch's avatar
zwelch committed
3661
			if (e == JIM_OK) {
3662
3663
3664
				/* more? */
				continue;
			}
zwelch's avatar
zwelch committed
3665
			if (e == JIM_ERR) {
3666
3667
3668
3669
3670
				/* An error */
				return e;
			}
			/* otherwise we 'continue' below */
		}
3671
		e = Jim_GetOpt_Nvp(goi, nvp_config_opts, &n);
zwelch's avatar
zwelch committed
3672
		if (e != JIM_OK) {
3673
			Jim_GetOpt_NvpUnknown(goi, nvp_config_opts, 0);
3674
3675
			return e;
		}
zwelch's avatar
zwelch committed
3676
		switch (n->value) {
3677
3678
		case TCFG_TYPE:
			/* not setable */
zwelch's avatar
zwelch committed
3679
			if (goi->isconfigure) {
3680
				Jim_SetResult_sprintf(goi->interp, "not setable: %s", n->name);
3681
3682
3683
				return JIM_ERR;
			} else {
			no_params:
zwelch's avatar
zwelch committed
3684
				if (goi->argc != 0) {
3685
					Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "NO PARAMS");
3686
3687
3688
					return JIM_ERR;
				}
			}
3689
			Jim_SetResultString(goi->interp, target_get_name(target), -1);
3690
3691
3692
			/* loop for more */
			break;
		case TCFG_EVENT:
zwelch's avatar
zwelch committed
3693
			if (goi->argc == 0) {
3694
				Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name? ...");
3695
3696
3697
				return JIM_ERR;
			}

3698
			e = Jim_GetOpt_Nvp(goi, nvp_target_event, &n);
zwelch's avatar
zwelch committed
3699
			if (e != JIM_OK) {
3700
				Jim_GetOpt_NvpUnknown(goi, nvp_target_event, 1);
3701
3702
3703
				return e;
			}

zwelch's avatar
zwelch committed
3704
3705
			if (goi->isconfigure) {
				if (goi->argc != 1) {
3706
					Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name? ?EVENT-BODY?");
3707
					return JIM_ERR;
3708
				}
3709
			} else {
zwelch's avatar
zwelch committed
3710
				if (goi->argc != 0) {
3711
3712
3713
3714
3715
					Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name?");
					return JIM_ERR;
				}
			}

3716
			{
3717
				target_event_action_t *teap;
3718

3719
3720
				teap = target->event_action;
				/* replace existing? */
zwelch's avatar
zwelch committed
3721
3722
				while (teap) {
					if (teap->event == (enum target_event)n->value) {
3723
3724
3725
3726
						break;
					}
					teap = teap->next;
				}
3727

zwelch's avatar
zwelch committed
3728
				if (goi->isconfigure) {
3729
					bool replace = true;
zwelch's avatar
zwelch committed
3730
					if (teap == NULL) {
3731
						/* create new */
3732
						teap = calloc(1, sizeof(*teap));
3733
						replace = false;
3734
3735
					}
					teap->event = n->value;
3736
					Jim_GetOpt_Obj(goi, &o);
zwelch's avatar
zwelch committed
3737
					if (teap->body) {
3738
						Jim_DecrRefCount(interp, teap->body);
3739
					}
3740
					teap->body  = Jim_DuplicateObj(goi->interp, o);
3741
					/*
3742
					 * FIXME:
3743
3744
3745
3746
3747
3748
3749
3750
					 *     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.
					 */
3751
					Jim_IncrRefCount(teap->body);
3752

3753
3754
3755
3756
3757
3758
					if (!replace)
					{
						/* add to head of event list */
						teap->next = target->event_action;
						target->event_action = teap;
					}
3759
3760
3761
					Jim_SetEmptyResult(goi->interp);
				} else {
					/* get */
zwelch's avatar
zwelch committed
3762
					if (teap == NULL) {
3763
						Jim_SetEmptyResult(goi->interp);
3764
					} else {
3765
						Jim_SetResult(goi->interp, Jim_DuplicateObj(goi->interp, teap->body));
3766
3767
3768
3769
3770
3771
3772
					}
				}
			}
			/* loop for more */
			break;

		case TCFG_WORK_AREA_VIRT:
zwelch's avatar
zwelch committed
3773
			if (goi->isconfigure) {
3774
				target_free_all_working_areas(target);
3775
				e = Jim_GetOpt_Wide(goi, &w);
zwelch's avatar
zwelch committed
3776
				if (e != JIM_OK) {
3777
3778
3779
					return e;
				}
				target->working_area_virt = w;
3780
				target->working_area_virt_spec = true;
3781
			} else {
zwelch's avatar
zwelch committed
3782
				if (goi->argc != 0) {
3783
3784
					goto no_params;
				}
3785
			}
3786
			Jim_SetResult(interp, Jim_NewIntObj(goi->interp, target->working_area_virt));
3787
3788
			/* loop for more */
			break;
3789

3790
		case TCFG_WORK_AREA_PHYS:
zwelch's avatar
zwelch committed
3791
			if (goi->isconfigure) {
3792
				target_free_all_working_areas(target);
3793
				e = Jim_GetOpt_Wide(goi, &w);
zwelch's avatar
zwelch committed
3794
				if (e != JIM_OK) {
3795
3796
3797
					return e;
				}
				target->working_area_phys = w;
3798
				target->working_area_phys_spec = true;
3799
			} else {
zwelch's avatar
zwelch committed
3800
				if (goi->argc != 0) {
3801
3802
					goto no_params;
				}
3803
			}
3804
			Jim_SetResult(interp, Jim_NewIntObj(goi->interp, target->working_area_phys));
3805
3806
3807
3808
			/* loop for more */
			break;

		case TCFG_WORK_AREA_SIZE:
zwelch's avatar
zwelch committed
3809
			if (goi->isconfigure) {
3810
				target_free_all_working_areas(target);
3811
				e = Jim_GetOpt_Wide(goi, &w);
zwelch's avatar
zwelch committed
3812
				if (e != JIM_OK) {
3813
3814
3815
3816
					return e;
				}
				target->working_area_size = w;
			} else {
zwelch's avatar
zwelch committed
3817
				if (goi->argc != 0) {
3818
3819
					goto no_params;
				}
3820
			}
3821
			Jim_SetResult(interp, Jim_NewIntObj(goi->interp, target->working_area_size));
3822
3823
3824
3825
			/* loop for more */
			break;

		case TCFG_WORK_AREA_BACKUP:
zwelch's avatar
zwelch committed
3826
			if (goi->isconfigure) {
3827
				target_free_all_working_areas(target);
3828
				e = Jim_GetOpt_Wide(goi, &w);
zwelch's avatar
zwelch committed
3829
				if (e != JIM_OK) {
3830
3831
3832
3833
3834
					return e;
				}
				/* make this exactly 1 or 0 */
				target->backup_working_area = (!!w);
			} else {
zwelch's avatar
zwelch committed
3835
				if (goi->argc != 0) {
3836
3837
					goto no_params;
				}
3838
			}
3839
			Jim_SetResult(interp, Jim_NewIntObj(goi->interp, target->backup_working_area));
3840
3841
3842
3843
			/* loop for more e*/
			break;

		case TCFG_ENDIAN:
zwelch's avatar
zwelch committed
3844
			if (goi->isconfigure) {
3845
				e = Jim_GetOpt_Nvp(goi, nvp_target_endian, &n);
zwelch's avatar
zwelch committed
3846
				if (e != JIM_OK) {
3847
					Jim_GetOpt_NvpUnknown(goi, nvp_target_endian, 1);
3848
3849
3850
3851
					return e;
				}
				target->endianness = n->value;
			} else {
zwelch's avatar
zwelch committed
3852
				if (goi->argc != 0) {
3853
3854
3855
					goto no_params;
				}
			}
3856
			n = Jim_Nvp_value2name_simple(nvp_target_endian, target->endianness);
zwelch's avatar
zwelch committed
3857
			if (n->name == NULL) {
3858
				target->endianness = TARGET_LITTLE_ENDIAN;
3859
				n = Jim_Nvp_value2name_simple(nvp_target_endian, target->endianness);
3860
			}
3861
			Jim_SetResultString(goi->interp, n->name, -1);
3862
3863
3864
3865
			/* loop for more */
			break;

		case TCFG_VARIANT:
zwelch's avatar
zwelch committed
3866
3867
			if (goi->isconfigure) {
				if (goi->argc < 1) {
3868
					Jim_SetResult_sprintf(goi->interp,
3869
										   "%s ?STRING?",
3870
										   n->name);
3871
3872
					return JIM_ERR;
				}
zwelch's avatar
zwelch committed
3873
				if (target->variant) {
3874
3875
					free((void *)(target->variant));
				}
3876
				e = Jim_GetOpt_String(goi, &cp, NULL);
3877
3878
				target->variant = strdup(cp);
			} else {
zwelch's avatar
zwelch committed
3879
				if (goi->argc != 0) {
3880
3881
					goto no_params;
				}
3882
			}
3883
			Jim_SetResultString(goi->interp, target->variant,-1);
3884
3885
3886
			/* loop for more */
			break;
		case TCFG_CHAIN_POSITION:
zwelch's avatar
zwelch committed
3887
			if (goi->isconfigure) {
3888
3889
				Jim_Obj *o;
				jtag_tap_t *tap;
3890
				target_free_all_working_areas(target);
3891
				e = Jim_GetOpt_Obj(goi, &o);
zwelch's avatar
zwelch committed
3892
				if (e != JIM_OK) {
3893
3894
					return e;
				}
3895
				tap = jtag_tap_by_jim_obj(goi->interp, o);
zwelch's avatar
zwelch committed
3896
				if (tap == NULL) {
3897
					return JIM_ERR;
3898
				}
3899
				/* make this exactly 1 or 0 */
3900
				target->tap = tap;
3901
			} else {
zwelch's avatar
zwelch committed
3902
				if (goi->argc != 0) {
3903
3904
					goto no_params;
				}
3905
			}
3906
			Jim_SetResultString(interp, target->tap->dotted_name, -1);
3907
3908
3909
			/* loop for more e*/
			break;
		}
3910
	} /* while (goi->argc) */
3911
3912


3913
		/* done - we return */
3914
3915
3916
3917
	return JIM_OK;
}

/** this is the 'tcl' handler for the target specific command */
3918
static int tcl_target_func(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3919
3920
3921
3922
{
	Jim_GetOptInfo goi;
	jim_wide a,b,c;
	int x,y,z;
3923
	uint8_t  target_buf[32];