mips_m4k.c 44.2 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>          *
 *                                                                         *
9
10
11
 *   Copyright (C) 2011 by Drasko DRASKOVIC                                *
 *   drasko.draskovic@gmail.com                                            *
 *                                                                         *
ntfreak's avatar
ntfreak committed
12
13
14
15
16
17
18
19
20
21
22
 *   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     *
23
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
ntfreak's avatar
ntfreak committed
24
 ***************************************************************************/
25

ntfreak's avatar
ntfreak committed
26
27
28
29
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

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

37
38
39
40
41
42
static void mips_m4k_enable_breakpoints(struct target *target);
static void mips_m4k_enable_watchpoints(struct target *target);
static int mips_m4k_set_breakpoint(struct target *target,
		struct breakpoint *breakpoint);
static int mips_m4k_unset_breakpoint(struct target *target,
		struct breakpoint *breakpoint);
43
static int mips_m4k_internal_restore(struct target *target, int current,
44
		target_addr_t address, int handle_breakpoints,
45
46
		int debug_execution);
static int mips_m4k_halt(struct target *target);
47
static int mips_m4k_bulk_write_memory(struct target *target, target_addr_t address,
48
		uint32_t count, const uint8_t *buffer);
49
50

static int mips_m4k_examine_debug_reason(struct target *target)
51
{
52
53
	struct mips32_common *mips32 = target_to_mips32(target);
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
54
	uint32_t break_status;
55
	int retval;
56

57
	if ((target->debug_reason != DBG_REASON_DBGRQ)
58
59
60
61
62
			&& (target->debug_reason != DBG_REASON_SINGLESTEP)) {
		if (ejtag_info->debug_caps & EJTAG_DCR_IB) {
			/* get info about inst breakpoint support */
			retval = target_read_u32(target,
				ejtag_info->ejtag_ibs_addr, &break_status);
63
			if (retval != ERROR_OK)
64
				return retval;
65
66
67
68
69
70
71
72
			if (break_status & 0x1f) {
				/* we have halted on a  breakpoint */
				retval = target_write_u32(target,
					ejtag_info->ejtag_ibs_addr, 0);
				if (retval != ERROR_OK)
					return retval;
				target->debug_reason = DBG_REASON_BREAKPOINT;
			}
73
		}
74

75
76
77
78
		if (ejtag_info->debug_caps & EJTAG_DCR_DB) {
			/* get info about data breakpoint support */
			retval = target_read_u32(target,
				ejtag_info->ejtag_dbs_addr, &break_status);
79
			if (retval != ERROR_OK)
80
				return retval;
81
82
83
84
85
86
87
88
			if (break_status & 0x1f) {
				/* we have halted on a  breakpoint */
				retval = target_write_u32(target,
					ejtag_info->ejtag_dbs_addr, 0);
				if (retval != ERROR_OK)
					return retval;
				target->debug_reason = DBG_REASON_WATCHPOINT;
			}
89
90
		}
	}
91

92
93
94
	return ERROR_OK;
}

95
static int mips_m4k_debug_entry(struct target *target)
ntfreak's avatar
ntfreak committed
96
{
97
	struct mips32_common *mips32 = target_to_mips32(target);
98
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
99

100
101
	mips32_save_context(target);

102
103
	/* make sure stepping disabled, SSt bit in CP0 debug register cleared */
	mips_ejtag_config_step(ejtag_info, 0);
104

105
	/* make sure break unit configured */
106
	mips32_configure_break_unit(target);
107

108
109
	/* attempt to find halt reason */
	mips_m4k_examine_debug_reason(target);
110

111
112
	mips32_read_config_regs(target);

113
114
115
	/* default to mips32 isa, it will be changed below if required */
	mips32->isa_mode = MIPS32_ISA_MIPS32;

116
117
118
	/* other than mips32 only and isa bit set ? */
	if (mips32->isa_imp && buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 1))
		mips32->isa_mode = mips32->isa_imp == 2 ? MIPS32_ISA_MIPS16E : MIPS32_ISA_MMIPS32;
119

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

ntfreak's avatar
ntfreak committed
124
125
126
	return ERROR_OK;
}

127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
static struct target *get_mips_m4k(struct target *target, int32_t coreid)
{
	struct target_list *head;
	struct target *curr;

	head = target->head;
	while (head != (struct target_list *)NULL) {
		curr = head->target;
		if ((curr->coreid == coreid) && (curr->state == TARGET_HALTED))
			return curr;
		head = head->next;
	}
	return target;
}

