mips_m4k.c 26.9 KB
Newer Older
ntfreak's avatar
ntfreak committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/***************************************************************************
 *   Copyright (C) 2008 by Spencer Oliver                                  *
 *   spen@spen-soft.co.uk                                                  *
 *                                                                         *
 *   Copyright (C) 2008 by David T.L. Wong                                 *
 *                                                                         *
 *   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 "mips32.h"
#include "mips_m4k.h"
28
#include "mips32_dmaacc.h"
29
#include "target_type.h"
ntfreak's avatar
ntfreak committed
30
31
32
33
34


/* cli handling */

/* forward declarations */
Zachary T Welch's avatar
Zachary T Welch committed
35
36
37
38
39
40
41
int mips_m4k_poll(struct target *target);
int mips_m4k_halt(struct target *target);
int mips_m4k_soft_reset_halt(struct target *target);
int mips_m4k_resume(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution);
int mips_m4k_step(struct target *target, int current, uint32_t address, int handle_breakpoints);
int mips_m4k_read_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer);
int mips_m4k_write_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer);
42
43
int mips_m4k_register_commands(struct command_context *cmd_ctx);
int mips_m4k_init_target(struct command_context *cmd_ctx, struct target *target);
Zachary T Welch's avatar
Zachary T Welch committed
44
int mips_m4k_target_create(struct target *target, Jim_Interp *interp);
ntfreak's avatar
ntfreak committed
45

Zachary T Welch's avatar
Zachary T Welch committed
46
47
48
49
int mips_m4k_examine(struct target *target);
int mips_m4k_assert_reset(struct target *target);
int mips_m4k_deassert_reset(struct target *target);
int mips_m4k_checksum_memory(struct target *target, uint32_t address, uint32_t size, uint32_t *checksum);
ntfreak's avatar
ntfreak committed
50

51
struct target_type mips_m4k_target =
ntfreak's avatar
ntfreak committed
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
{
	.name = "mips_m4k",

	.poll = mips_m4k_poll,
	.arch_state = mips32_arch_state,

	.target_request_data = NULL,

	.halt = mips_m4k_halt,
	.resume = mips_m4k_resume,
	.step = mips_m4k_step,

	.assert_reset = mips_m4k_assert_reset,
	.deassert_reset = mips_m4k_deassert_reset,
	.soft_reset_halt = mips_m4k_soft_reset_halt,
67

ntfreak's avatar
ntfreak committed
68
69
70
71
72
	.get_gdb_reg_list = mips32_get_gdb_reg_list,

	.read_memory = mips_m4k_read_memory,
	.write_memory = mips_m4k_write_memory,
	.bulk_write_memory = mips_m4k_bulk_write_memory,
73
	.checksum_memory = mips_m4k_checksum_memory,
ntfreak's avatar
ntfreak committed
74
	.blank_check_memory = NULL,
75

ntfreak's avatar
ntfreak committed
76
77
78
79
80
81
82
83
	.run_algorithm = mips32_run_algorithm,

	.add_breakpoint = mips_m4k_add_breakpoint,
	.remove_breakpoint = mips_m4k_remove_breakpoint,
	.add_watchpoint = mips_m4k_add_watchpoint,
	.remove_watchpoint = mips_m4k_remove_watchpoint,

	.register_commands = mips_m4k_register_commands,
84
	.target_create = mips_m4k_target_create,
ntfreak's avatar
ntfreak committed
85
86
87
88
	.init_target = mips_m4k_init_target,
	.examine = mips_m4k_examine,
};

Zachary T Welch's avatar
Zachary T Welch committed
89
int mips_m4k_examine_debug_reason(struct target *target)
90
{
91
	uint32_t break_status;
92
	int retval;
93

94
95
96
97
98
99
100
101
102
103
104
105
106
	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;
		}
107

