arm7tdmi.c 26.3 KB
Newer Older
1
2
3
4
/***************************************************************************
 *   Copyright (C) 2005 by Dominic Rath                                    *
 *   Dominic.Rath@gmx.de                                                   *
 *                                                                         *
5
6
7
 *   Copyright (C) 2008 by Spencer Oliver                                  *
 *   spen@spen-soft.co.uk                                                  *
 *                                                                         *
8
9
10
 *   Copyright (C) 2007,2008 yvind Harboe                                 *
 *   oyvind.harboe@zylin.com                                               *
 *                                                                         *
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "arm7tdmi.h"
31
#include "target_type.h"
32
33
34
35
36
37
38


#if 0
#define _DEBUG_INSTRUCTION_EXECUTION_
#endif

/* forward declarations */
39
40

int arm7tdmi_target_create(struct target_s *target,Jim_Interp *interp);
oharboe's avatar
oharboe committed
41
int arm7tdmi_quit(void);
42
43
44
45

/* target function declarations */
int arm7tdmi_poll(struct target_s *target);
int arm7tdmi_halt(target_t *target);
46

47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
target_type_t arm7tdmi_target =
{
	.name = "arm7tdmi",

	.poll = arm7_9_poll,
	.arch_state = armv4_5_arch_state,

	.target_request_data = arm7_9_target_request_data,

	.halt = arm7_9_halt,
	.resume = arm7_9_resume,
	.step = arm7_9_step,

	.assert_reset = arm7_9_assert_reset,
	.deassert_reset = arm7_9_deassert_reset,
	.soft_reset_halt = arm7_9_soft_reset_halt,

	.get_gdb_reg_list = armv4_5_get_gdb_reg_list,
65

66
67
68
69
	.read_memory = arm7_9_read_memory,
	.write_memory = arm7_9_write_memory,
	.bulk_write_memory = arm7_9_bulk_write_memory,
	.checksum_memory = arm7_9_checksum_memory,
70
	.blank_check_memory = arm7_9_blank_check_memory,
71

72
	.run_algorithm = armv4_5_run_algorithm,
73

74
75
76
77
78
	.add_breakpoint = arm7_9_add_breakpoint,
	.remove_breakpoint = arm7_9_remove_breakpoint,
	.add_watchpoint = arm7_9_add_watchpoint,
	.remove_watchpoint = arm7_9_remove_watchpoint,

79
80
	.register_commands  = arm7tdmi_register_commands,
	.target_create  = arm7tdmi_target_create,
81
	.init_target = arm7tdmi_init_target,
82
	.examine = arm7tdmi_examine,
83
84
85
86
87
	.quit = arm7tdmi_quit
};

int arm7tdmi_examine_debug_reason(target_t *target)
{
88
	int retval = ERROR_OK;
89
90
91
	/* get pointers to arch-specific information */
	armv4_5_common_t *armv4_5 = target->arch_info;
	arm7_9_common_t *arm7_9 = armv4_5->arch_info;
92

93
94
95
96
97
	/* only check the debug reason if we don't know it already */
	if ((target->debug_reason != DBG_REASON_DBGRQ)
			&& (target->debug_reason != DBG_REASON_SINGLESTEP))
	{
		scan_field_t fields[2];
98
99
		uint8_t databus[4];
		uint8_t breakpoint;
100

101
		jtag_set_end_state(TAP_DRPAUSE);
102

103
		fields[0].tap = arm7_9->jtag_info.tap;
104
105
106
		fields[0].num_bits = 1;
		fields[0].out_value = NULL;
		fields[0].in_value = &breakpoint;
107

108
		fields[1].tap = arm7_9->jtag_info.tap;
109
110
111
		fields[1].num_bits = 32;
		fields[1].out_value = NULL;
		fields[1].in_value = databus;
112

113
114
115
116
		if((retval = arm_jtag_scann(&arm7_9->jtag_info, 0x1)) != ERROR_OK)
		{
			return retval;
		}
117
118
		arm_jtag_set_instr(&arm7_9->jtag_info, arm7_9->jtag_info.intest_instr, NULL);

119
		jtag_add_dr_scan(2, fields, jtag_set_end_state(TAP_DRPAUSE));
120
121
122
123
		if((retval = jtag_execute_queue()) != ERROR_OK)
		{
			return retval;
		}
124

125
126
127
128
		fields[0].in_value = NULL;
		fields[0].out_value = &breakpoint;
		fields[1].in_value = NULL;
		fields[1].out_value = databus;
129

130
		jtag_add_dr_scan(2, fields, jtag_set_end_state(TAP_DRPAUSE));
131
132

		if (breakpoint & 1)
133
			target->debug_reason = DBG_REASON_WATCHPOINT;
134
		else
135
			target->debug_reason = DBG_REASON_BREAKPOINT;
136
137
138
139
140
	}

	return ERROR_OK;
}