static int mips_m4k_halt_smp(struct target *target)
{
	int retval = ERROR_OK;
	struct target_list *head;
	struct target *curr;
	head = target->head;
	while (head != (struct target_list *)NULL) {
		int ret = ERROR_OK;
		curr = head->target;
		if ((curr != target) && (curr->state != TARGET_HALTED))
			ret = mips_m4k_halt(curr);

		if (ret != ERROR_OK) {
155
			LOG_ERROR("halt failed target->coreid: %" PRId32, curr->coreid);
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
			retval = ret;
		}
		head = head->next;
	}
	return retval;
}

static int update_halt_gdb(struct target *target)
{
	int retval = ERROR_OK;
	if (target->gdb_service->core[0] == -1) {
		target->gdb_service->target = target;
		target->gdb_service->core[0] = target->coreid;
		retval = mips_m4k_halt_smp(target);
	}
	return retval;
}

174
static int mips_m4k_poll(struct target *target)
ntfreak's avatar
ntfreak committed
175
{
176
	int retval = ERROR_OK;
177
	struct mips32_common *mips32 = target_to_mips32(target);
178
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
179
	uint32_t ejtag_ctrl = ejtag_info->ejtag_ctrl;
180
181
182
183
184
185
186
187
188
189
190
191
192
193
	enum target_state prev_target_state = target->state;

	/*  toggle to another core is done by gdb as follow */
	/*  maint packet J core_id */
	/*  continue */
	/*  the next polling trigger an halt event sent to gdb */
	if ((target->state == TARGET_HALTED) && (target->smp) &&
		(target->gdb_service) &&
		(target->gdb_service->target == NULL)) {
		target->gdb_service->target =
			get_mips_m4k(target, target->gdb_service->core[1]);
		target_call_event_callbacks(target, TARGET_EVENT_HALTED);
		return retval;
	}
194

ntfreak's avatar
ntfreak committed
195
	/* read ejtag control reg */
196
	mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
197
198
199
	retval = mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
	if (retval != ERROR_OK)
		return retval;
200

201
202
	ejtag_info->isa = (ejtag_ctrl & EJTAG_CTRL_DBGISA) ? 1 : 0;

203
204
	/* clear this bit before handling polling
	 * as after reset registers will read zero */
205
	if (ejtag_ctrl & EJTAG_CTRL_ROCC) {
206
207
208
		/* we have detected a reset, clear flag
		 * otherwise ejtag will not work */
		ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_ROCC;
209

210
		mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
211
212
213
		retval = mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
		if (retval != ERROR_OK)
			return retval;
214
215
		LOG_DEBUG("Reset Detected");
	}
216

217
	/* check for processor halted */
218
	if (ejtag_ctrl & EJTAG_CTRL_BRKST) {
219
220
221
222
		if ((target->state != TARGET_HALTED)
		    && (target->state != TARGET_DEBUG_RUNNING)) {
			if (target->state == TARGET_UNKNOWN)
				LOG_DEBUG("EJTAG_CTRL_BRKST already set during server startup.");
223
224
225
226

			/* OpenOCD was was probably started on the board with EJTAG_CTRL_BRKST already set
			 * (maybe put on by HALT-ing the board in the previous session).
			 *
227
			 * Force enable debug entry for this session.
228
			 */
229
			mips_ejtag_set_instr(ejtag_info, EJTAG_INST_NORMALBOOT);
ntfreak's avatar
ntfreak committed
230
			target->state = TARGET_HALTED;
231
232
			retval = mips_m4k_debug_entry(target);
			if (retval != ERROR_OK)
ntfreak's avatar
ntfreak committed
233
				return retval;
234

235
236
237
238
239
240
241
			if (target->smp &&
				((prev_target_state == TARGET_RUNNING)
			     || (prev_target_state == TARGET_RESET))) {
				retval = update_halt_gdb(target);
				if (retval != ERROR_OK)
					return retval;
			}
ntfreak's avatar
ntfreak committed
242
			target_call_event_callbacks(target, TARGET_EVENT_HALTED);
243
		} else if (target->state == TARGET_DEBUG_RUNNING) {
ntfreak's avatar
ntfreak committed
244
			target->state = TARGET_HALTED;
245

246
247
			retval = mips_m4k_debug_entry(target);
			if (retval != ERROR_OK)
ntfreak's avatar
ntfreak committed
248
				return retval;
249

250
251
252
253
254
255
			if (target->smp) {
				retval = update_halt_gdb(target);
				if (retval != ERROR_OK)
					return retval;
			}

ntfreak's avatar
ntfreak committed
256
257
			target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
		}
258
	} else
ntfreak's avatar
ntfreak committed
259
		target->state = TARGET_RUNNING;
260

261
/*	LOG_DEBUG("ctrl = 0x%08X", ejtag_ctrl); */
262

ntfreak's avatar
ntfreak committed
263
264
265
	return ERROR_OK;
}