108
109
110
111
112
113
114
115
116
117
118
		/* get info about data breakpoint support */
		if ((retval = target_read_u32(target, 0xFF302000, &break_status)) != ERROR_OK)
			return retval;
		if (break_status & 0x1f)
		{
			/* we have halted on a  breakpoint */
			if ((retval = target_write_u32(target, 0xFF302000, 0)) != ERROR_OK)
				return retval;
			target->debug_reason = DBG_REASON_WATCHPOINT;
		}
	}
119

120
121
122
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
123
int mips_m4k_debug_entry(struct target *target)
ntfreak's avatar
ntfreak committed
124
{
125
	struct mips32_common *mips32 = target->arch_info;
126
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
127
	uint32_t debug_reg;
128

ntfreak's avatar
ntfreak committed
129
130
	/* read debug register */
	mips_ejtag_read_debug(ejtag_info, &debug_reg);
131

132
133
	/* make sure break uit configured */
	mips32_configure_break_unit(target);
134

135
136
	/* attempt to find halt reason */
	mips_m4k_examine_debug_reason(target);
137

138
	/* clear single step if active */
ntfreak's avatar
ntfreak committed
139
140
141
142
143
	if (debug_reg & EJTAG_DEBUG_DSS)
	{
		/* stopped due to single step - clear step bit */
		mips_ejtag_config_step(ejtag_info, 0);
	}
144

ntfreak's avatar
ntfreak committed
145
	mips32_save_context(target);
146

duane's avatar
duane committed
147
	LOG_DEBUG("entered debug state at PC 0x%" PRIx32 ", target->state: %s",
148
		*(uint32_t*)(mips32->core_cache->reg_list[MIPS32_PC].value),
149
		  target_state_name(target));
150

ntfreak's avatar
ntfreak committed
151
152
153
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
154
int mips_m4k_poll(struct target *target)
ntfreak's avatar
ntfreak committed
155
156
{
	int retval;
157
	struct mips32_common *mips32 = target->arch_info;
158
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
159
	uint32_t ejtag_ctrl = ejtag_info->ejtag_ctrl;
160

ntfreak's avatar
ntfreak committed
161
	/* read ejtag control reg */
162
	jtag_set_end_state(TAP_IDLE);
ntfreak's avatar
ntfreak committed
163
	mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL, NULL);
164
	mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
165

166
167
168
169
170
171
	/* 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 */
172
		jtag_set_end_state(TAP_IDLE);
173
		ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_ROCC;
174

175
176
177
178
		mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL, NULL);
		mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
		LOG_DEBUG("Reset Detected");
	}
179

180
	/* check for processor halted */
181
	if (ejtag_ctrl & EJTAG_CTRL_BRKST)
ntfreak's avatar
ntfreak committed
182
183
184
	{
		if ((target->state == TARGET_RUNNING) || (target->state == TARGET_RESET))
		{
185
			jtag_set_end_state(TAP_IDLE);
ntfreak's avatar
ntfreak committed
186
			mips_ejtag_set_instr(ejtag_info, EJTAG_INST_NORMALBOOT, NULL);
187

ntfreak's avatar
ntfreak committed
188
			target->state = TARGET_HALTED;
189

ntfreak's avatar
ntfreak committed
190
191
			if ((retval = mips_m4k_debug_entry(target)) != ERROR_OK)
				return retval;
192

ntfreak's avatar
ntfreak committed
193
194
195
196
197
			target_call_event_callbacks(target, TARGET_EVENT_HALTED);
		}
		else if (target->state == TARGET_DEBUG_RUNNING)
		{
			target->state = TARGET_HALTED;
198

ntfreak's avatar
ntfreak committed
199
200
			if ((retval = mips_m4k_debug_entry(target)) != ERROR_OK)
				return retval;
201

ntfreak's avatar
ntfreak committed
202
203
204
205
206
207
208
			target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
		}
	}
	else
	{
		target->state = TARGET_RUNNING;
	}
209

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