141
142
static int arm7tdmi_num_bits[]={1, 32};
static __inline int arm7tdmi_clock_out_inner(arm_jtag_t *jtag_info, u32 out, int breakpoint)
143
{
144
	u32 values[2]={breakpoint, flip_u32(out, 32)};
145

146
	jtag_add_dr_out(jtag_info->tap,
147
148
149
			2,
			arm7tdmi_num_bits,
			values,
150
			jtag_get_end_state());
151

152
	jtag_add_runtest(0, jtag_get_end_state());
153

154
155
156
157
158
159
	return ERROR_OK;
}

/* put an instruction in the ARM7TDMI pipeline or write the data bus, and optionally read data */
static __inline int arm7tdmi_clock_out(arm_jtag_t *jtag_info, u32 out, u32 *deprecated, int breakpoint)
{
160
	jtag_set_end_state(TAP_DRPAUSE);
161
162
	arm_jtag_scann(jtag_info, 0x1);
	arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL);
163

164
	return arm7tdmi_clock_out_inner(jtag_info, out, breakpoint);
165
166
167
168
169
}

/* clock the target, reading the databus */
int arm7tdmi_clock_data_in(arm_jtag_t *jtag_info, u32 *in)
{
170
	int retval = ERROR_OK;
171
172
	scan_field_t fields[2];

173
	jtag_set_end_state(TAP_DRPAUSE);
174
175
176
177
	if((retval = arm_jtag_scann(jtag_info, 0x1)) != ERROR_OK)
	{
		return retval;
	}
178
	arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL);
179

180
	fields[0].tap = jtag_info->tap;
181
182
183
	fields[0].num_bits = 1;
	fields[0].out_value = NULL;
	fields[0].in_value = NULL;
184

185
	fields[1].tap = jtag_info->tap;
186
187
	fields[1].num_bits = 32;
	fields[1].out_value = NULL;
188
	fields[1].in_value = (uint8_t *)in;
189

190
	jtag_add_dr_scan(2, fields, jtag_get_end_state());
191

192
	jtag_add_callback(arm7flip32, (uint8_t *)in);
193

194
	jtag_add_runtest(0, jtag_get_end_state());
195

196
197
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
{
198
199
200
201
		if((retval = jtag_execute_queue()) != ERROR_OK)
		{
			return retval;
		}
202

203
204
		if (in)
		{
205
			LOG_DEBUG("in: 0x%8.8x", *in);
206
207
208
		}
		else
		{
209
			LOG_ERROR("BUG: called with in == NULL");
210
211
212
213
214
215
216
		}
}
#endif

	return ERROR_OK;
}