266
static int mips_m4k_halt(struct target *target)
ntfreak's avatar
ntfreak committed
267
{
268
	struct mips32_common *mips32 = target_to_mips32(target);
269
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
270

271
	LOG_DEBUG("target->state: %s", target_state_name(target));
272

273
	if (target->state == TARGET_HALTED) {
ntfreak's avatar
ntfreak committed
274
275
276
		LOG_DEBUG("target was already halted");
		return ERROR_OK;
	}
277

ntfreak's avatar
ntfreak committed
278
279
	if (target->state == TARGET_UNKNOWN)
		LOG_WARNING("target was in unknown state when halt was requested");
280

281
282
	if (target->state == TARGET_RESET) {
		if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) && jtag_get_srst()) {
ntfreak's avatar
ntfreak committed
283
284
			LOG_ERROR("can't request a halt while in reset if nSRST pulls nTRST");
			return ERROR_TARGET_FAILURE;
285
		} else {
ntfreak's avatar
ntfreak committed
286
			/* we came here in a reset_halt or reset_init sequence
287
			 * debug entry was already prepared in mips_m4k_assert_reset()
ntfreak's avatar
ntfreak committed
288
289
			 */
			target->debug_reason = DBG_REASON_DBGRQ;
290

ntfreak's avatar
ntfreak committed
291
292
293
			return ERROR_OK;
		}
	}
294

ntfreak's avatar
ntfreak committed
295
296
	/* break processor */
	mips_ejtag_enter_debug(ejtag_info);
297

ntfreak's avatar
ntfreak committed
298
	target->debug_reason = DBG_REASON_DBGRQ;
299

ntfreak's avatar
ntfreak committed
300
301
302
	return ERROR_OK;
}

303
static int mips_m4k_assert_reset(struct target *target)
ntfreak's avatar
ntfreak committed
304
{
305
306
	struct mips_m4k_common *mips_m4k = target_to_m4k(target);
	struct mips_ejtag *ejtag_info = &mips_m4k->mips32.ejtag_info;
307

308
309
310
311
312
313
314
	/* TODO: apply hw reset signal in not examined state */
	if (!(target_was_examined(target))) {
		LOG_WARNING("Reset is not asserted because the target is not examined.");
		LOG_WARNING("Use a reset button or power cycle the target.");
		return ERROR_TARGET_NOT_EXAMINED;
	}

315
	LOG_DEBUG("target->state: %s",
316
		target_state_name(target));
317

318
	enum reset_types jtag_reset_config = jtag_get_reset_config();
319

320
321
322
323
324
325
326
327
328
329
	/* some cores support connecting while srst is asserted
	 * use that mode is it has been configured */

	bool srst_asserted = false;

	if (!(jtag_reset_config & RESET_SRST_PULLS_TRST) &&
			(jtag_reset_config & RESET_SRST_NO_GATING)) {
		jtag_add_reset(0, 1);
		srst_asserted = true;
	}
330

331
332
333
334
335
336
337
338
339

	/* EJTAG before v2.5/2.6 does not support EJTAGBOOT or NORMALBOOT */
	if (ejtag_info->ejtag_version != EJTAG_VERSION_20) {
		if (target->reset_halt) {
			/* use hardware to catch reset */
			mips_ejtag_set_instr(ejtag_info, EJTAG_INST_EJTAGBOOT);
		} else
			mips_ejtag_set_instr(ejtag_info, EJTAG_INST_NORMALBOOT);
	}
340

341
	if (jtag_reset_config & RESET_HAS_SRST) {
342
343
344
		/* 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);
345
		else if (!srst_asserted)
346
			jtag_add_reset(0, 1);
347
348
	} else if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) {
		target_handle_event(target, TARGET_EVENT_RESET_ASSERT);
349
350
	} else {
		if (mips_m4k->is_pic32mx) {
351
352
353
			LOG_DEBUG("Using MTAP reset to reset processor...");

			/* use microchip specific MTAP reset */
354
355
			mips_ejtag_set_instr(ejtag_info, MTAP_SW_MTAP);
			mips_ejtag_set_instr(ejtag_info, MTAP_COMMAND);
356

357
358
			mips_ejtag_drscan_8_out(ejtag_info, MCHP_ASERT_RST);
			mips_ejtag_drscan_8_out(ejtag_info, MCHP_DE_ASSERT_RST);
359
			mips_ejtag_set_instr(ejtag_info, MTAP_SW_ETAP);
360
		} else {
361
362
363
			/* use ejtag reset - not supported by all cores */
			uint32_t ejtag_ctrl = ejtag_info->ejtag_ctrl | EJTAG_CTRL_PRRST | EJTAG_CTRL_PERRST;
			LOG_DEBUG("Using EJTAG reset (PRRST) to reset processor...");
364
			mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
365
			mips_ejtag_drscan_32_out(ejtag_info, ejtag_ctrl);
366
		}
367
	}
