mips_m4k.c 27.5 KB
Newer Older
ntfreak's avatar
ntfreak committed
1
2
3
4
5
6
/***************************************************************************
 *   Copyright (C) 2008 by Spencer Oliver                                  *
 *   spen@spen-soft.co.uk                                                  *
 *                                                                         *
 *   Copyright (C) 2008 by David T.L. Wong                                 *
 *                                                                         *
7
8
 *   Copyright (C) 2009 by David N. Claffey <dnclaffey@gmail.com>          *
 *                                                                         *
ntfreak's avatar
ntfreak committed
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 *   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

28
#include "breakpoints.h"
ntfreak's avatar
ntfreak committed
29
30
#include "mips32.h"
#include "mips_m4k.h"
31
#include "mips32_dmaacc.h"
32
#include "target_type.h"
33
#include "register.h"
ntfreak's avatar
ntfreak committed
34

Zachary T Welch's avatar
Zachary T Welch committed
35
int mips_m4k_examine_debug_reason(struct target *target)
36
{
37
	uint32_t break_status;
38
	int retval;
39

40
41
42
43
44
45
46
47
48
49
50
51
52
	if ((target->debug_reason != DBG_REASON_DBGRQ)
		&& (target->debug_reason != DBG_REASON_SINGLESTEP))
	{
		/* get info about inst breakpoint support */
		if ((retval = target_read_u32(target, EJTAG_IBS, &break_status)) != ERROR_OK)
			return retval;
		if (break_status & 0x1f)
		{
			/* we have halted on a  breakpoint */
			if ((retval = target_write_u32(target, EJTAG_IBS, 0)) != ERROR_OK)
				return retval;
			target->debug_reason = DBG_REASON_BREAKPOINT;
		}
53

54
		/* get info about data breakpoint support */
55
		if ((retval = target_read_u32(target, EJTAG_DBS, &break_status)) != ERROR_OK)
56
57
58
59
			return retval;
		if (break_status & 0x1f)
		{
			/* we have halted on a  breakpoint */
60
			if ((retval = target_write_u32(target, EJTAG_DBS, 0)) != ERROR_OK)
61
62
63
64
				return retval;
			target->debug_reason = DBG_REASON_WATCHPOINT;
		}
	}
65

66
67
68
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
69
int mips_m4k_debug_entry(struct target *target)
ntfreak's avatar
ntfreak committed
70
{
71
	struct mips32_common *mips32 = target_to_mips32(target);
72
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
73
	uint32_t debug_reg;
74

ntfreak's avatar
ntfreak committed
75
76
	/* read debug register */
	mips_ejtag_read_debug(ejtag_info, &debug_reg);
77

78
	/* make sure break unit configured */
79
	mips32_configure_break_unit(target);
80

81
82
	/* attempt to find halt reason */
	mips_m4k_examine_debug_reason(target);
83

84
	/* clear single step if active */
ntfreak's avatar
ntfreak committed
85
86
87
88
89
	if (debug_reg & EJTAG_DEBUG_DSS)
	{
		/* stopped due to single step - clear step bit */
		mips_ejtag_config_step(ejtag_info, 0);
	}
90

ntfreak's avatar
ntfreak committed
91
	mips32_save_context(target);
92

93
94
95
	/* default to mips32 isa, it will be changed below if required */
	mips32->isa_mode = MIPS32_ISA_MIPS32;

96
97
	if (ejtag_info->impcode & EJTAG_IMP_MIPS16) {
		mips32->isa_mode = buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 1);
98
99
	}

duane's avatar
duane committed
100
	LOG_DEBUG("entered debug state at PC 0x%" PRIx32 ", target->state: %s",
101
102
			buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32),
			target_state_name(target));
103

ntfreak's avatar
ntfreak committed
104
105
106
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
107
int mips_m4k_poll(struct target *target)
ntfreak's avatar
ntfreak committed
108
109
{
	int retval;
110
	struct mips32_common *mips32 = target_to_mips32(target);
111
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
112
	uint32_t ejtag_ctrl = ejtag_info->ejtag_ctrl;
113

ntfreak's avatar
ntfreak committed
114
	/* read ejtag control reg */
115
	jtag_set_end_state(TAP_IDLE);
ntfreak's avatar
ntfreak committed
116
	mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL, NULL);
117
	mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
118

119
120
121
122
123
124
	/* clear this bit before handling polling
	 * as after reset registers will read zero */
	if (ejtag_ctrl & EJTAG_CTRL_ROCC)
	{
		/* we have detected a reset, clear flag
		 * otherwise ejtag will not work */
125
		jtag_set_end_state(TAP_IDLE);
126
		ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_ROCC;
127

128
129
130
131
		mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL, NULL);
		mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
		LOG_DEBUG("Reset Detected");
	}