217
void arm_endianness(uint8_t *tmp, void *in, int size, int be, int flip)
oharboe's avatar
oharboe committed
218
{
oharboe's avatar
oharboe committed
219
220
221
	u32 readback=le_to_h_u32(tmp);
	if (flip)
		readback=flip_u32(readback, 32);
oharboe's avatar
oharboe committed
222
223
224
225
226
	switch (size)
	{
		case 4:
			if (be)
			{
227
				h_u32_to_be(((uint8_t*)in), readback);
oharboe's avatar
oharboe committed
228
229
			} else
			{
230
				 h_u32_to_le(((uint8_t*)in), readback);
oharboe's avatar
oharboe committed
231
232
233
234
235
			}
			break;
		case 2:
			if (be)
			{
236
				h_u16_to_be(((uint8_t*)in), readback & 0xffff);
oharboe's avatar
oharboe committed
237
238
			} else
			{
239
				h_u16_to_le(((uint8_t*)in), readback & 0xffff);
oharboe's avatar
oharboe committed
240
241
242
			}
			break;
		case 1:
243
			*((uint8_t *)in)= readback & 0xff;
oharboe's avatar
oharboe committed
244
245
			break;
	}
246
}
oharboe's avatar
oharboe committed
247

248
static int arm7endianness(uint8_t *in, jtag_callback_data_t size, jtag_callback_data_t be, jtag_callback_data_t captured)
249
{
250
	arm_endianness((uint8_t *)captured, in, (int)size, (int)be, 1);
251
	return ERROR_OK;
oharboe's avatar
oharboe committed
252
253
}

254
255
256
/* clock the target, and read the databus
 * the *in pointer points to a buffer where elements of 'size' bytes
 * are stored in big (be==1) or little (be==0) endianness
257
 */
258
259
int arm7tdmi_clock_data_in_endianness(arm_jtag_t *jtag_info, void *in, int size, int be)
{
260
	int retval = ERROR_OK;
261
262
	scan_field_t fields[2];

263
	jtag_set_end_state(TAP_DRPAUSE);
264
265
266
267
	if((retval = arm_jtag_scann(jtag_info, 0x1)) != ERROR_OK)
	{
		return retval;
	}
268
	arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL);
269

270
	fields[0].tap = jtag_info->tap;
271
272
273
	fields[0].num_bits = 1;
	fields[0].out_value = NULL;
	fields[0].in_value = NULL;
274

275
	fields[1].tap = jtag_info->tap;
276
277
	fields[1].num_bits = 32;
	fields[1].out_value = NULL;
278
	jtag_alloc_in_value32(&fields[1]);
279

280
	jtag_add_dr_scan(2, fields, jtag_get_end_state());
281

282
	jtag_add_callback4(arm7endianness, in, (jtag_callback_data_t)size, (jtag_callback_data_t)be, (jtag_callback_data_t)fields[1].in_value);
283

284
	jtag_add_runtest(0, jtag_get_end_state());
285

286
287
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
{
288
289
290
291
		if((retval = jtag_execute_queue()) != ERROR_OK)
		{
			return retval;
		}
292

293
294
		if (in)
		{
295
			LOG_DEBUG("in: 0x%8.8x", *(u32*)in);
296
297
298
		}
		else
		{
299
			LOG_ERROR("BUG: called with in == NULL");
300
301
302
303
304
305
306
307
308
309
310
311
312
		}
}
#endif

	return ERROR_OK;
}

void arm7tdmi_change_to_arm(target_t *target, u32 *r0, u32 *pc)
{
	/* get pointers to arch-specific information */
	armv4_5_common_t *armv4_5 = target->arch_info;
	arm7_9_common_t *arm7_9 = armv4_5->arch_info;
	arm_jtag_t *jtag_info = &arm7_9->jtag_info;
313
314

	/* save r0 before using it and put system in ARM state
315
	 * to allow common handling of ARM and THUMB debugging */
316

317
318
319
320
321
322
323
	/* fetch STR r0, [r0] */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), NULL, 0);
	arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
	arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
	/* nothing fetched, STR r0, [r0] in Execute (2) */
	arm7tdmi_clock_data_in(jtag_info, r0);

324
	/* MOV r0, r15 fetched, STR in Decode */
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
	arm7tdmi_clock_out(jtag_info, ARMV4_5_T_MOV(0, 15), NULL, 0);
	arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), NULL, 0);
	arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
	arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
	/* nothing fetched, STR r0, [r0] in Execute (2) */
	arm7tdmi_clock_data_in(jtag_info, pc);

	/* use pc-relative LDR to clear r0[1:0] (for switch to ARM mode) */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), NULL, 0);
	arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
	arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
	/* nothing fetched, data for LDR r0, [PC, #0] */
	arm7tdmi_clock_out(jtag_info, 0x0, NULL, 0);
	/* nothing fetched, data from previous cycle is written to register */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