368

ntfreak's avatar
ntfreak committed
369
370
371
	target->state = TARGET_RESET;
	jtag_add_sleep(50000);

372
	register_cache_invalidate(mips_m4k->mips32.core_cache);
ntfreak's avatar
ntfreak committed
373

374
375
376
	if (target->reset_halt) {
		int retval = target_halt(target);
		if (retval != ERROR_OK)
377
			return retval;
ntfreak's avatar
ntfreak committed
378
	}
379

ntfreak's avatar
ntfreak committed
380
381
382
	return ERROR_OK;
}

383
static int mips_m4k_deassert_reset(struct target *target)
ntfreak's avatar
ntfreak committed
384
{
385
	LOG_DEBUG("target->state: %s", target_state_name(target));
386

ntfreak's avatar
ntfreak committed
387
388
	/* deassert reset lines */
	jtag_add_reset(0, 0);
389

ntfreak's avatar
ntfreak committed
390
391
392
	return ERROR_OK;
}

393
static int mips_m4k_single_step_core(struct target *target)
394
{
395
	struct mips32_common *mips32 = target_to_mips32(target);
396
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
397

398
399
	/* configure single step mode */
	mips_ejtag_config_step(ejtag_info, 1);
400

401
402
	/* disable interrupts while stepping */
	mips32_enable_interrupts(target, 0);
403

404
	/* exit debug mode */
405
	mips_ejtag_exit_debug(ejtag_info);
406

407
	mips_m4k_debug_entry(target);
408

409
410
411
	return ERROR_OK;
}

412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
static int mips_m4k_restore_smp(struct target *target, uint32_t address, int handle_breakpoints)
{
	int retval = ERROR_OK;
	struct target_list *head;
	struct target *curr;

	head = target->head;
	while (head != (struct target_list *)NULL) {
		int ret = ERROR_OK;
		curr = head->target;
		if ((curr != target) && (curr->state != TARGET_RUNNING)) {
			/*  resume current address , not in step mode */
			ret = mips_m4k_internal_restore(curr, 1, address,
						   handle_breakpoints, 0);

			if (ret != ERROR_OK) {
428
				LOG_ERROR("target->coreid :%" PRId32 " failed to resume at address :0x%" PRIx32,
429
430
431
432
433
434
435
436
437
438
						  curr->coreid, address);
				retval = ret;
			}
		}
		head = head->next;
	}
	return retval;
}

static int mips_m4k_internal_restore(struct target *target, int current,
439
		target_addr_t address, int handle_breakpoints, int debug_execution)
ntfreak's avatar
ntfreak committed
440
{
441
	struct mips32_common *mips32 = target_to_mips32(target);
442
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
443
	struct breakpoint *breakpoint = NULL;
444
	uint32_t resume_pc;
445

446
	if (target->state != TARGET_HALTED) {
ntfreak's avatar
ntfreak committed
447
448
449
		LOG_WARNING("target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}
450

451
	if (!debug_execution) {
ntfreak's avatar
ntfreak committed
452
453
454
455
		target_free_all_working_areas(target);
		mips_m4k_enable_breakpoints(target);
		mips_m4k_enable_watchpoints(target);
	}
456

ntfreak's avatar
ntfreak committed
457
	/* current = 1: continue on current pc, otherwise continue at <address> */
458
	if (!current) {
459
		mips_m4k_isa_filter(mips32->isa_imp, &address);
ntfreak's avatar
ntfreak committed
460
		buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32, address);
461
462
		mips32->core_cache->reg_list[MIPS32_PC].dirty = true;
		mips32->core_cache->reg_list[MIPS32_PC].valid = true;
ntfreak's avatar
ntfreak committed
463
	}
464

465
	if ((mips32->isa_imp > 1) &&  debug_execution)	/* if more than one isa supported */
466
467
		buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 1, mips32->isa_mode);

468
469
470
471
	if (!current)
		resume_pc = address;
	else
		resume_pc = buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32);
472

ntfreak's avatar
ntfreak committed
473
	mips32_restore_context(target);
474

ntfreak's avatar
ntfreak committed
475
	/* the front-end may request us not to handle breakpoints */
