mips_m4k.c 26.7 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
35
36
37


/* cli handling */

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

ntfreak's avatar
ntfreak committed
46
int mips_m4k_examine(struct target_s *target);
ntfreak's avatar
ntfreak committed
47
48
int mips_m4k_assert_reset(target_t *target);
int mips_m4k_deassert_reset(target_t *target);
49
int mips_m4k_checksum_memory(target_t *target, uint32_t address, uint32_t size, uint32_t *checksum);
ntfreak's avatar
ntfreak committed
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66

target_type_t mips_m4k_target =
{
	.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,
};

89
int mips_m4k_examine_debug_reason(target_t *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;
}

ntfreak's avatar
ntfreak committed
123
124
125
126
int mips_m4k_debug_entry(target_t *target)
{
	mips32_common_t *mips32 = target->arch_info;
	mips_ejtag_t *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
154
155
156
157
158
	return ERROR_OK;
}

int mips_m4k_poll(target_t *target)
{
	int retval;
	mips32_common_t *mips32 = target->arch_info;
	mips_ejtag_t *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
215
216
217
218
	return ERROR_OK;
}

int mips_m4k_halt(struct target_s *target)
{
	mips32_common_t *mips32 = target->arch_info;
	mips_ejtag_t *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
260
261
262
263
	return ERROR_OK;
}

int mips_m4k_assert_reset(target_t *target)
{
	mips32_common_t *mips32 = target->arch_info;
	mips_ejtag_t *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
322
323
	return ERROR_OK;
}

int mips_m4k_deassert_reset(target_t *target)
{
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
333
334
335
336
337
338
	return ERROR_OK;
}

int mips_m4k_soft_reset_halt(struct target_s *target)
{
	/* TODO */
	return ERROR_OK;
}

339
340
341
342
int mips_m4k_single_step_core(target_t *target)
{
	mips32_common_t *mips32 = target->arch_info;
	mips_ejtag_t *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;
}

358
int mips_m4k_resume(struct target_s *target, int current, uint32_t address, int handle_breakpoints, int debug_execution)
ntfreak's avatar
ntfreak committed
359
360
361
362
{
	mips32_common_t *mips32 = target->arch_info;
	mips_ejtag_t *ejtag_info = &mips32->ejtag_info;
	breakpoint_t *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;
}

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

	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
481
482
483
	return ERROR_OK;
}

void mips_m4k_enable_breakpoints(struct target_s *target)
{
	breakpoint_t *breakpoint = target->breakpoints;
484

ntfreak's avatar
ntfreak committed
485
486
487
488
489
490
491
492
493
494
495
	/* set any pending breakpoints */
	while (breakpoint)
	{
		if (breakpoint->set == 0)
			mips_m4k_set_breakpoint(target, breakpoint);
		breakpoint = breakpoint->next;
	}
}

int mips_m4k_set_breakpoint(struct target_s *target, breakpoint_t *breakpoint)
{
496
	mips32_common_t *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
585
586
	return ERROR_OK;
}

int mips_m4k_unset_breakpoint(struct target_s *target, breakpoint_t *breakpoint)
{
587
588
	/* get pointers to arch-specific information */
	mips32_common_t *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
660
661
	return ERROR_OK;
}

int mips_m4k_add_breakpoint(struct target_s *target, breakpoint_t *breakpoint)
{
662
	mips32_common_t *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
680
681
	return ERROR_OK;
}

int mips_m4k_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint)
{
682
683
	/* get pointers to arch-specific information */
	mips32_common_t *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;
}

702
int mips_m4k_set_watchpoint(struct target_s *target, struct watchpoint *watchpoint)
ntfreak's avatar
ntfreak committed
703
{
704
	mips32_common_t *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;
}

770
int mips_m4k_unset_watchpoint(struct target_s *target, struct watchpoint *watchpoint)
ntfreak's avatar
ntfreak committed
771
{
772
773
	/* get pointers to arch-specific information */
	mips32_common_t *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;
}

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

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

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

	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
833
834
	return ERROR_OK;
}

void mips_m4k_enable_watchpoints(struct target_s *target)
{
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;
	}
}

846
int mips_m4k_read_memory(struct target_s *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
ntfreak's avatar
ntfreak committed
847
848
849
{
	mips32_common_t *mips32 = target->arch_info;
	mips_ejtag_t *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
}

878
int mips_m4k_write_memory(struct target_s *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
ntfreak's avatar
ntfreak committed
879
880
881
{
	mips32_common_t *mips32 = target->arch_info;
	mips_ejtag_t *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
906
907
}

int mips_m4k_register_commands(struct command_context_s *cmd_ctx)
{
	int retval;
908

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

int mips_m4k_init_target(struct command_context_s *cmd_ctx, struct target_s *target)
{
	mips32_build_reg_cache(target);
916

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

920
int mips_m4k_init_arch_info(target_t *target, mips_m4k_common_t *mips_m4k, struct jtag_tap *tap)
ntfreak's avatar
ntfreak committed
921
922
{
	mips32_common_t *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;
}

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

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

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

ntfreak's avatar
ntfreak committed
942
int mips_m4k_examine(struct target_s *target)
ntfreak's avatar
ntfreak committed
943
944
945
946
{
	int retval;
	mips32_common_t *mips32 = target->arch_info;
	mips_ejtag_t *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;
}

973
int mips_m4k_bulk_write_memory(target_t *target, uint32_t address, uint32_t count, uint8_t *buffer)
ntfreak's avatar
ntfreak committed
974
975
976
{
	return mips_m4k_write_memory(target, address, 4, count, buffer);
}
977

978
int mips_m4k_checksum_memory(target_t *target, uint32_t address, uint32_t size, uint32_t *checksum)
979
980
981
{
	return ERROR_FAIL; /* use bulk read method */
}