340

341
342
343
344
345
346
	/* fetch BX */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_T_BX(0), NULL, 0);
	/* NOP fetched, BX in Decode, MOV in Execute */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
	/* NOP fetched, BX in Execute (1) */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
347

348
	jtag_execute_queue();
349

350
351
352
353
354
355
356
	/* fix program counter:
	 * MOV r0, r15 was the 4th instruction (+6)
	 * reading PC in Thumb state gives address of instruction + 4
	 */
	*pc -= 0xa;
}

357
358
359
360
361
362
363

/* FIX!!! is this a potential performance bottleneck w.r.t. requiring too many
 * roundtrips when jtag_execute_queue() has a large overhead(e.g. for USB)s?
 *
 * The solution is to arrange for a large out/in scan in this loop and
 * and convert data afterwards.
 */
364
365
366
367
368
369
370
void arm7tdmi_read_core_regs(target_t *target, u32 mask, u32* core_regs[16])
{
	int i;
	/* get pointers to arch-specific information */
	armv4_5_common_t *armv4_5 = target->arch_info;
	arm7_9_common_t *arm7_9 = armv4_5->arch_info;
	arm_jtag_t *jtag_info = &arm7_9->jtag_info;
371

372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
	/* STMIA r0-15, [r0] at debug speed
	 * register values will start to appear on 4th DCLK
	 */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), NULL, 0);

	/* fetch NOP, STM in DECODE stage */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
	/* fetch NOP, STM in EXECUTE stage (1st cycle) */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);

	for (i = 0; i <= 15; i++)
	{
		if (mask & (1 << i))
			/* nothing fetched, STM still in EXECUTE (1+i cycle) */
			arm7tdmi_clock_data_in(jtag_info, core_regs[i]);
	}
}

void arm7tdmi_read_core_regs_target_buffer(target_t *target, u32 mask, void* buffer, int size)
{
	int i;
	/* get pointers to arch-specific information */
	armv4_5_common_t *armv4_5 = target->arch_info;
	arm7_9_common_t *arm7_9 = armv4_5->arch_info;
	arm_jtag_t *jtag_info = &arm7_9->jtag_info;
	int be = (target->endianness == TARGET_BIG_ENDIAN) ? 1 : 0;
	u32 *buf_u32 = buffer;
	u16 *buf_u16 = buffer;
400
	uint8_t *buf_u8 = buffer;
401

402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
	/* STMIA r0-15, [r0] at debug speed
	 * register values will start to appear on 4th DCLK
	 */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), NULL, 0);

	/* fetch NOP, STM in DECODE stage */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
	/* fetch NOP, STM in EXECUTE stage (1st cycle) */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);

	for (i = 0; i <= 15; i++)
	{
		/* nothing fetched, STM still in EXECUTE (1+i cycle), read databus */
		if (mask & (1 << i))
		{
			switch (size)
			{
				case 4:
					arm7tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be);
					break;
				case 2:
					arm7tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be);
					break;
				case 1:
					arm7tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be);
					break;
			}
		}
	}
}

void arm7tdmi_read_xpsr(target_t *target, u32 *xpsr, int spsr)
{
	/* get pointers to arch-specific information */
	armv4_5_common_t *armv4_5 = target->arch_info;
	arm7_9_common_t *arm7_9 = armv4_5->arch_info;
	arm_jtag_t *jtag_info = &arm7_9->jtag_info;
439

440
441
	/* MRS r0, cpsr */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), NULL, 0);
442

443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
	/* STR r0, [r15] */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 15), NULL, 0);
	/* fetch NOP, STR in DECODE stage */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
	/* fetch NOP, STR in EXECUTE stage (1st cycle) */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
	/* nothing fetched, STR still in EXECUTE (2nd cycle) */
	arm7tdmi_clock_data_in(jtag_info, xpsr);
}