ntfreak's avatar
ntfreak committed
212
213
214
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
215
int mips_m4k_halt(struct target *target)
ntfreak's avatar
ntfreak committed
216
{
217
	struct mips32_common *mips32 = target->arch_info;
218
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
219
220

	LOG_DEBUG("target->state: %s",
221
		  target_state_name(target));
222

ntfreak's avatar
ntfreak committed
223
224
225
226
227
	if (target->state == TARGET_HALTED)
	{
		LOG_DEBUG("target was already halted");
		return ERROR_OK;
	}
228

ntfreak's avatar
ntfreak committed
229
230
231
232
	if (target->state == TARGET_UNKNOWN)
	{
		LOG_WARNING("target was in unknown state when halt was requested");
	}
233
234

	if (target->state == TARGET_RESET)
ntfreak's avatar
ntfreak committed
235
	{
236
		if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) && jtag_get_srst())
ntfreak's avatar
ntfreak committed
237
238
239
240
241
242
243
244
245
246
		{
			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;
247

ntfreak's avatar
ntfreak committed
248
249
250
			return ERROR_OK;
		}
	}
251

ntfreak's avatar
ntfreak committed
252
253
	/* break processor */
	mips_ejtag_enter_debug(ejtag_info);
254

ntfreak's avatar
ntfreak committed
255
	target->debug_reason = DBG_REASON_DBGRQ;
256