132

133
	/* check for processor halted */
134
	if (ejtag_ctrl & EJTAG_CTRL_BRKST)
ntfreak's avatar
ntfreak committed
135
136
137
	{
		if ((target->state == TARGET_RUNNING) || (target->state == TARGET_RESET))
		{
138
			jtag_set_end_state(TAP_IDLE);
ntfreak's avatar
ntfreak committed
139
			mips_ejtag_set_instr(ejtag_info, EJTAG_INST_NORMALBOOT, NULL);
140

ntfreak's avatar
ntfreak committed
141
			target->state = TARGET_HALTED;
142

ntfreak's avatar
ntfreak committed
143
144
			if ((retval = mips_m4k_debug_entry(target)) != ERROR_OK)
				return retval;
145

ntfreak's avatar
ntfreak committed
146
147
148
149
150
			target_call_event_callbacks(target, TARGET_EVENT_HALTED);
		}
		else if (target->state == TARGET_DEBUG_RUNNING)
		{
			target->state = TARGET_HALTED;
151

ntfreak's avatar
ntfreak committed
152
153
			if ((retval = mips_m4k_debug_entry(target)) != ERROR_OK)
				return retval;
154

ntfreak's avatar
ntfreak committed
155
156
157
158
159
160
161
			target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
		}
	}
	else
	{
		target->state = TARGET_RUNNING;
	}
162

zwelch's avatar
zwelch committed
163
//	LOG_DEBUG("ctrl = 0x%08X", ejtag_ctrl);
164

ntfreak's avatar
ntfreak committed
165
166
167
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
168
int mips_m4k_halt(struct target *target)
ntfreak's avatar
ntfreak committed
169
{
170
	struct mips32_common *mips32 = target_to_mips32(target);
171
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
172
173

	LOG_DEBUG("target->state: %s",
174
		  target_state_name(target));
175

ntfreak's avatar
ntfreak committed
176
177
178
179
180
	if (target->state == TARGET_HALTED)
	{
		LOG_DEBUG("target was already halted");
		return ERROR_OK;
	}
181

ntfreak's avatar
ntfreak committed
182
183
184
185
	if (target->state == TARGET_UNKNOWN)
	{
		LOG_WARNING("target was in unknown state when halt was requested");
	}
186
187

	if (target->state == TARGET_RESET)
ntfreak's avatar
ntfreak committed
188
	{
189
		if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) && jtag_get_srst())
ntfreak's avatar
ntfreak committed
190
191
192
193
194
195
196
197
198
199
		{
			LOG_ERROR("can't request a halt while in reset if nSRST pulls nTRST");
			return ERROR_TARGET_FAILURE;
		}
		else
		{
			/* we came here in a reset_halt or reset_init sequence
			 * debug entry was already prepared in mips32_prepare_reset_halt()
			 */
			target->debug_reason = DBG_REASON_DBGRQ;
200

ntfreak's avatar
ntfreak committed
201
202
203
			return ERROR_OK;
		}
	}
204

ntfreak's avatar
ntfreak committed
205
206
	/* break processor */
	mips_ejtag_enter_debug(ejtag_info);
207

ntfreak's avatar
ntfreak committed
208
	target->debug_reason = DBG_REASON_DBGRQ;
209

ntfreak's avatar
ntfreak committed
210
211
212
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
213
int mips_m4k_assert_reset(struct target *target)
ntfreak's avatar
ntfreak committed
214
{
215
	struct mips32_common *mips32 = target_to_mips32(target);
216
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
217
218

	LOG_DEBUG("target->state: %s",
219
		target_state_name(target));
220

221
	enum reset_types jtag_reset_config = jtag_get_reset_config();
ntfreak's avatar
ntfreak committed
222
223
224
225
226
	if (!(jtag_reset_config & RESET_HAS_SRST))
	{
		LOG_ERROR("Can't assert SRST");
		return ERROR_FAIL;
	}
227

ntfreak's avatar
ntfreak committed
228
229
230
	if (target->reset_halt)
	{
		/* use hardware to catch reset */
231
		jtag_set_end_state(TAP_IDLE);
ntfreak's avatar
ntfreak committed
232
233
234
235
		mips_ejtag_set_instr(ejtag_info, EJTAG_INST_EJTAGBOOT, NULL);
	}
	else
	{
236
		jtag_set_end_state(TAP_IDLE);
ntfreak's avatar
ntfreak committed
237
238
		mips_ejtag_set_instr(ejtag_info, EJTAG_INST_NORMALBOOT, NULL);
	}
239

240
	if (strcmp(target->variant, "ejtag_srst") == 0)
ntfreak's avatar
ntfreak committed
241
	{
242
		uint32_t ejtag_ctrl = ejtag_info->ejtag_ctrl | EJTAG_CTRL_PRRST | EJTAG_CTRL_PERRST;
243
244
245
		LOG_DEBUG("Using EJTAG reset (PRRST) to reset processor...");
		mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL, NULL);
		mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
ntfreak's avatar
ntfreak committed
246
247
248
	}
	else
	{
249
250
251
252
253
254
255
256
257
		/* here we should issue a srst only, but we may have to assert trst as well */
		if (jtag_reset_config & RESET_SRST_PULLS_TRST)
		{
			jtag_add_reset(1, 1);
		}
		else
		{
			jtag_add_reset(0, 1);
		}
ntfreak's avatar
ntfreak committed
258
	}
