1 /***************************************************************************
2 * Copyright (C) 2013 Andes Technology *
3 * Hsiangkai Wang <hkwang@andestech.com> *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
19 ***************************************************************************/
25 #include "breakpoints.h"
26 #include "nds32_cmd.h"
27 #include "nds32_aice.h"
28 #include "nds32_v3m.h"
29 #include "nds32_v3_common.h"
31 static int nds32_v3m_activate_hardware_breakpoint(struct target *target)
33 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
34 struct aice_port_s *aice = target_to_aice(target);
35 struct breakpoint *bp;
36 unsigned brp_num = nds32_v3m->n_hbr - 1;
38 for (bp = target->breakpoints; bp; bp = bp->next) {
39 if (bp->type == BKPT_SOFT) {
40 /* already set at nds32_v3m_add_breakpoint() */
42 } else if (bp->type == BKPT_HARD) {
44 aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + brp_num, bp->address);
46 aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + brp_num, 0);
48 if (nds32_v3m->nds32.memory.address_translation)
49 /* enable breakpoint (virtual address) */
50 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0x2);
52 /* enable breakpoint (physical address) */
53 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0xA);
55 LOG_DEBUG("Add hardware BP %u at %08" PRIx32, brp_num,
67 static int nds32_v3m_deactivate_hardware_breakpoint(struct target *target)
69 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
70 struct aice_port_s *aice = target_to_aice(target);
71 struct breakpoint *bp;
72 unsigned brp_num = nds32_v3m->n_hbr - 1;
74 for (bp = target->breakpoints; bp; bp = bp->next) {
75 if (bp->type == BKPT_SOFT)
77 else if (bp->type == BKPT_HARD)
78 /* disable breakpoint */
79 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0x0);
83 LOG_DEBUG("Remove hardware BP %u at %08" PRIx32, brp_num,
92 static int nds32_v3m_activate_hardware_watchpoint(struct target *target)
94 struct aice_port_s *aice = target_to_aice(target);
95 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
96 struct watchpoint *wp;
98 uint32_t wp_config = 0;
99 bool ld_stop, st_stop;
101 if (nds32_v3m->nds32.global_stop)
102 ld_stop = st_stop = false;
104 for (wp = target->watchpoints; wp; wp = wp->next) {
106 if (wp_num < nds32_v3m->used_n_wp) {
107 wp->mask = wp->length - 1;
108 if ((wp->address % wp->length) != 0)
109 wp->mask = (wp->mask << 1) + 1;
111 if (wp->rw == WPT_READ)
113 else if (wp->rw == WPT_WRITE)
115 else if (wp->rw == WPT_ACCESS)
118 /* set/unset physical address bit of BPCn according to PSW.DT */
119 if (nds32_v3m->nds32.memory.address_translation == false)
123 aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + wp_num,
124 wp->address - (wp->address % wp->length));
126 aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + wp_num, wp->mask);
127 /* enable watchpoint */
128 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, wp_config);
130 LOG_DEBUG("Add hardware wathcpoint %" PRId32 " at %08" PRIx32
131 " mask %08" PRIx32, wp_num, wp->address, wp->mask);
134 } else if (nds32_v3m->nds32.global_stop) {
135 if (wp->rw == WPT_READ)
137 else if (wp->rw == WPT_WRITE)
139 else if (wp->rw == WPT_ACCESS)
140 ld_stop = st_stop = true;
144 if (nds32_v3m->nds32.global_stop) {
146 aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl);
151 aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl);
157 static int nds32_v3m_deactivate_hardware_watchpoint(struct target *target)
159 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
160 struct aice_port_s *aice = target_to_aice(target);
161 struct watchpoint *wp;
163 bool clean_global_stop = false;
165 for (wp = target->watchpoints; wp; wp = wp->next) {
167 if (wp_num < nds32_v3m->used_n_wp) {
168 /* disable watchpoint */
169 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, 0x0);
171 LOG_DEBUG("Remove hardware wathcpoint %" PRId32 " at %08" PRIx32
172 " mask %08" PRIx32, wp_num, wp->address, wp->mask);
174 } else if (nds32_v3m->nds32.global_stop) {
175 clean_global_stop = true;
179 if (clean_global_stop) {
181 aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl);
182 edm_ctl = edm_ctl & (~0x30);
183 aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl);
189 static int nds32_v3m_check_interrupt_stack(struct nds32 *nds32)
194 /* Save interrupt level */
195 nds32_get_mapped_reg(nds32, IR0, &val_ir0);
196 nds32->current_interrupt_level = (val_ir0 >> 1) & 0x3;
198 if (nds32_reach_max_interrupt_level(nds32))
199 LOG_ERROR("<-- TARGET ERROR! Reaching the max interrupt stack level %" PRIu32 ". -->",
200 nds32->current_interrupt_level);
202 /* backup $ir6 to avoid suppressed exception overwrite */
203 nds32_get_mapped_reg(nds32, IR6, &value);
208 static int nds32_v3m_restore_interrupt_stack(struct nds32 *nds32)
212 /* get backup value from cache */
213 /* then set back to make the register dirty */
214 nds32_get_mapped_reg(nds32, IR0, &value);
215 nds32_set_mapped_reg(nds32, IR0, value);
217 nds32_get_mapped_reg(nds32, IR6, &value);
218 nds32_set_mapped_reg(nds32, IR6, value);
223 static int nds32_v3m_deassert_reset(struct target *target)
227 CHECK_RETVAL(nds32_poll(target));
229 if (target->state != TARGET_HALTED) {
231 LOG_WARNING("%s: ran after reset and before halt ...",
232 target_name(target));
233 retval = target_halt(target);
234 if (retval != ERROR_OK)
242 static int nds32_v3m_add_breakpoint(struct target *target,
243 struct breakpoint *breakpoint)
245 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
246 struct nds32 *nds32 = &(nds32_v3m->nds32);
249 if (breakpoint->type == BKPT_HARD) {
250 /* check hardware resource */
251 if (nds32_v3m->next_hbr_index < nds32_v3m->next_hwp_index) {
252 LOG_WARNING("<-- TARGET WARNING! Insert too many "
253 "hardware breakpoints/watchpoints! "
254 "The limit of combined hardware "
255 "breakpoints/watchpoints is %" PRId32 ". -->",
257 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
258 "hardware breakpoint: %" PRId32 ", hardware "
259 "watchpoints: %" PRId32 ". -->",
260 nds32_v3m->n_hbr - nds32_v3m->next_hbr_index - 1,
261 nds32_v3m->used_n_wp);
262 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
265 /* update next place to put hardware breakpoint */
266 nds32_v3m->next_hbr_index--;
268 /* hardware breakpoint insertion occurs before 'continue' actually */
270 } else if (breakpoint->type == BKPT_SOFT) {
271 result = nds32_add_software_breakpoint(target, breakpoint);
272 if (ERROR_OK != result) {
273 /* auto convert to hardware breakpoint if failed */
274 if (nds32->auto_convert_hw_bp) {
275 /* convert to hardware breakpoint */
276 breakpoint->type = BKPT_HARD;
278 return nds32_v3m_add_breakpoint(target, breakpoint);
283 } else /* unrecognized breakpoint type */
289 static int nds32_v3m_remove_breakpoint(struct target *target,
290 struct breakpoint *breakpoint)
292 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
294 if (breakpoint->type == BKPT_HARD) {
295 if (nds32_v3m->next_hbr_index >= nds32_v3m->n_hbr - 1)
298 /* update next place to put hardware breakpoint */
299 nds32_v3m->next_hbr_index++;
301 /* hardware breakpoint removal occurs after 'halted' actually */
303 } else if (breakpoint->type == BKPT_SOFT) {
304 return nds32_remove_software_breakpoint(target, breakpoint);
305 } else /* unrecognized breakpoint type */
311 static int nds32_v3m_add_watchpoint(struct target *target,
312 struct watchpoint *watchpoint)
314 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
316 /* check hardware resource */
317 if (nds32_v3m->next_hwp_index >= nds32_v3m->n_hwp) {
318 /* No hardware resource */
319 if (nds32_v3m->nds32.global_stop) {
320 LOG_WARNING("<-- TARGET WARNING! The number of "
321 "watchpoints exceeds the hardware "
322 "resources. Stop at every load/store "
323 "instruction to check for watchpoint matches. -->");
327 LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
328 "watchpoints! The limit of hardware watchpoints "
329 "is %" PRId32 ". -->", nds32_v3m->n_hwp);
330 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
331 "hardware watchpoint: %" PRId32 ". -->",
332 nds32_v3m->used_n_wp);
333 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
336 if (nds32_v3m->next_hwp_index > nds32_v3m->next_hbr_index) {
337 /* No hardware resource */
338 if (nds32_v3m->nds32.global_stop) {
339 LOG_WARNING("<-- TARGET WARNING! The number of "
340 "watchpoints exceeds the hardware "
341 "resources. Stop at every load/store "
342 "instruction to check for watchpoint matches. -->");
346 LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
347 "breakpoints/watchpoints! The limit of combined "
348 "hardware breakpoints/watchpoints is %" PRId32 ". -->",
350 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
351 "hardware breakpoint: %" PRId32 ", hardware "
352 "watchpoints: %" PRId32 ". -->",
353 nds32_v3m->n_hbr - nds32_v3m->next_hbr_index - 1,
354 nds32_v3m->used_n_wp);
355 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
358 /* update next place to put hardware watchpoint */
359 nds32_v3m->next_hwp_index++;
360 nds32_v3m->used_n_wp++;
365 static int nds32_v3m_remove_watchpoint(struct target *target,
366 struct watchpoint *watchpoint)
368 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
370 if (nds32_v3m->next_hwp_index <= 0) {
371 if (nds32_v3m->nds32.global_stop)
377 /* update next place to put hardware watchpoint */
378 nds32_v3m->next_hwp_index--;
379 nds32_v3m->used_n_wp--;
384 struct nds32_v3_common_callback nds32_v3m_common_callback = {
385 .check_interrupt_stack = nds32_v3m_check_interrupt_stack,
386 .restore_interrupt_stack = nds32_v3m_restore_interrupt_stack,
387 .activate_hardware_breakpoint = nds32_v3m_activate_hardware_breakpoint,
388 .activate_hardware_watchpoint = nds32_v3m_activate_hardware_watchpoint,
389 .deactivate_hardware_breakpoint = nds32_v3m_deactivate_hardware_breakpoint,
390 .deactivate_hardware_watchpoint = nds32_v3m_deactivate_hardware_watchpoint,
393 static int nds32_v3m_target_create(struct target *target, Jim_Interp *interp)
395 struct nds32_v3m_common *nds32_v3m;
397 nds32_v3m = calloc(1, sizeof(*nds32_v3m));
401 nds32_v3_common_register_callback(&nds32_v3m_common_callback);
402 nds32_v3_target_create_common(target, &(nds32_v3m->nds32));
407 /* talk to the target and set things up */
408 static int nds32_v3m_examine(struct target *target)
410 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
411 struct nds32 *nds32 = &(nds32_v3m->nds32);
412 struct aice_port_s *aice = target_to_aice(target);
414 if (!target_was_examined(target)) {
415 CHECK_RETVAL(nds32_edm_config(nds32));
417 if (nds32->reset_halt_as_examine)
418 CHECK_RETVAL(nds32_reset_halt(nds32));
422 aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CFG, &edm_cfg);
424 /* get the number of hardware breakpoints */
425 nds32_v3m->n_hbr = (edm_cfg & 0x7) + 1;
426 nds32_v3m->used_n_wp = 0;
428 /* get the number of hardware watchpoints */
429 /* If the WP field is hardwired to zero, it means this is a
430 * simple breakpoint. Otherwise, if the WP field is writable
431 * then it means this is a regular watchpoints. */
432 nds32_v3m->n_hwp = 0;
433 for (int32_t i = 0 ; i < nds32_v3m->n_hbr ; i++) {
434 /** check the hardware breakpoint is simple or not */
436 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + i, 0x1);
437 aice_read_debug_reg(aice, NDS_EDM_SR_BPC0 + i, &tmp_value);
442 /* hardware breakpoint is inserted from high index to low index */
443 nds32_v3m->next_hbr_index = nds32_v3m->n_hbr - 1;
444 /* hardware watchpoint is inserted from low index to high index */
445 nds32_v3m->next_hwp_index = 0;
447 LOG_INFO("%s: total hardware breakpoint %" PRId32 " (simple breakpoint %" PRId32 ")",
448 target_name(target), nds32_v3m->n_hbr, nds32_v3m->n_hbr - nds32_v3m->n_hwp);
449 LOG_INFO("%s: total hardware watchpoint %" PRId32, target_name(target), nds32_v3m->n_hwp);
451 nds32->target->state = TARGET_RUNNING;
452 nds32->target->debug_reason = DBG_REASON_NOTHALTED;
454 target_set_examined(target);
459 /** Holds methods for NDS32 V3m targets. */
460 struct target_type nds32_v3m_target = {
464 .arch_state = nds32_arch_state,
466 .target_request_data = nds32_v3_target_request_data,
469 .resume = nds32_resume,
472 .assert_reset = nds32_assert_reset,
473 .deassert_reset = nds32_v3m_deassert_reset,
475 /* register access */
476 .get_gdb_reg_list = nds32_get_gdb_reg_list,
479 .read_buffer = nds32_v3_read_buffer,
480 .write_buffer = nds32_v3_write_buffer,
481 .read_memory = nds32_v3_read_memory,
482 .write_memory = nds32_v3_write_memory,
484 .checksum_memory = nds32_v3_checksum_memory,
486 /* breakpoint/watchpoint */
487 .add_breakpoint = nds32_v3m_add_breakpoint,
488 .remove_breakpoint = nds32_v3m_remove_breakpoint,
489 .add_watchpoint = nds32_v3m_add_watchpoint,
490 .remove_watchpoint = nds32_v3m_remove_watchpoint,
491 .hit_watchpoint = nds32_v3_hit_watchpoint,
495 .virt2phys = nds32_virtual_to_physical,
496 .read_phys_memory = nds32_read_phys_memory,
497 .write_phys_memory = nds32_write_phys_memory,
499 .run_algorithm = nds32_v3_run_algorithm,
501 .commands = nds32_command_handlers,
502 .target_create = nds32_v3m_target_create,
503 .init_target = nds32_v3_init_target,
504 .examine = nds32_v3m_examine,
506 .get_gdb_fileio_info = nds32_get_gdb_fileio_info,
507 .gdb_fileio_end = nds32_gdb_fileio_end,