void arm7tdmi_write_xpsr(target_t *target, u32 xpsr, int spsr)
{
	/* get pointers to arch-specific information */
	armv4_5_common_t *armv4_5 = target->arch_info;
	arm7_9_common_t *arm7_9 = armv4_5->arch_info;
	arm_jtag_t *jtag_info = &arm7_9->jtag_info;
459

460
	LOG_DEBUG("xpsr: %8.8x, spsr: %i", xpsr, spsr);
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483

	/* MSR1 fetched */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), NULL, 0);
	/* MSR2 fetched, MSR1 in DECODE */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), NULL, 0);
	/* MSR3 fetched, MSR1 in EXECUTE (1), MSR2 in DECODE */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), NULL, 0);
	/* nothing fetched, MSR1 in EXECUTE (2) */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
	/* MSR4 fetched, MSR2 in EXECUTE (1), MSR3 in DECODE */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), NULL, 0);
	/* nothing fetched, MSR2 in EXECUTE (2) */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
	/* NOP fetched, MSR3 in EXECUTE (1), MSR4 in DECODE */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
	/* nothing fetched, MSR3 in EXECUTE (2) */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
	/* NOP fetched, MSR4 in EXECUTE (1) */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
	/* nothing fetched, MSR4 in EXECUTE (2) */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
}

484
void arm7tdmi_write_xpsr_im8(target_t *target, uint8_t xpsr_im, int rot, int spsr)
485
486
487
488
489
{
	/* get pointers to arch-specific information */
	armv4_5_common_t *armv4_5 = target->arch_info;
	arm7_9_common_t *arm7_9 = armv4_5->arch_info;
	arm_jtag_t *jtag_info = &arm7_9->jtag_info;
490

491
	LOG_DEBUG("xpsr_im: %2.2x, rot: %i, spsr: %i", xpsr_im, rot, spsr);
492

493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
	/* MSR fetched */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), NULL, 0);
	/* NOP fetched, MSR in DECODE */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
	/* NOP fetched, MSR in EXECUTE (1) */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
	/* nothing fetched, MSR in EXECUTE (2) */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
}

void arm7tdmi_write_core_regs(target_t *target, u32 mask, u32 core_regs[16])
{
	int i;
	/* get pointers to arch-specific information */
	armv4_5_common_t *armv4_5 = target->arch_info;
	arm7_9_common_t *arm7_9 = armv4_5->arch_info;
	arm_jtag_t *jtag_info = &arm7_9->jtag_info;
510

511
512
513
514
515
516
	/* LDMIA r0-15, [r0] at debug speed
	* register values will start to appear on 4th DCLK
	*/
	arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), NULL, 0);

	/* fetch NOP, LDM in DECODE stage */
517
	arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0);
518
	/* fetch NOP, LDM in EXECUTE stage (1st cycle) */
519
	arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0);
520
521
522
523
524

	for (i = 0; i <= 15; i++)
	{
		if (mask & (1 << i))
			/* nothing fetched, LDM still in EXECUTE (1+i cycle) */
525
			arm7tdmi_clock_out_inner(jtag_info, core_regs[i], 0);
526
	}
527
	arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0);
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
}

void arm7tdmi_load_word_regs(target_t *target, u32 mask)
{
	/* get pointers to arch-specific information */
	armv4_5_common_t *armv4_5 = target->arch_info;
	arm7_9_common_t *arm7_9 = armv4_5->arch_info;
	arm_jtag_t *jtag_info = &arm7_9->jtag_info;

	/* put system-speed load-multiple into the pipeline */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
	arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 1), NULL, 0);
}

void arm7tdmi_load_hword_reg(target_t *target, int num)
{
	/* get pointers to arch-specific information */
	armv4_5_common_t *armv4_5 = target->arch_info;
	arm7_9_common_t *arm7_9 = armv4_5->arch_info;
	arm_jtag_t *jtag_info = &arm7_9->jtag_info;
549

550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
	/* put system-speed load half-word into the pipeline */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
	arm7tdmi_clock_out(jtag_info, ARMV4_5_LDRH_IP(num, 0), NULL, 0);
}