476
	if (handle_breakpoints) {
ntfreak's avatar
ntfreak committed
477
		/* Single step past breakpoint at current address */
478
479
		breakpoint = breakpoint_find(target, resume_pc);
		if (breakpoint) {
480
481
			LOG_DEBUG("unset breakpoint at " TARGET_ADDR_FMT "",
					  breakpoint->address);
ntfreak's avatar
ntfreak committed
482
			mips_m4k_unset_breakpoint(target, breakpoint);
483
			mips_m4k_single_step_core(target);
ntfreak's avatar
ntfreak committed
484
485
486
			mips_m4k_set_breakpoint(target, breakpoint);
		}
	}
487

488
489
	/* enable interrupts if we are running */
	mips32_enable_interrupts(target, !debug_execution);
490

491
492
	/* exit debug mode */
	mips_ejtag_exit_debug(ejtag_info);
493
	target->debug_reason = DBG_REASON_NOTHALTED;
494

ntfreak's avatar
ntfreak committed
495
	/* registers are now invalid */
496
	register_cache_invalidate(mips32->core_cache);
497

498
	if (!debug_execution) {
ntfreak's avatar
ntfreak committed
499
500
		target->state = TARGET_RUNNING;
		target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
duane's avatar
duane committed
501
		LOG_DEBUG("target resumed at 0x%" PRIx32 "", resume_pc);
502
	} else {
ntfreak's avatar
ntfreak committed
503
504
		target->state = TARGET_DEBUG_RUNNING;
		target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED);
duane's avatar
duane committed
505
		LOG_DEBUG("target debug resumed at 0x%" PRIx32 "", resume_pc);
ntfreak's avatar
ntfreak committed
506
	}
507

ntfreak's avatar
ntfreak committed
508
509
510
	return ERROR_OK;
}

511
static int mips_m4k_resume(struct target *target, int current,
512
		target_addr_t address, int handle_breakpoints, int debug_execution)
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
{
	int retval = ERROR_OK;

	/* dummy resume for smp toggle in order to reduce gdb impact  */
	if ((target->smp) && (target->gdb_service->core[1] != -1)) {
		/*   simulate a start and halt of target */
		target->gdb_service->target = NULL;
		target->gdb_service->core[0] = target->gdb_service->core[1];
		/*  fake resume at next poll we play the  target core[1], see poll*/
		target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
		return retval;
	}

	retval = mips_m4k_internal_restore(target, current, address,
				handle_breakpoints,
				debug_execution);

530
	if (retval == ERROR_OK && target->smp) {
531
532
533
534
535
536
537
		target->gdb_service->core[0] = -1;
		retval = mips_m4k_restore_smp(target, address, handle_breakpoints);
	}

	return retval;
}

538
static int mips_m4k_step(struct target *target, int current,
539
		target_addr_t address, int handle_breakpoints)
ntfreak's avatar
ntfreak committed
540
541
{
	/* get pointers to arch-specific information */
542
	struct mips32_common *mips32 = target_to_mips32(target);
543
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
544
	struct breakpoint *breakpoint = NULL;
ntfreak's avatar
ntfreak committed
545

546
	if (target->state != TARGET_HALTED) {
ntfreak's avatar
ntfreak committed
547
548
549
550
551
		LOG_WARNING("target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	/* current = 1: continue on current pc, otherwise continue at <address> */
552
	if (!current) {
553
		mips_m4k_isa_filter(mips32->isa_imp, &address);
ntfreak's avatar
ntfreak committed
554
		buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32, address);
555
556
		mips32->core_cache->reg_list[MIPS32_PC].dirty = true;
		mips32->core_cache->reg_list[MIPS32_PC].valid = true;
557
	}
558

ntfreak's avatar
ntfreak committed
559
	/* the front-end may request us not to handle breakpoints */
560
561
562
563
	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
564
			mips_m4k_unset_breakpoint(target, breakpoint);
565
	}
566

ntfreak's avatar
ntfreak committed
567
568
	/* restore context */
	mips32_restore_context(target);
569

ntfreak's avatar
ntfreak committed
570
571
	/* configure single step mode */
	mips_ejtag_config_step(ejtag_info, 1);
572

ntfreak's avatar
ntfreak committed
573
	target->debug_reason = DBG_REASON_SINGLESTEP;
574

ntfreak's avatar
ntfreak committed
575
	target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
576

577
578
	/* disable interrupts while stepping */
	mips32_enable_interrupts(target, 0);
579

ntfreak's avatar
ntfreak committed
580
	/* exit debug mode */
581
	mips_ejtag_exit_debug(ejtag_info);
582

ntfreak's avatar
ntfreak committed
583
	/* registers are now invalid */
584
	register_cache_invalidate(mips32->core_cache);
585

586
587
588
	LOG_DEBUG("target stepped ");
	mips_m4k_debug_entry(target);

ntfreak's avatar
ntfreak committed
589
590
591
592
	if (breakpoint)
		mips_m4k_set_breakpoint(target, breakpoint);

	target_call_event_callbacks(target, TARGET_EVENT_HALTED);
593

ntfreak's avatar
ntfreak committed
594
595
596
	return ERROR_OK;
}