ntfreak's avatar
ntfreak committed
257
258
259
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
260
int mips_m4k_assert_reset(struct target *target)
ntfreak's avatar
ntfreak committed
261
{
262
	struct mips32_common *mips32 = target->arch_info;
263
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
264
265

	LOG_DEBUG("target->state: %s",
266
		target_state_name(target));
267

268
	enum reset_types jtag_reset_config = jtag_get_reset_config();
ntfreak's avatar
ntfreak committed
269
270
271
272
273
	if (!(jtag_reset_config & RESET_HAS_SRST))
	{
		LOG_ERROR("Can't assert SRST");
		return ERROR_FAIL;
	}
274

ntfreak's avatar
ntfreak committed
275
276
277
	if (target->reset_halt)
	{
		/* use hardware to catch reset */
278
		jtag_set_end_state(TAP_IDLE);
ntfreak's avatar
ntfreak committed
279
280
281
282
		mips_ejtag_set_instr(ejtag_info, EJTAG_INST_EJTAGBOOT, NULL);
	}
	else
	{
283
		jtag_set_end_state(TAP_IDLE);
ntfreak's avatar
ntfreak committed
284
285
		mips_ejtag_set_instr(ejtag_info, EJTAG_INST_NORMALBOOT, NULL);
	}
286

287
	if (strcmp(target->variant, "ejtag_srst") == 0)
ntfreak's avatar
ntfreak committed
288
	{
289
		uint32_t ejtag_ctrl = ejtag_info->ejtag_ctrl | EJTAG_CTRL_PRRST | EJTAG_CTRL_PERRST;
290
291
292
		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
293
294
295
	}
	else
	{
296
297
298
299
300
301
302
303
304
		/* 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
305
	}
306

ntfreak's avatar
ntfreak committed
307
308
309
310
311
	target->state = TARGET_RESET;
	jtag_add_sleep(50000);

	mips32_invalidate_core_regs(target);

ntfreak's avatar
ntfreak committed
312
313
314
	if (target->reset_halt)
	{
		int retval;
zwelch's avatar
zwelch committed
315
		if ((retval = target_halt(target)) != ERROR_OK)
316
			return retval;
ntfreak's avatar
ntfreak committed
317
	}
318

ntfreak's avatar
ntfreak committed
319
320
321
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
322
int mips_m4k_deassert_reset(struct target *target)
ntfreak's avatar
ntfreak committed
323
{
324
	LOG_DEBUG("target->state: %s",
325
		target_state_name(target));
326

ntfreak's avatar
ntfreak committed
327
328
	/* deassert reset lines */
	jtag_add_reset(0, 0);
329

ntfreak's avatar
ntfreak committed
330
331
332
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
333
int mips_m4k_soft_reset_halt(struct target *target)
ntfreak's avatar
ntfreak committed
334
335
336
337
338
{
	/* TODO */
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
339
int mips_m4k_single_step_core(struct target *target)
340
{
341
	struct mips32_common *mips32 = target->arch_info;
342
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
343

344
345
	/* configure single step mode */
	mips_ejtag_config_step(ejtag_info, 1);
346

347
348
	/* disable interrupts while stepping */
	mips32_enable_interrupts(target, 0);
349

350
	/* exit debug mode */
351
	mips_ejtag_exit_debug(ejtag_info);
352

353
	mips_m4k_debug_entry(target);
354

355
356
357
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
358
int mips_m4k_resume(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution)
ntfreak's avatar
ntfreak committed
359
{
360
	struct mips32_common *mips32 = target->arch_info;
361
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
362
	struct breakpoint *breakpoint = NULL;
363
	uint32_t resume_pc;
364

ntfreak's avatar
ntfreak committed
365
366
367
368
369
	if (target->state != TARGET_HALTED)
	{
		LOG_WARNING("target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}
370

ntfreak's avatar
ntfreak committed
371
372
373
374
375
376
	if (!debug_execution)
	{
		target_free_all_working_areas(target);
		mips_m4k_enable_breakpoints(target);
		mips_m4k_enable_watchpoints(target);
	}
377

ntfreak's avatar
ntfreak committed
378
	/* current = 1: continue on current pc, otherwise continue at <address> */
ntfreak's avatar
ntfreak committed
379
	if (!current)
ntfreak's avatar
ntfreak committed
380
381
382
383
384
	{
		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;
	}
385

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

ntfreak's avatar
ntfreak committed
388
	mips32_restore_context(target);
389

ntfreak's avatar
ntfreak committed
390
391
392
393
394
395
	/* 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
396
			LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 "", breakpoint->address);
ntfreak's avatar
ntfreak committed
397
			mips_m4k_unset_breakpoint(target, breakpoint);
398
			mips_m4k_single_step_core(target);
ntfreak's avatar
ntfreak committed
399
400
401
			mips_m4k_set_breakpoint(target, breakpoint);
		}
	}
402

403
404
	/* enable interrupts if we are running */
	mips32_enable_interrupts(target, !debug_execution);
405

406
407
	/* exit debug mode */
	mips_ejtag_exit_debug(ejtag_info);
408
	target->debug_reason = DBG_REASON_NOTHALTED;
409

ntfreak's avatar
ntfreak committed
410
411
	/* registers are now invalid */
	mips32_invalidate_core_regs(target);
412

ntfreak's avatar
ntfreak committed
413
414
415
416
	if (!debug_execution)
	{
		target->state = TARGET_RUNNING;
		target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
duane's avatar
duane committed
417
		LOG_DEBUG("target resumed at 0x%" PRIx32 "", resume_pc);
ntfreak's avatar
ntfreak committed
418
419
420
421
422
	}
	else
	{
		target->state = TARGET_DEBUG_RUNNING;
		target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED);
duane's avatar
duane committed
423
		LOG_DEBUG("target debug resumed at 0x%" PRIx32 "", resume_pc);
ntfreak's avatar
ntfreak committed
424
	}
425

ntfreak's avatar
ntfreak committed
426
427
428
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
429
int mips_m4k_step(struct target *target, int current, uint32_t address, int handle_breakpoints)
ntfreak's avatar
ntfreak committed
430
431
{
	/* get pointers to arch-specific information */
432
	struct mips32_common *mips32 = target->arch_info;
433
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
434
	struct breakpoint *breakpoint = NULL;
ntfreak's avatar
ntfreak committed
435
436
437
438
439
440
441
442
443
444

	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);
445

ntfreak's avatar
ntfreak committed
446
447
448
449
	/* the front-end may request us not to handle breakpoints */
	if (handle_breakpoints)
		if ((breakpoint = breakpoint_find(target, buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32))))
			mips_m4k_unset_breakpoint(target, breakpoint);
450

ntfreak's avatar
ntfreak committed
451
452
	/* restore context */
	mips32_restore_context(target);
453

ntfreak's avatar
ntfreak committed
454
455
	/* configure single step mode */
	mips_ejtag_config_step(ejtag_info, 1);
456

ntfreak's avatar
ntfreak committed
457
	target->debug_reason = DBG_REASON_SINGLESTEP;
458

ntfreak's avatar
ntfreak committed
459
	target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
460

461
462
	/* disable interrupts while stepping */
	mips32_enable_interrupts(target, 0);
463

ntfreak's avatar
ntfreak committed
464
	/* exit debug mode */
465
	mips_ejtag_exit_debug(ejtag_info);
466

ntfreak's avatar
ntfreak committed
467
468
	/* registers are now invalid */
	mips32_invalidate_core_regs(target);
469

ntfreak's avatar
ntfreak committed
470
471
472
473
	if (breakpoint)
		mips_m4k_set_breakpoint(target, breakpoint);

	LOG_DEBUG("target stepped ");
474

ntfreak's avatar
ntfreak committed
475
476
	mips_m4k_debug_entry(target);
	target_call_event_callbacks(target, TARGET_EVENT_HALTED);
477

ntfreak's avatar
ntfreak committed
478
479
480
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
481
void mips_m4k_enable_breakpoints(struct target *target)
ntfreak's avatar
ntfreak committed
482
{
483
	struct breakpoint *breakpoint = target->breakpoints;
484

ntfreak's avatar
ntfreak committed
485
486
487
488
489
490
491
492
493
	/* 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
494
int mips_m4k_set_breakpoint(struct target *target, struct breakpoint *breakpoint)
ntfreak's avatar
ntfreak committed
495
{
496
	struct mips32_common *mips32 = target->arch_info;
497
	struct mips32_comparator * comparator_list = mips32->inst_break_list;
498
	int retval;
499

500
501
502
503
504
	if (breakpoint->set)
	{
		LOG_WARNING("breakpoint already set");
		return ERROR_OK;
	}
505

506
507
508
	if (breakpoint->type == BKPT_HARD)
	{
		int bp_num = 0;
509

zwelch's avatar
zwelch committed
510
		while (comparator_list[bp_num].used && (bp_num < mips32->num_inst_bpoints))
511
512
513
			bp_num++;
		if (bp_num >= mips32->num_inst_bpoints)
		{
514
515
			LOG_DEBUG("ERROR Can not find free FP Comparator(bpid: %d)",
					  breakpoint->unique_id );
516
517
518
519
520
521
522
523
524
			LOG_WARNING("ERROR Can not find free FP Comparator");
			exit(-1);
		}
		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);
525
		LOG_DEBUG("bpid: %d, bp_num %i bp_value 0x%" PRIx32 "",
526
527
				  breakpoint->unique_id,
				  bp_num, comparator_list[bp_num].bp_value);
528
529
530
	}
	else if (breakpoint->type == BKPT_SOFT)
	{
531
		LOG_DEBUG("bpid: %d", breakpoint->unique_id );
532
533
		if (breakpoint->length == 4)
		{
534
			uint32_t verify = 0xffffffff;
535

zwelch's avatar
zwelch committed
536
			if ((retval = target_read_memory(target, breakpoint->address, breakpoint->length, 1, breakpoint->orig_instr)) != ERROR_OK)
537
538
539
540
541
542
543
			{
				return retval;
			}
			if ((retval = target_write_u32(target, breakpoint->address, MIPS32_SDBBP)) != ERROR_OK)
			{
				return retval;
			}
544

545
546
547
548
549
550
			if ((retval = target_read_u32(target, breakpoint->address, &verify)) != ERROR_OK)
			{
				return retval;
			}
			if (verify != MIPS32_SDBBP)
			{
duane's avatar
duane committed
551
				LOG_ERROR("Unable to set 32bit breakpoint at address %08" PRIx32 " - check that memory is read/writable", breakpoint->address);
552
553
554
555
556
				return ERROR_OK;
			}
		}
		else
		{
zwelch's avatar
zwelch committed
557
			uint16_t verify = 0xffff;
558

zwelch's avatar
zwelch committed
559
			if ((retval = target_read_memory(target, breakpoint->address, breakpoint->length, 1, breakpoint->orig_instr)) != ERROR_OK)
560
561
562
563
564
565
566
			{
				return retval;
			}
			if ((retval = target_write_u16(target, breakpoint->address, MIPS16_SDBBP)) != ERROR_OK)
			{
				return retval;
			}
567

568
569
570
571
572
573
			if ((retval = target_read_u16(target, breakpoint->address, &verify)) != ERROR_OK)
			{
				return retval;
			}
			if (verify != MIPS16_SDBBP)
			{
duane's avatar
duane committed
574
				LOG_ERROR("Unable to set 16bit breakpoint at address %08" PRIx32 " - check that memory is read/writable", breakpoint->address);
575
576
577
				return ERROR_OK;
			}
		}
578

579
		breakpoint->set = 20; /* Any nice value but 0 */
580
	}
581

ntfreak's avatar
ntfreak committed
582
583
584
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
585
int mips_m4k_unset_breakpoint(struct target *target, struct breakpoint *breakpoint)
ntfreak's avatar
ntfreak committed
586
{
587
	/* get pointers to arch-specific information */
588
	struct mips32_common *mips32 = target->arch_info;
589
	struct mips32_comparator * comparator_list = mips32->inst_break_list;
590
	int retval;
591

592
593
594
595
596
	if (!breakpoint->set)
	{
		LOG_WARNING("breakpoint not set");
		return ERROR_OK;
	}
597

598
599
600
601
602
	if (breakpoint->type == BKPT_HARD)
	{
		int bp_num = breakpoint->set - 1;
		if ((bp_num < 0) || (bp_num >= mips32->num_inst_bpoints))
		{
603
604
			LOG_DEBUG("Invalid FP Comparator number in breakpoint (bpid: %d)",
					  breakpoint->unique_id);
605
606
			return ERROR_OK;
		}
607
608
609
		LOG_DEBUG("bpid: %d - releasing hw: %d",
				  breakpoint->unique_id,
				  bp_num );
610
611
612
		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);
613

614
615
616
	}
	else
	{
617
		/* restore original instruction (kept in target endianness) */
618
		LOG_DEBUG("bpid: %d", breakpoint->unique_id);
619
620
		if (breakpoint->length == 4)
		{
621
			uint32_t current_instr;
622

623
			/* check that user program has not modified breakpoint instruction */
624
			if ((retval = target_read_memory(target, breakpoint->address, 4, 1, (uint8_t*)&current_instr)) != ERROR_OK)
625
626
627
628
629
			{
				return retval;
			}
			if (current_instr == MIPS32_SDBBP)
			{
zwelch's avatar
zwelch committed
630
				if ((retval = target_write_memory(target, breakpoint->address, 4, 1, breakpoint->orig_instr)) != ERROR_OK)
631
632
633
634
635
636
637
				{
					return retval;
				}
			}
		}
		else
		{
zwelch's avatar
zwelch committed
638
			uint16_t current_instr;
639

640
			/* check that user program has not modified breakpoint instruction */
641
			if ((retval = target_read_memory(target, breakpoint->address, 2, 1, (uint8_t*)&current_instr)) != ERROR_OK)
642
643
644
			{
				return retval;
			}
645

646
647
			if (current_instr == MIPS16_SDBBP)
			{
zwelch's avatar
zwelch committed
648
				if ((retval = target_write_memory(target, breakpoint->address, 2, 1, breakpoint->orig_instr)) != ERROR_OK)
649
650
651
652
653
				{
					return retval;
				}
			}
		}
654
655
	}
	breakpoint->set = 0;
656

ntfreak's avatar
ntfreak committed
657
658
659
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
660
int mips_m4k_add_breakpoint(struct target *target, struct breakpoint *breakpoint)
ntfreak's avatar
ntfreak committed
661
{
662
	struct mips32_common *mips32 = target->arch_info;
663

664
	if (breakpoint->type == BKPT_HARD)
665
	{
666
667
668
669
670
		if (mips32->num_inst_bpoints_avail < 1)
		{
			LOG_INFO("no hardware breakpoint available");
			return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
		}
671

672
		mips32->num_inst_bpoints_avail--;
673
	}
674

675
	mips_m4k_set_breakpoint(target, breakpoint);
676

ntfreak's avatar
ntfreak committed
677
678
679
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
680
int mips_m4k_remove_breakpoint(struct target *target, struct breakpoint *breakpoint)
ntfreak's avatar
ntfreak committed
681
{
682
	/* get pointers to arch-specific information */
683
	struct mips32_common *mips32 = target->arch_info;
684

685
686
687
688
689
	if (target->state != TARGET_HALTED)
	{
		LOG_WARNING("target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}
690

691
692
693
694
	if (breakpoint->set)
	{
		mips_m4k_unset_breakpoint(target, breakpoint);
	}
695

696
697
	if (breakpoint->type == BKPT_HARD)
		mips32->num_inst_bpoints_avail++;
698

ntfreak's avatar
ntfreak committed
699
700
701
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
702
int mips_m4k_set_watchpoint(struct target *target, struct watchpoint *watchpoint)
ntfreak's avatar
ntfreak committed
703
{
704
	struct mips32_common *mips32 = target->arch_info;
705
	struct mips32_comparator * comparator_list = mips32->data_break_list;
706
707
708
709
710
711
	int wp_num = 0;
	/*
	 * watchpoint enabled, ignore all byte lanes in value register
	 * and exclude both load and store accesses from  watchpoint
	 * condition evaluation
	*/
712
	int enable = EJTAG_DBCn_NOSB | EJTAG_DBCn_NOLB | EJTAG_DBCn_BE |
713
                (0xff << EJTAG_DBCn_BLM_SHIFT);
714

715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
	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)
	{
		LOG_DEBUG("ERROR Can not find free FP Comparator");
		LOG_WARNING("ERROR Can not find free FP Comparator");
		exit(-1);
	}

	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);
766

ntfreak's avatar
ntfreak committed
767
768
769
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
770
int mips_m4k_unset_watchpoint(struct target *target, struct watchpoint *watchpoint)
ntfreak's avatar
ntfreak committed
771
{
772
	/* get pointers to arch-specific information */
773
	struct mips32_common *mips32 = target->arch_info;
774
	struct mips32_comparator * comparator_list = mips32->data_break_list;
775

776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
	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
793
794
795
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
796
int mips_m4k_add_watchpoint(struct target *target, struct watchpoint *watchpoint)
ntfreak's avatar
ntfreak committed
797
{
798
	struct mips32_common *mips32 = target->arch_info;
799
800
801
802
803
804

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

806
807
808
	mips32->num_data_bpoints_avail--;

	mips_m4k_set_watchpoint(target, watchpoint);
ntfreak's avatar
ntfreak committed
809
810
811
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
812
int mips_m4k_remove_watchpoint(struct target *target, struct watchpoint *watchpoint)
ntfreak's avatar
ntfreak committed
813
{
814
	/* get pointers to arch-specific information */
815
	struct mips32_common *mips32 = target->arch_info;
816
817
818
819
820
821
822
823
824
825
826
827
828
829

	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
830
831
832
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
833
void mips_m4k_enable_watchpoints(struct target *target)
ntfreak's avatar
ntfreak committed
834
{
835
	struct watchpoint *watchpoint = target->watchpoints;
836

ntfreak's avatar
ntfreak committed
837
838
839
840
841
842
843
844
845
	/* 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
846
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
847
{
848
	struct mips32_common *mips32 = target->arch_info;
849
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
850

duane's avatar
duane committed
851
	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
852
853
854
855
856
857
858
859
860
861
862
863
864

	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;
865

866
867
	/* if noDMA off, use DMAACC mode for memory read */
	int retval;
zwelch's avatar
zwelch committed
868
	if (ejtag_info->impcode & EJTAG_IMP_NODMA)
869
870
871
872
873
		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
874

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

Zachary T Welch's avatar
Zachary T Welch committed
878
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
879
{
880
	struct mips32_common *mips32 = target->arch_info;
881
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
882

duane's avatar
duane committed
883
	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
884
885
886
887
888
889
890
891
892
893
894
895
896

	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;
897

898
	/* if noDMA off, use DMAACC mode for memory write */
zwelch's avatar
zwelch committed
899
	if (ejtag_info->impcode & EJTAG_IMP_NODMA)
900
		return mips32_pracc_write_mem(ejtag_info, address, size, count, (void *)buffer);
zwelch's avatar
zwelch committed
901
	else
902
		return mips32_dmaacc_write_mem(ejtag_info, address, size, count, (void *)buffer);
ntfreak's avatar
ntfreak committed
903
904
}

905
int mips_m4k_register_commands(struct command_context *cmd_ctx)
ntfreak's avatar
ntfreak committed
906
907
{
	int retval;
908

ntfreak's avatar
ntfreak committed
909
910
911
912
	retval = mips32_register_commands(cmd_ctx);
	return retval;
}

913
int mips_m4k_init_target(struct command_context *cmd_ctx, struct target *target)
ntfreak's avatar
ntfreak committed
914
915
{
	mips32_build_reg_cache(target);
916

ntfreak's avatar
ntfreak committed
917
918
919
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
920
int mips_m4k_init_arch_info(struct target *target, struct mips_m4k_common *mips_m4k, struct jtag_tap *tap)
ntfreak's avatar
ntfreak committed
921
{
922
	struct mips32_common *mips32 = &mips_m4k->mips32_common;
923

ntfreak's avatar
ntfreak committed
924
	mips_m4k->common_magic = MIPSM4K_COMMON_MAGIC;
925

ntfreak's avatar
ntfreak committed
926
	/* initialize mips4k specific info */
927
	mips32_init_arch_info(target, mips32, tap);
ntfreak's avatar
ntfreak committed
928
	mips32->arch_info = mips_m4k;
929

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

Zachary T Welch's avatar
Zachary T Welch committed
933
int mips_m4k_target_create(struct target *target, Jim_Interp *interp)
ntfreak's avatar
ntfreak committed
934
{
935
	struct mips_m4k_common *mips_m4k = calloc(1,sizeof(struct mips_m4k_common));
936

937
	mips_m4k_init_arch_info(target, mips_m4k, target->tap);
938

ntfreak's avatar
ntfreak committed
939
940
941
	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
942
int mips_m4k_examine(struct target *target)
ntfreak's avatar
ntfreak committed
943
944
{
	int retval;
945
	struct mips32_common *mips32 = target->arch_info;
946
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
947
	uint32_t idcode = 0;
948

949
	if (!target_was_examined(target))
ntfreak's avatar
ntfreak committed
950
	{
951
		mips_ejtag_get_idcode(ejtag_info, &idcode);
952
		ejtag_info->idcode = idcode;
953

954
955
956
957
958
959
960
		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
961
	}
962

ntfreak's avatar
ntfreak committed
963
964
965
	/* init rest of ejtag interface */
	if ((retval = mips_ejtag_init(ejtag_info)) != ERROR_OK)
		return retval;
966

967
968
	if ((retval = mips32_examine(target)) != ERROR_OK)
		return retval;
969

ntfreak's avatar
ntfreak committed
970
971
972
	return ERROR_OK;
}

Zachary T Welch's avatar