void arm7tdmi_load_byte_reg(target_t *target, int num)
{
	/* get pointers to arch-specific information */
	armv4_5_common_t *armv4_5 = target->arch_info;
	arm7_9_common_t *arm7_9 = armv4_5->arch_info;
	arm_jtag_t *jtag_info = &arm7_9->jtag_info;

	/* put system-speed load byte into the pipeline */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
	arm7tdmi_clock_out(jtag_info, ARMV4_5_LDRB_IP(num, 0), NULL, 0);
}

void arm7tdmi_store_word_regs(target_t *target, u32 mask)
{
	/* get pointers to arch-specific information */
	armv4_5_common_t *armv4_5 = target->arch_info;
	arm7_9_common_t *arm7_9 = armv4_5->arch_info;
	arm_jtag_t *jtag_info = &arm7_9->jtag_info;

	/* put system-speed store-multiple into the pipeline */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
	arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask, 0, 1), NULL, 0);
}

void arm7tdmi_store_hword_reg(target_t *target, int num)
{
	/* get pointers to arch-specific information */
	armv4_5_common_t *armv4_5 = target->arch_info;
	arm7_9_common_t *arm7_9 = armv4_5->arch_info;
	arm_jtag_t *jtag_info = &arm7_9->jtag_info;

	/* put system-speed store half-word into the pipeline */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
	arm7tdmi_clock_out(jtag_info, ARMV4_5_STRH_IP(num, 0), NULL, 0);
}

void arm7tdmi_store_byte_reg(target_t *target, int num)
{
	/* get pointers to arch-specific information */
	armv4_5_common_t *armv4_5 = target->arch_info;
	arm7_9_common_t *arm7_9 = armv4_5->arch_info;
	arm_jtag_t *jtag_info = &arm7_9->jtag_info;

	/* put system-speed store byte into the pipeline */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
	arm7tdmi_clock_out(jtag_info, ARMV4_5_STRB_IP(num, 0), NULL, 0);
}

void arm7tdmi_write_pc(target_t *target, u32 pc)
{
	/* get pointers to arch-specific information */
	armv4_5_common_t *armv4_5 = target->arch_info;
	arm7_9_common_t *arm7_9 = armv4_5->arch_info;
	arm_jtag_t *jtag_info = &arm7_9->jtag_info;
614

615
616
617
618
619
	/* LDMIA r0-15, [r0] at debug speed
	 * register values will start to appear on 4th DCLK
	 */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x8000, 0, 0), NULL, 0);
	/* fetch NOP, LDM in DECODE stage */
620
	arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0);
621
	/* fetch NOP, LDM in EXECUTE stage (1st cycle) */
622
	arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0);
623
	/* nothing fetched, LDM in EXECUTE stage (1st cycle) load register */
624
	arm7tdmi_clock_out_inner(jtag_info, pc, 0);
625
	/* nothing fetched, LDM in EXECUTE stage (2nd cycle) load register */
626
	arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0);
627
	/* nothing fetched, LDM in EXECUTE stage (3rd cycle) load register */
628
	arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0);
629
	/* fetch NOP, LDM in EXECUTE stage (4th cycle) */
630
	arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0);
631
	/* fetch NOP, LDM in EXECUTE stage (5th cycle) */
632
	arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0);
633
634
635
636
637
638
639
640
}

void arm7tdmi_branch_resume(target_t *target)
{
	/* get pointers to arch-specific information */
	armv4_5_common_t *armv4_5 = target->arch_info;
	arm7_9_common_t *arm7_9 = armv4_5->arch_info;
	arm_jtag_t *jtag_info = &arm7_9->jtag_info;
641

642
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
643
	arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_B(0xfffffa, 0), 0);
644
645
646
647
}