597
static void mips_m4k_enable_breakpoints(struct target *target)
ntfreak's avatar
ntfreak committed
598
{
599
	struct breakpoint *breakpoint = target->breakpoints;
600

ntfreak's avatar
ntfreak committed
601
	/* set any pending breakpoints */
602
	while (breakpoint) {
ntfreak's avatar
ntfreak committed
603
604
605
606
607
608
		if (breakpoint->set == 0)
			mips_m4k_set_breakpoint(target, breakpoint);
		breakpoint = breakpoint->next;
	}
}

609
610
static int mips_m4k_set_breakpoint(struct target *target,
		struct breakpoint *breakpoint)
ntfreak's avatar
ntfreak committed
611
{
612
	struct mips32_common *mips32 = target_to_mips32(target);
613
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
614
	struct mips32_comparator *comparator_list = mips32->inst_break_list;
615
	int retval;
616

617
	if (breakpoint->set) {
618
619
620
		LOG_WARNING("breakpoint already set");
		return ERROR_OK;
	}
621

622
	if (breakpoint->type == BKPT_HARD) {
623
		int bp_num = 0;
624

zwelch's avatar
zwelch committed
625
		while (comparator_list[bp_num].used && (bp_num < mips32->num_inst_bpoints))
626
			bp_num++;
627
		if (bp_num >= mips32->num_inst_bpoints) {
628
			LOG_ERROR("Can not find free FP Comparator(bpid: %" PRIu32 ")",
629
					breakpoint->unique_id);
630
			return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
631
632
633
634
		}
		breakpoint->set = bp_num + 1;
		comparator_list[bp_num].used = 1;
		comparator_list[bp_num].bp_value = breakpoint->address;
635

636
637
638
639
640
		if (breakpoint->length != 4)			/* make sure isa bit set */
			comparator_list[bp_num].bp_value |= 1;
		else						/* make sure isa bit cleared */
			comparator_list[bp_num].bp_value &= ~1;

641
642
643
644
645
646
		/* EJTAG 2.0 uses 30bit IBA. First 2 bits are reserved.
		 * Warning: there is no IB ASID registers in 2.0.
		 * Do not set it! :) */
		if (ejtag_info->ejtag_version == EJTAG_VERSION_20)
			comparator_list[bp_num].bp_value &= 0xFFFFFFFC;

647
648
		target_write_u32(target, comparator_list[bp_num].reg_address,
				comparator_list[bp_num].bp_value);
649
650
651
652
		target_write_u32(target, comparator_list[bp_num].reg_address +
				 ejtag_info->ejtag_ibm_offs, 0x00000000);
		target_write_u32(target, comparator_list[bp_num].reg_address +
				 ejtag_info->ejtag_ibc_offs, 1);
653
		LOG_DEBUG("bpid: %" PRIu32 ", bp_num %i bp_value 0x%" PRIx32 "",
654
655
				  breakpoint->unique_id,
				  bp_num, comparator_list[bp_num].bp_value);
656
	} else if (breakpoint->type == BKPT_SOFT) {
657
		LOG_DEBUG("bpid: %" PRIu32, breakpoint->unique_id);
658
659
660
661
662
663

		uint32_t isa_req = breakpoint->length & 1;	/* micro mips request bit */
		uint32_t bplength = breakpoint->length & ~1;	/* drop micro mips request bit for length */
		uint32_t bpaddr = breakpoint->address & ~1;	/* drop isa bit from address, if set */

		if (bplength == 4) {
664
			uint32_t verify = 0xffffffff;
665
666
667
			uint32_t sdbbp32_instr = MIPS32_SDBBP(isa_req);
			if (ejtag_info->endianness && isa_req)
				sdbbp32_instr = SWAP16(sdbbp32_instr);
668

669
			if ((breakpoint->address & 3) == 0) {	/* word alligned */
670

671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
				retval = target_read_memory(target, bpaddr, bplength, 1, breakpoint->orig_instr);
				if (retval != ERROR_OK)
					return retval;

				retval = target_write_u32(target, bpaddr, sdbbp32_instr);
				if (retval != ERROR_OK)
					return retval;

				retval = target_read_u32(target, bpaddr, &verify);
				if (retval != ERROR_OK)
					return retval;

				if (verify != sdbbp32_instr)
					verify = 0;

			} else {	/* 16 bit aligned */
				retval = target_read_memory(target, bpaddr, 2, 2, breakpoint->orig_instr);
				if (retval != ERROR_OK)
					return retval;

				uint8_t sdbbp_buf[4];
				target_buffer_set_u32(target, sdbbp_buf, sdbbp32_instr);

				retval = target_write_memory(target, bpaddr, 2, 2, sdbbp_buf);
				if (retval != ERROR_OK)
					return retval;

				retval = target_read_memory(target, bpaddr, 2, 2, sdbbp_buf);
				if (retval != ERROR_OK)
					return retval;

				if (target_buffer_get_u32(target, sdbbp_buf) != sdbbp32_instr)
					verify = 0;
			}

			if (verify == 0) {
707
				LOG_ERROR("Unable to set 32bit breakpoint at address %08" TARGET_PRIxADDR
708
					" - check that memory is read/writable", breakpoint->address);
709
710
				return ERROR_OK;
			}
711

712
		} else {
zwelch's avatar
zwelch committed
713
			uint16_t verify = 0xffff;
714

715
			retval = target_read_memory(target, bpaddr, bplength, 1, breakpoint->orig_instr);
716
			if (retval != ERROR_OK)
717
				return retval;
718
719

			retval = target_write_u16(target, bpaddr, MIPS16_SDBBP(isa_req));
720
			if (retval != ERROR_OK)
721
				return retval;
722

723
			retval = target_read_u16(target, bpaddr, &verify);
724
			if (retval != ERROR_OK)
725
				return retval;
726
727

			if (verify != MIPS16_SDBBP(isa_req)) {
728
				LOG_ERROR("Unable to set 16bit breakpoint at address %08" TARGET_PRIxADDR
729
						" - check that memory is read/writable", breakpoint->address);
730
731
732
				return ERROR_OK;
			}
		}
733

734
		breakpoint->set = 20; /* Any nice value but 0 */
735
	}
736

ntfreak's avatar
ntfreak committed
737
738
739
	return ERROR_OK;
}