259

ntfreak's avatar
ntfreak committed
260
261
262
	target->state = TARGET_RESET;
	jtag_add_sleep(50000);

263
	register_cache_invalidate(mips32->core_cache);
ntfreak's avatar
ntfreak committed
264

ntfreak's avatar
ntfreak committed
265
266
267
	if (target->reset_halt)
	{
		int retval;
zwelch's avatar
zwelch committed
268
		if ((retval = target_halt(target)) != ERROR_OK)
269
			return retval;
ntfreak's avatar
ntfreak committed
270
	}
271

ntfreak's avatar
ntfreak committed
272
273
274
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
275
int mips_m4k_deassert_reset(struct target *target)
ntfreak's avatar
ntfreak committed
276
{
277
	LOG_DEBUG("target->state: %s",
278
		target_state_name(target));
279

ntfreak's avatar
ntfreak committed
280
281
	/* deassert reset lines */
	jtag_add_reset(0, 0);
282

ntfreak's avatar
ntfreak committed
283
284
285
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
286
int mips_m4k_soft_reset_halt(struct target *target)
ntfreak's avatar
ntfreak committed
287
288
289
290
291
{
	/* TODO */
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
292
int mips_m4k_single_step_core(struct target *target)
293
{
294
	struct mips32_common *mips32 = target_to_mips32(target);
295
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
296

297
298
	/* configure single step mode */
	mips_ejtag_config_step(ejtag_info, 1);
299

300
301
	/* disable interrupts while stepping */
	mips32_enable_interrupts(target, 0);
302

303
	/* exit debug mode */
304
	mips_ejtag_exit_debug(ejtag_info);
305

306
	mips_m4k_debug_entry(target);
307

308
309
310
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
311
int mips_m4k_resume(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution)
ntfreak's avatar
ntfreak committed
312
{
313
	struct mips32_common *mips32 = target_to_mips32(target);
314
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
315
	struct breakpoint *breakpoint = NULL;
316
	uint32_t resume_pc;
317

ntfreak's avatar
ntfreak committed
318
319
320
321
322
	if (target->state != TARGET_HALTED)
	{
		LOG_WARNING("target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}
323

ntfreak's avatar
ntfreak committed
324
325
326
327
328
329
	if (!debug_execution)
	{
		target_free_all_working_areas(target);
		mips_m4k_enable_breakpoints(target);
		mips_m4k_enable_watchpoints(target);
	}
330

ntfreak's avatar
ntfreak committed
331
	/* current = 1: continue on current pc, otherwise continue at <address> */
ntfreak's avatar
ntfreak committed
332
	if (!current)
ntfreak's avatar
ntfreak committed
333
334
335
336
337
	{
		buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32, address);
		mips32->core_cache->reg_list[MIPS32_PC].dirty = 1;
		mips32->core_cache->reg_list[MIPS32_PC].valid = 1;
	}
338

339
340
341
342
	if (ejtag_info->impcode & EJTAG_IMP_MIPS16) {
		buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 1, mips32->isa_mode);
	}

ntfreak's avatar
ntfreak committed
343
	resume_pc = buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32);
344

ntfreak's avatar
ntfreak committed
345
	mips32_restore_context(target);
346

ntfreak's avatar
ntfreak committed
347
348
349
350
351
352
	/* the front-end may request us not to handle breakpoints */
	if (handle_breakpoints)
	{
		/* Single step past breakpoint at current address */
		if ((breakpoint = breakpoint_find(target, resume_pc)))
		{
duane's avatar
duane committed
353
			LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 "", breakpoint->address);
ntfreak's avatar
ntfreak committed
354
			mips_m4k_unset_breakpoint(target, breakpoint);
355
			mips_m4k_single_step_core(target);
ntfreak's avatar
ntfreak committed
356
357
358
			mips_m4k_set_breakpoint(target, breakpoint);
		}
	}
359

360
361
	/* enable interrupts if we are running */
	mips32_enable_interrupts(target, !debug_execution);
362

363
364
	/* exit debug mode */
	mips_ejtag_exit_debug(ejtag_info);
365
	target->debug_reason = DBG_REASON_NOTHALTED;
366

ntfreak's avatar
ntfreak committed
367
	/* registers are now invalid */
368
	register_cache_invalidate(mips32->core_cache);
369

ntfreak's avatar
ntfreak committed
370
371
372
373
	if (!debug_execution)
	{
		target->state = TARGET_RUNNING;
		target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
duane's avatar
duane committed
374
		LOG_DEBUG("target resumed at 0x%" PRIx32 "", resume_pc);
ntfreak's avatar
ntfreak committed
375
376
377
378
379
	}
	else
	{
		target->state = TARGET_DEBUG_RUNNING;
		target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED);
duane's avatar
duane committed
380
		LOG_DEBUG("target debug resumed at 0x%" PRIx32 "", resume_pc);
ntfreak's avatar
ntfreak committed
381
	}
382

ntfreak's avatar
ntfreak committed
383
384
385
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
386
int mips_m4k_step(struct target *target, int current, uint32_t address, int handle_breakpoints)
ntfreak's avatar
ntfreak committed
387
388
{
	/* get pointers to arch-specific information */
389
	struct mips32_common *mips32 = target_to_mips32(target);
390
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
391
	struct breakpoint *breakpoint = NULL;
ntfreak's avatar
ntfreak committed
392
393
394
395
396
397
398
399
400
401

	if (target->state != TARGET_HALTED)
	{
		LOG_WARNING("target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	/* current = 1: continue on current pc, otherwise continue at <address> */
	if (!current)
		buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32, address);
402

ntfreak's avatar
ntfreak committed
403
	/* the front-end may request us not to handle breakpoints */
404
405
406
407
	if (handle_breakpoints) {
		breakpoint = breakpoint_find(target,
				buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32));
		if (breakpoint)
ntfreak's avatar
ntfreak committed
408
			mips_m4k_unset_breakpoint(target, breakpoint);
409
	}
410

ntfreak's avatar
ntfreak committed
411
412
	/* restore context */
	mips32_restore_context(target);
413

ntfreak's avatar
ntfreak committed
414
415
	/* configure single step mode */
	mips_ejtag_config_step(ejtag_info, 1);
416

ntfreak's avatar
ntfreak committed
417
	target->debug_reason = DBG_REASON_SINGLESTEP;
418

ntfreak's avatar
ntfreak committed
419
	target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
420

421
422
	/* disable interrupts while stepping */
	mips32_enable_interrupts(target, 0);
423

ntfreak's avatar
ntfreak committed
424
	/* exit debug mode */
425
	mips_ejtag_exit_debug(ejtag_info);
426

ntfreak's avatar
ntfreak committed
427
	/* registers are now invalid */
428
	register_cache_invalidate(mips32->core_cache);
429

ntfreak's avatar
ntfreak committed
430
431
432
433
	if (breakpoint)
		mips_m4k_set_breakpoint(target, breakpoint);

	LOG_DEBUG("target stepped ");
434

ntfreak's avatar
ntfreak committed
435
436
	mips_m4k_debug_entry(target);
	target_call_event_callbacks(target, TARGET_EVENT_HALTED);
437

ntfreak's avatar
ntfreak committed
438
439
440
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
441
void mips_m4k_enable_breakpoints(struct target *target)
ntfreak's avatar
ntfreak committed
442
{
443
	struct breakpoint *breakpoint = target->breakpoints;
444

ntfreak's avatar
ntfreak committed
445
446
447
448
449
450
451
452
453
	/* set any pending breakpoints */
	while (breakpoint)
	{
		if (breakpoint->set == 0)
			mips_m4k_set_breakpoint(target, breakpoint);
		breakpoint = breakpoint->next;
	}
}

Zachary T Welch's avatar
Zachary T Welch committed
454
int mips_m4k_set_breakpoint(struct target *target, struct breakpoint *breakpoint)
ntfreak's avatar
ntfreak committed
455
{
456
	struct mips32_common *mips32 = target_to_mips32(target);
457
	struct mips32_comparator * comparator_list = mips32->inst_break_list;
458
	int retval;
459

460
461
462
463
464
	if (breakpoint->set)
	{
		LOG_WARNING("breakpoint already set");
		return ERROR_OK;
	}
465

466
467
468
	if (breakpoint->type == BKPT_HARD)
	{
		int bp_num = 0;
469

zwelch's avatar
zwelch committed
470
		while (comparator_list[bp_num].used && (bp_num < mips32->num_inst_bpoints))
471
472
473
			bp_num++;
		if (bp_num >= mips32->num_inst_bpoints)
		{
David Brownell's avatar
David Brownell committed
474
			LOG_ERROR("Can not find free FP Comparator(bpid: %d)",
475
					  breakpoint->unique_id );
David Brownell's avatar
David Brownell committed
476
			return ERROR_FAIL;
477
478
479
480
481
482
483
		}
		breakpoint->set = bp_num + 1;
		comparator_list[bp_num].used = 1;
		comparator_list[bp_num].bp_value = breakpoint->address;
		target_write_u32(target, comparator_list[bp_num].reg_address, comparator_list[bp_num].bp_value);
		target_write_u32(target, comparator_list[bp_num].reg_address + 0x08, 0x00000000);
		target_write_u32(target, comparator_list[bp_num].reg_address + 0x18, 1);
484
		LOG_DEBUG("bpid: %d, bp_num %i bp_value 0x%" PRIx32 "",
485
486
				  breakpoint->unique_id,
				  bp_num, comparator_list[bp_num].bp_value);
487
488
489
	}
	else if (breakpoint->type == BKPT_SOFT)
	{
490
		LOG_DEBUG("bpid: %d", breakpoint->unique_id );
491
492
		if (breakpoint->length == 4)
		{
493
			uint32_t verify = 0xffffffff;
494

495
496
			if ((retval = target_read_memory(target, breakpoint->address, breakpoint->length, 1,
					breakpoint->orig_instr)) != ERROR_OK)
497
498
499
500
501
502
503
			{
				return retval;
			}
			if ((retval = target_write_u32(target, breakpoint->address, MIPS32_SDBBP)) != ERROR_OK)
			{
				return retval;
			}
504

505
506
507
508
509
510
			if ((retval = target_read_u32(target, breakpoint->address, &verify)) != ERROR_OK)
			{
				return retval;
			}
			if (verify != MIPS32_SDBBP)
			{
duane's avatar
duane committed
511
				LOG_ERROR("Unable to set 32bit breakpoint at address %08" PRIx32 " - check that memory is read/writable", breakpoint->address);
512
513
514
515
516
				return ERROR_OK;
			}
		}
		else
		{
zwelch's avatar
zwelch committed
517
			uint16_t verify = 0xffff;
518

519
520
			if ((retval = target_read_memory(target, breakpoint->address, breakpoint->length, 1,
					breakpoint->orig_instr)) != ERROR_OK)
521
522
523
524
525
526
527
			{
				return retval;
			}
			if ((retval = target_write_u16(target, breakpoint->address, MIPS16_SDBBP)) != ERROR_OK)
			{
				return retval;
			}
528

529
530
531
532
533
534
			if ((retval = target_read_u16(target, breakpoint->address, &verify)) != ERROR_OK)
			{
				return retval;
			}
			if (verify != MIPS16_SDBBP)
			{
duane's avatar
duane committed
535
				LOG_ERROR("Unable to set 16bit breakpoint at address %08" PRIx32 " - check that memory is read/writable", breakpoint->address);
536
537
538
				return ERROR_OK;
			}
		}
539

540
		breakpoint->set = 20; /* Any nice value but 0 */
541
	}
542

ntfreak's avatar
ntfreak committed
543
544
545
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
546
int mips_m4k_unset_breakpoint(struct target *target, struct breakpoint *breakpoint)
ntfreak's avatar
ntfreak committed
547
{
548
	/* get pointers to arch-specific information */
549
550
	struct mips32_common *mips32 = target_to_mips32(target);
	struct mips32_comparator *comparator_list = mips32->inst_break_list;
551
	int retval;
552

553
554
555
556
557
	if (!breakpoint->set)
	{
		LOG_WARNING("breakpoint not set");
		return ERROR_OK;
	}
558

559
560
561
562
563
	if (breakpoint->type == BKPT_HARD)
	{
		int bp_num = breakpoint->set - 1;
		if ((bp_num < 0) || (bp_num >= mips32->num_inst_bpoints))
		{
564
565
			LOG_DEBUG("Invalid FP Comparator number in breakpoint (bpid: %d)",
					  breakpoint->unique_id);
566
567
			return ERROR_OK;
		}
568
569
570
		LOG_DEBUG("bpid: %d - releasing hw: %d",
				  breakpoint->unique_id,
				  bp_num );
571
572
573
		comparator_list[bp_num].used = 0;
		comparator_list[bp_num].bp_value = 0;
		target_write_u32(target, comparator_list[bp_num].reg_address + 0x18, 0);
574

575
576
577
	}
	else
	{
578
		/* restore original instruction (kept in target endianness) */
579
		LOG_DEBUG("bpid: %d", breakpoint->unique_id);
580
581
		if (breakpoint->length == 4)
		{
582
			uint32_t current_instr;
583

584
			/* check that user program has not modified breakpoint instruction */
585
586
			if ((retval = target_read_memory(target, breakpoint->address, 4, 1,
					(uint8_t*)&current_instr)) != ERROR_OK)
587
588
589
590
591
			{
				return retval;
			}
			if (current_instr == MIPS32_SDBBP)
			{
592
593
				if ((retval = target_write_memory(target, breakpoint->address, 4, 1,
						breakpoint->orig_instr)) != ERROR_OK)
594
595
596
597
598
599
600
				{
					return retval;
				}
			}
		}
		else
		{
zwelch's avatar
zwelch committed
601
			uint16_t current_instr;
602

603
			/* check that user program has not modified breakpoint instruction */
604
605
			if ((retval = target_read_memory(target, breakpoint->address, 2, 1,
					(uint8_t*)&current_instr)) != ERROR_OK)
606
607
608
			{
				return retval;
			}
609

610
611
			if (current_instr == MIPS16_SDBBP)
			{
612
613
				if ((retval = target_write_memory(target, breakpoint->address, 2, 1,
						breakpoint->orig_instr)) != ERROR_OK)
614
615
616
617
618
				{
					return retval;
				}
			}
		}
619
620
	}
	breakpoint->set = 0;
621

ntfreak's avatar
ntfreak committed
622
623
624
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
625
int mips_m4k_add_breakpoint(struct target *target, struct breakpoint *breakpoint)
ntfreak's avatar
ntfreak committed
626
{
627
	struct mips32_common *mips32 = target_to_mips32(target);
628

629
	if (breakpoint->type == BKPT_HARD)
630
	{
631
632
633
634
635
		if (mips32->num_inst_bpoints_avail < 1)
		{
			LOG_INFO("no hardware breakpoint available");
			return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
		}
636

637
		mips32->num_inst_bpoints_avail--;
638
	}
639

640
	mips_m4k_set_breakpoint(target, breakpoint);
641

ntfreak's avatar
ntfreak committed
642
643
644
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
645
int mips_m4k_remove_breakpoint(struct target *target, struct breakpoint *breakpoint)
ntfreak's avatar
ntfreak committed
646
{
647
	/* get pointers to arch-specific information */
648
	struct mips32_common *mips32 = target_to_mips32(target);
649

650
651
652
653
654
	if (target->state != TARGET_HALTED)
	{
		LOG_WARNING("target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}
655

656
657
658
659
	if (breakpoint->set)
	{
		mips_m4k_unset_breakpoint(target, breakpoint);
	}
660

661
662
	if (breakpoint->type == BKPT_HARD)
		mips32->num_inst_bpoints_avail++;
663

ntfreak's avatar
ntfreak committed
664
665
666
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
667
int mips_m4k_set_watchpoint(struct target *target, struct watchpoint *watchpoint)
ntfreak's avatar
ntfreak committed
668
{
669
670
	struct mips32_common *mips32 = target_to_mips32(target);
	struct mips32_comparator *comparator_list = mips32->data_break_list;
671
672
673
674
675
676
	int wp_num = 0;
	/*
	 * watchpoint enabled, ignore all byte lanes in value register
	 * and exclude both load and store accesses from  watchpoint
	 * condition evaluation
	*/
677
	int enable = EJTAG_DBCn_NOSB | EJTAG_DBCn_NOLB | EJTAG_DBCn_BE |
678
                (0xff << EJTAG_DBCn_BLM_SHIFT);
679

680
681
682
683
684
685
686
687
688
689
	if (watchpoint->set)
	{
		LOG_WARNING("watchpoint already set");
		return ERROR_OK;
	}

	while(comparator_list[wp_num].used && (wp_num < mips32->num_data_bpoints))
		wp_num++;
	if (wp_num >= mips32->num_data_bpoints)
	{
David Brownell's avatar
David Brownell committed
690
691
		LOG_ERROR("Can not find free FP Comparator");
		return ERROR_FAIL;
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
	}

	if (watchpoint->length != 4)
	{
		LOG_ERROR("Only watchpoints of length 4 are supported");
		return ERROR_TARGET_UNALIGNED_ACCESS;
	}

	if (watchpoint->address % 4)
	{
		LOG_ERROR("Watchpoints address should be word aligned");
		return ERROR_TARGET_UNALIGNED_ACCESS;
	}

	switch (watchpoint->rw)
	{
		case WPT_READ:
			enable &= ~EJTAG_DBCn_NOLB;
			break;
		case WPT_WRITE:
			enable &= ~EJTAG_DBCn_NOSB;
			break;
		case WPT_ACCESS:
			enable &= ~(EJTAG_DBCn_NOLB | EJTAG_DBCn_NOSB);
			break;
		default:
			LOG_ERROR("BUG: watchpoint->rw neither read, write nor access");
	}

	watchpoint->set = wp_num + 1;
	comparator_list[wp_num].used = 1;
	comparator_list[wp_num].bp_value = watchpoint->address;
	target_write_u32(target, comparator_list[wp_num].reg_address, comparator_list[wp_num].bp_value);
	target_write_u32(target, comparator_list[wp_num].reg_address + 0x08, 0x00000000);
	target_write_u32(target, comparator_list[wp_num].reg_address + 0x10, 0x00000000);
	target_write_u32(target, comparator_list[wp_num].reg_address + 0x18, enable);
	target_write_u32(target, comparator_list[wp_num].reg_address + 0x20, 0);
	LOG_DEBUG("wp_num %i bp_value 0x%" PRIx32 "", wp_num, comparator_list[wp_num].bp_value);
730

ntfreak's avatar
ntfreak committed
731
732
733
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
734
int mips_m4k_unset_watchpoint(struct target *target, struct watchpoint *watchpoint)
ntfreak's avatar
ntfreak committed
735
{
736
	/* get pointers to arch-specific information */
737
738
	struct mips32_common *mips32 = target_to_mips32(target);
	struct mips32_comparator *comparator_list = mips32->data_break_list;
739

740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
	if (!watchpoint->set)
	{
		LOG_WARNING("watchpoint not set");
		return ERROR_OK;
	}

	int wp_num = watchpoint->set - 1;
	if ((wp_num < 0) || (wp_num >= mips32->num_data_bpoints))
	{
		LOG_DEBUG("Invalid FP Comparator number in watchpoint");
		return ERROR_OK;
	}
	comparator_list[wp_num].used = 0;
	comparator_list[wp_num].bp_value = 0;
	target_write_u32(target, comparator_list[wp_num].reg_address + 0x18, 0);
	watchpoint->set = 0;

ntfreak's avatar
ntfreak committed
757
758
759
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
760
int mips_m4k_add_watchpoint(struct target *target, struct watchpoint *watchpoint)
ntfreak's avatar
ntfreak committed
761
{
762
	struct mips32_common *mips32 = target_to_mips32(target);
763
764
765
766
767
768

	if (mips32->num_data_bpoints_avail < 1)
	{
		LOG_INFO("no hardware watchpoints available");
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	}
769

770
771
772
	mips32->num_data_bpoints_avail--;

	mips_m4k_set_watchpoint(target, watchpoint);
ntfreak's avatar
ntfreak committed
773
774
775
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
776
int mips_m4k_remove_watchpoint(struct target *target, struct watchpoint *watchpoint)
ntfreak's avatar
ntfreak committed
777
{
778
	/* get pointers to arch-specific information */
779
	struct mips32_common *mips32 = target_to_mips32(target);
780
781
782
783
784
785
786
787
788
789
790
791
792
793

	if (target->state != TARGET_HALTED)
	{
		LOG_WARNING("target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	if (watchpoint->set)
	{
		mips_m4k_unset_watchpoint(target, watchpoint);
	}

	mips32->num_data_bpoints_avail++;

ntfreak's avatar
ntfreak committed
794
795
796
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
797
void mips_m4k_enable_watchpoints(struct target *target)
ntfreak's avatar
ntfreak committed
798
{
799
	struct watchpoint *watchpoint = target->watchpoints;
800

ntfreak's avatar
ntfreak committed
801
802
803
804
805
806
807
808
809
	/* set any pending watchpoints */
	while (watchpoint)
	{
		if (watchpoint->set == 0)
			mips_m4k_set_watchpoint(target, watchpoint);
		watchpoint = watchpoint->next;
	}
}

Zachary T Welch's avatar
Zachary T Welch committed
810
int mips_m4k_read_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
ntfreak's avatar
ntfreak committed
811
{
812
	struct mips32_common *mips32 = target_to_mips32(target);
813
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
814

duane's avatar
duane committed
815
	LOG_DEBUG("address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", address, size, count);
ntfreak's avatar
ntfreak committed
816
817
818
819
820
821
822
823
824
825
826
827
828

	if (target->state != TARGET_HALTED)
	{
		LOG_WARNING("target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	/* sanitize arguments */
	if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer))
		return ERROR_INVALID_ARGUMENTS;

	if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))
		return ERROR_TARGET_UNALIGNED_ACCESS;
829

830
831
	/* if noDMA off, use DMAACC mode for memory read */
	int retval;
zwelch's avatar
zwelch committed
832
	if (ejtag_info->impcode & EJTAG_IMP_NODMA)
833
834
835
836
837
		retval = mips32_pracc_read_mem(ejtag_info, address, size, count, (void *)buffer);
	else
		retval = mips32_dmaacc_read_mem(ejtag_info, address, size, count, (void *)buffer);
	if (ERROR_OK != retval)
		return retval;
ntfreak's avatar
ntfreak committed
838

839
	return ERROR_OK;
ntfreak's avatar
ntfreak committed
840
841
}

842
843
int mips_m4k_write_memory(struct target *target, uint32_t address, uint32_t size,
		uint32_t count, uint8_t *buffer)
ntfreak's avatar
ntfreak committed
844
{
845
	struct mips32_common *mips32 = target_to_mips32(target);
846
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
847

848
849
	LOG_DEBUG("address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "",
			address, size, count);
ntfreak's avatar
ntfreak committed
850
851
852
853
854
855
856
857
858
859
860
861
862

	if (target->state != TARGET_HALTED)
	{
		LOG_WARNING("target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	/* sanitize arguments */
	if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer))
		return ERROR_INVALID_ARGUMENTS;

	if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))
		return ERROR_TARGET_UNALIGNED_ACCESS;
863

864
	/* if noDMA off, use DMAACC mode for memory write */
zwelch's avatar
zwelch committed
865
	if (ejtag_info->impcode & EJTAG_IMP_NODMA)
866
		return mips32_pracc_write_mem(ejtag_info, address, size, count, (void *)buffer);
zwelch's avatar
zwelch committed
867
	else
868
		return mips32_dmaacc_write_mem(ejtag_info, address, size, count, (void *)buffer);
ntfreak's avatar
ntfreak committed
869
870
}

871
int mips_m4k_init_target(struct command_context *cmd_ctx, struct target *target)
ntfreak's avatar
ntfreak committed
872
873
{
	mips32_build_reg_cache(target);
874

ntfreak's avatar
ntfreak committed
875
876
877
	return ERROR_OK;
}

878
879
int mips_m4k_init_arch_info(struct target *target, struct mips_m4k_common *mips_m4k,
		struct jtag_tap *tap)
ntfreak's avatar
ntfreak committed
880
{
881
	struct mips32_common *mips32 = &mips_m4k->mips32_common;
882

ntfreak's avatar
ntfreak committed
883
	mips_m4k->common_magic = MIPSM4K_COMMON_MAGIC;
884

ntfreak's avatar
ntfreak committed
885
	/* initialize mips4k specific info */
886
	mips32_init_arch_info(target, mips32, tap);
ntfreak's avatar
ntfreak committed
887
	mips32->arch_info = mips_m4k;
888

ntfreak's avatar
ntfreak committed
889
890
891
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
892
int mips_m4k_target_create(struct target *target, Jim_Interp *interp)
ntfreak's avatar
ntfreak committed
893
{
894
	struct mips_m4k_common *mips_m4k = calloc(1, sizeof(struct mips_m4k_common));
895

896
	mips_m4k_init_arch_info(target, mips_m4k, target->tap);
897

ntfreak's avatar
ntfreak committed
898
899
900
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
901
int mips_m4k_examine(struct target *target)
ntfreak's avatar
ntfreak committed
902
903
{
	int retval;
904
	struct mips32_common *mips32 = target_to_mips32(target);
905
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
906
	uint32_t idcode = 0;
907

908
	if (!target_was_examined(target))
ntfreak's avatar
ntfreak committed
909
	{
910
		mips_ejtag_get_idcode(ejtag_info, &idcode);
911
		ejtag_info->idcode = idcode;
912

913
914
915
916
917
918
919
		if (((idcode >> 1) & 0x7FF) == 0x29)
		{
			/* we are using a pic32mx so select ejtag port
			 * as it is not selected by default */
			mips_ejtag_set_instr(ejtag_info, 0x05, NULL);
			LOG_DEBUG("PIC32MX Detected - using EJTAG Interface");
		}
ntfreak's avatar
ntfreak committed
920
	}
921

ntfreak's avatar
ntfreak committed
922
923
924
	/* init rest of ejtag interface */
	if ((retval = mips_ejtag_init(ejtag_info)) != ERROR_OK)
		return retval;
925

926
927
	if ((retval = mips32_examine(target)) != ERROR_OK)
		return retval;
928

ntfreak's avatar
ntfreak committed
929
930
931
	return ERROR_OK;
}

932
933
int mips_m4k_bulk_write_memory(struct target *target, uint32_t address,
		uint32_t count, uint8_t *buffer)
ntfreak's avatar
ntfreak committed
934
{
935
	struct mips32_common *mips32 = target_to_mips32(target);
936
937
938
939
940
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
	struct working_area *source;
	int retval;
	int write = 1;

941
	LOG_DEBUG("address: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", address, count);
942
943
944
945