void arm7tdmi_branch_resume_thumb(target_t *target)
{
648
	LOG_DEBUG("-");
649

650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
	/* get pointers to arch-specific information */
	armv4_5_common_t *armv4_5 = target->arch_info;
	arm7_9_common_t *arm7_9 = armv4_5->arch_info;
	arm_jtag_t *jtag_info = &arm7_9->jtag_info;
	reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT];

	/* LDMIA r0, [r0] at debug speed
	 * register values will start to appear on 4th DCLK
	 */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x1, 0, 0), NULL, 0);

	/* fetch NOP, LDM in DECODE stage */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
	/* fetch NOP, LDM in EXECUTE stage (1st cycle) */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
	/* nothing fetched, LDM in EXECUTE stage (2nd cycle) */
	arm7tdmi_clock_out(jtag_info, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32) | 1, NULL, 0);
	/* nothing fetched, LDM in EXECUTE stage (3rd cycle) */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);

	/* Branch and eXchange */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_BX(0), NULL, 0);
672

673
	embeddedice_read_reg(dbg_stat);
674

675
676
	/* fetch NOP, BX in DECODE stage */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
677

678
679
	/* target is now in Thumb state */
	embeddedice_read_reg(dbg_stat);
680

681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
	/* fetch NOP, BX in EXECUTE stage (1st cycle) */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);

	/* target is now in Thumb state */
	embeddedice_read_reg(dbg_stat);

	/* load r0 value */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), NULL, 0);
	/* fetch NOP, LDR in Decode */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
	/* fetch NOP, LDR in Execute */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
	/* nothing fetched, LDR in EXECUTE stage (2nd cycle) */
	arm7tdmi_clock_out(jtag_info, buf_get_u32(armv4_5->core_cache->reg_list[0].value, 0, 32), NULL, 0);
	/* nothing fetched, LDR in EXECUTE stage (3rd cycle) */
	arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
697

698
699
700
701
	arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
	arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);

	embeddedice_read_reg(dbg_stat);
702

703
704
705
	arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 1);
	arm7tdmi_clock_out(jtag_info, ARMV4_5_T_B(0x7f8), NULL, 0);
}
706

707
708
709
710
711
712
713
714
715
716
void arm7tdmi_build_reg_cache(target_t *target)
{
	reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache);
	/* get pointers to arch-specific information */
	armv4_5_common_t *armv4_5 = target->arch_info;

	(*cache_p) = armv4_5_build_reg_cache(target, armv4_5);
	armv4_5->core_cache = (*cache_p);
}

717
int arm7tdmi_examine(struct target_s *target)
718
{
oharboe's avatar
oharboe committed
719
720
721
	int retval;
	armv4_5_common_t *armv4_5 = target->arch_info;
	arm7_9_common_t *arm7_9 = armv4_5->arch_info;
722
	if (!target_was_examined(target))
oharboe's avatar
oharboe committed
723
724
725
726
727
728
	{
		/* get pointers to arch-specific information */
		reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache);
		reg_cache_t *t=embeddedice_build_reg_cache(target, arm7_9);
		if (t==NULL)
			return ERROR_FAIL;
729

oharboe's avatar
oharboe committed
730
731
		(*cache_p) = t;
		arm7_9->eice_cache = (*cache_p);
732

oharboe's avatar
oharboe committed
733
734
735
736
737
738
		if (arm7_9->etm_ctx)
		{
			arm_jtag_t *jtag_info = &arm7_9->jtag_info;
			(*cache_p)->next = etm_build_reg_cache(target, jtag_info, arm7_9->etm_ctx);
			arm7_9->etm_ctx->reg_cache = (*cache_p)->next;
		}
739
		target_set_examined(target);
oharboe's avatar
oharboe committed
740
741
742
	}
	if ((retval=embeddedice_setup(target))!=ERROR_OK)
		return retval;
743
744
	if ((retval=arm7_9_setup(target))!=ERROR_OK)
		return retval;
oharboe's avatar
oharboe committed
745
746
747
748
749
	if (arm7_9->etm_ctx)
	{
		if ((retval=etm_setup(target))!=ERROR_OK)
			return retval;
	}