740
741
static int mips_m4k_unset_breakpoint(struct target *target,
		struct breakpoint *breakpoint)
ntfreak's avatar
ntfreak committed
742
{
743
	/* get pointers to arch-specific information */
744
	struct mips32_common *mips32 = target_to_mips32(target);
745
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
746
	struct mips32_comparator *comparator_list = mips32->inst_break_list;
747
	int retval;
748

749
	if (!breakpoint->set) {
750
751
752
		LOG_WARNING("breakpoint not set");
		return ERROR_OK;
	}
753

754
	if (breakpoint->type == BKPT_HARD) {
755
		int bp_num = breakpoint->set - 1;
756
		if ((bp_num < 0) || (bp_num >= mips32->num_inst_bpoints)) {
757
			LOG_DEBUG("Invalid FP Comparator number in breakpoint (bpid: %" PRIu32 ")",
758
					  breakpoint->unique_id);
759
760
			return ERROR_OK;
		}
761
		LOG_DEBUG("bpid: %" PRIu32 " - releasing hw: %d",
762
763
				breakpoint->unique_id,
				bp_num);
764
765
		comparator_list[bp_num].used = 0;
		comparator_list[bp_num].bp_value = 0;
766
767
		target_write_u32(target, comparator_list[bp_num].reg_address +
				 ejtag_info->ejtag_ibc_offs, 0);
768

769
	} else {
770
		/* restore original instruction (kept in target endianness) */
771
772
773
		uint32_t isa_req = breakpoint->length & 1;
		uint32_t bplength = breakpoint->length & ~1;
		uint8_t current_instr[4];
774
		LOG_DEBUG("bpid: %" PRIu32, breakpoint->unique_id);
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
		if (bplength == 4) {
			uint32_t sdbbp32_instr =  MIPS32_SDBBP(isa_req);
			if (ejtag_info->endianness && isa_req)
				sdbbp32_instr = SWAP16(sdbbp32_instr);

			if ((breakpoint->address & 3) == 0) {		/* 32bit aligned */
				/* check that user program has not modified breakpoint instruction */
				retval = target_read_memory(target, breakpoint->address, 4, 1, current_instr);
				if (retval != ERROR_OK)
					return retval;
				/**
				* target_read_memory() gets us data in _target_ endianess.
				* If we want to use this data on the host for comparisons with some macros
				* we must first transform it to _host_ endianess using target_buffer_get_u16().
				*/
				if (sdbbp32_instr == target_buffer_get_u32(target, current_instr)) {
					retval = target_write_memory(target, breakpoint->address, 4, 1,
										breakpoint->orig_instr);
					if (retval != ERROR_OK)
						return retval;
				}
			} else {	/* 16bit alligned */
				retval = target_read_memory(target, breakpoint->address, 2, 2, current_instr);
798
				if (retval != ERROR_OK)
799
					return retval;
800
801
802
803
804
805
806

				if (sdbbp32_instr == target_buffer_get_u32(target, current_instr)) {
					retval = target_write_memory(target, breakpoint->address, 2, 2,
										breakpoint->orig_instr);
					if (retval != ERROR_OK)
						return retval;
				}
807
			}
808
		} else {
809
			/* check that user program has not modified breakpoint instruction */
810
			retval = target_read_memory(target, breakpoint->address, 2, 1, current_instr);
811
			if (retval != ERROR_OK)
812
				return retval;
813
814

			if (target_buffer_get_u16(target, current_instr) == MIPS16_SDBBP(isa_req)) {
815
				retval = target_write_memory(target, breakpoint->address, 2, 1,
816
									breakpoint->orig_instr);
817
				if (retval != ERROR_OK)
818
819
820
					return retval;
			}
		}
821
	}
822

823
	breakpoint->set = 0;
824

ntfreak's avatar
ntfreak committed
825
826
827
	return ERROR_OK;
}

828
static int mips_m4k_add_breakpoint(struct target *target, struct breakpoint *breakpoint)
ntfreak's avatar
ntfreak committed
829
{
830
	struct mips32_common *mips32 = target_to_mips32(target);
831

832
833
834
835
836
837
	if ((breakpoint->length > 5 || breakpoint->length < 2) ||		/* out of range */
		(breakpoint->length == 4 && (breakpoint->address & 2)) ||	/* mips32 unaligned */
		(mips32->isa_imp == MIPS32_ONLY && breakpoint->length != 4) ||	/* misp32 specific */
		((mips32->isa_imp & 1) != (breakpoint->length & 1)))		/* isa not implemented */
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;

838
839
	if (breakpoint->type == BKPT_HARD) {
		if (mips32->num_inst_bpoints_avail < 1) {
840
841
842
			LOG_INFO("no hardware breakpoint available");
			return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
		}
843

844
		mips32->num_inst_bpoints_avail--;
845
	}
846

847
	return mips_m4k_set_breakpoint(target, breakpoint);
ntfreak's avatar
ntfreak committed
848
849
}

850
851
static int mips_m4k_remove_breakpoint(struct target *target,
		struct breakpoint *breakpoint)
ntfreak's avatar
ntfreak committed
852
{
853
	/* get pointers to arch-specific information */
854
	struct mips32_common *mips32 = target_to_mips32(target);
855

856
	if (target->state != TARGET_HALTED) {
857
858
859
		LOG_WARNING("target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}
860

861
862
	if (breakpoint->set)
		mips_m4k_unset_breakpoint(target, breakpoint);
863

864
865
	if (breakpoint->type == BKPT_HARD)
		mips32->num_inst_bpoints_avail++;
866

ntfreak's avatar
ntfreak committed
867
868
869
	return ERROR_OK;
}

870
871
static int mips_m4k_set_watchpoint(struct target *target,
		struct watchpoint *watchpoint)
ntfreak's avatar
ntfreak committed
872
{
873
	struct mips32_common *mips32 = target_to_mips32(target);
874
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
875
	struct mips32_comparator *comparator_list = mips32->data_break_list;
876
877
878
879
880
881
	int wp_num = 0;
	/*
	 * watchpoint enabled, ignore all byte lanes in value register
	 * and exclude both load and store accesses from  watchpoint
	 * condition evaluation
	*/
882
	int enable = EJTAG_DBCn_NOSB | EJTAG_DBCn_NOLB | EJTAG_DBCn_BE |
883
			(0xff << EJTAG_DBCn_BLM_SHIFT);
884

885
	if (watchpoint->set) {
886
887
888
889
		LOG_WARNING("watchpoint already set");
		return ERROR_OK;
	}

890
	while (comparator_list[wp_num].used && (wp_num < mips32->num_data_bpoints))
891
		wp_num++;
892
	if (wp_num >= mips32->num_data_bpoints) {
David Brownell's avatar
David Brownell committed
893
894
		LOG_ERROR("Can not find free FP Comparator");
		return ERROR_FAIL;
895
896
	}

897
	if (watchpoint->length != 4) {
oharboe's avatar