750
751
752
	return ERROR_OK;
}

753
754
755
int arm7tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target)
{
	arm7tdmi_build_reg_cache(target);
756

757
758
759
	return ERROR_OK;
}

oharboe's avatar
oharboe committed
760
int arm7tdmi_quit(void)
761
762
763
764
{
	return ERROR_OK;
}

765
int arm7tdmi_init_arch_info(target_t *target, arm7tdmi_common_t *arm7tdmi, jtag_tap_t *tap)
766
767
768
{
	armv4_5_common_t *armv4_5;
	arm7_9_common_t *arm7_9;
769

770
771
	arm7_9 = &arm7tdmi->arm7_9_common;
	armv4_5 = &arm7_9->armv4_5_common;
772

773
	/* prepare JTAG information for the new target */
774
	arm7_9->jtag_info.tap = tap;
775
	arm7_9->jtag_info.scann_size = 4;
776

777
778
779
780
781
782
	/* register arch-specific functions */
	arm7_9->examine_debug_reason = arm7tdmi_examine_debug_reason;
	arm7_9->change_to_arm = arm7tdmi_change_to_arm;
	arm7_9->read_core_regs = arm7tdmi_read_core_regs;
	arm7_9->read_core_regs_target_buffer = arm7tdmi_read_core_regs_target_buffer;
	arm7_9->read_xpsr = arm7tdmi_read_xpsr;
783

784
785
786
	arm7_9->write_xpsr = arm7tdmi_write_xpsr;
	arm7_9->write_xpsr_im8 = arm7tdmi_write_xpsr_im8;
	arm7_9->write_core_regs = arm7tdmi_write_core_regs;
787

788
789
790
	arm7_9->load_word_regs = arm7tdmi_load_word_regs;
	arm7_9->load_hword_reg = arm7tdmi_load_hword_reg;
	arm7_9->load_byte_reg = arm7tdmi_load_byte_reg;
791

792
793
794
	arm7_9->store_word_regs = arm7tdmi_store_word_regs;
	arm7_9->store_hword_reg = arm7tdmi_store_hword_reg;
	arm7_9->store_byte_reg = arm7tdmi_store_byte_reg;
795

796
797
798
	arm7_9->write_pc = arm7tdmi_write_pc;
	arm7_9->branch_resume = arm7tdmi_branch_resume;
	arm7_9->branch_resume_thumb = arm7tdmi_branch_resume_thumb;
799

800
801
	arm7_9->enable_single_step = arm7_9_enable_eice_step;
	arm7_9->disable_single_step = arm7_9_disable_eice_step;
802

803
804
	arm7_9->pre_debug_entry = NULL;
	arm7_9->post_debug_entry = NULL;
805

806
807
	arm7_9->pre_restore_context = NULL;
	arm7_9->post_restore_context = NULL;
808

809
810
811
	/* initialize arch-specific breakpoint handling */
	arm7_9->arm_bkpt = 0xdeeedeee;
	arm7_9->thumb_bkpt = 0xdeee;
812

813
814
815
816
817
	arm7_9->dbgreq_adjust_pc = 2;
	arm7_9->arch_info = arm7tdmi;

	arm7tdmi->arch_info = NULL;
	arm7tdmi->common_magic = ARM7TDMI_COMMON_MAGIC;
818

819
820
821
822
823
	arm7_9_init_arch_info(target, arm7_9);

	return ERROR_OK;
}

824
int arm7tdmi_target_create( struct target_s *target, Jim_Interp *interp )
825
826
{
	arm7tdmi_common_t *arm7tdmi;
827

828
	arm7tdmi = calloc(1,sizeof(arm7tdmi_common_t));
829
	arm7tdmi_init_arch_info(target, arm7tdmi, target->tap);
830

831
832
833
	return ERROR_OK;
}

834
835
836
int arm7tdmi_register_commands(struct command_context_s *cmd_ctx)
{
	int retval;
837

838
	retval = arm7_9_register_commands(cmd_ctx);
839

840
	return retval;
841
}