mips32, add option to avoid check in last instruction
[openocd.git] / src / target / nds32_v3m.c
blob86903a51ba6ee75e61ef6884ed03b79aaea6da06
1 /***************************************************************************
2 * Copyright (C) 2013 Andes Technology *
3 * Hsiangkai Wang <hkwang@andestech.com> *
4 * *
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. *
9 * *
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. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
17 ***************************************************************************/
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
23 #include "breakpoints.h"
24 #include "nds32_cmd.h"
25 #include "nds32_aice.h"
26 #include "nds32_v3m.h"
27 #include "nds32_v3_common.h"
29 static int nds32_v3m_activate_hardware_breakpoint(struct target *target)
31 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
32 struct aice_port_s *aice = target_to_aice(target);
33 struct breakpoint *bp;
34 unsigned brp_num = nds32_v3m->n_hbr - 1;
36 for (bp = target->breakpoints; bp; bp = bp->next) {
37 if (bp->type == BKPT_SOFT) {
38 /* already set at nds32_v3m_add_breakpoint() */
39 continue;
40 } else if (bp->type == BKPT_HARD) {
41 /* set address */
42 aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + brp_num, bp->address);
43 /* set mask */
44 aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + brp_num, 0);
46 if (nds32_v3m->nds32.memory.address_translation)
47 /* enable breakpoint (virtual address) */
48 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0x2);
49 else
50 /* enable breakpoint (physical address) */
51 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0xA);
53 LOG_DEBUG("Add hardware BP %u at %08" TARGET_PRIxADDR, brp_num,
54 bp->address);
56 brp_num--;
57 } else {
58 return ERROR_FAIL;
62 return ERROR_OK;
65 static int nds32_v3m_deactivate_hardware_breakpoint(struct target *target)
67 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
68 struct aice_port_s *aice = target_to_aice(target);
69 struct breakpoint *bp;
70 unsigned brp_num = nds32_v3m->n_hbr - 1;
72 for (bp = target->breakpoints; bp; bp = bp->next) {
73 if (bp->type == BKPT_SOFT)
74 continue;
75 else if (bp->type == BKPT_HARD)
76 /* disable breakpoint */
77 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0x0);
78 else
79 return ERROR_FAIL;
81 LOG_DEBUG("Remove hardware BP %u at %08" TARGET_PRIxADDR, brp_num,
82 bp->address);
84 brp_num--;
87 return ERROR_OK;
90 static int nds32_v3m_activate_hardware_watchpoint(struct target *target)
92 struct aice_port_s *aice = target_to_aice(target);
93 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
94 struct watchpoint *wp;
95 int32_t wp_num = 0;
96 uint32_t wp_config = 0;
97 bool ld_stop, st_stop;
99 if (nds32_v3m->nds32.global_stop)
100 ld_stop = st_stop = false;
102 for (wp = target->watchpoints; wp; wp = wp->next) {
104 if (wp_num < nds32_v3m->used_n_wp) {
105 wp->mask = wp->length - 1;
106 if ((wp->address % wp->length) != 0)
107 wp->mask = (wp->mask << 1) + 1;
109 if (wp->rw == WPT_READ)
110 wp_config = 0x3;
111 else if (wp->rw == WPT_WRITE)
112 wp_config = 0x5;
113 else if (wp->rw == WPT_ACCESS)
114 wp_config = 0x7;
116 /* set/unset physical address bit of BPCn according to PSW.DT */
117 if (nds32_v3m->nds32.memory.address_translation == false)
118 wp_config |= 0x8;
120 /* set address */
121 aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + wp_num,
122 wp->address - (wp->address % wp->length));
123 /* set mask */
124 aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + wp_num, wp->mask);
125 /* enable watchpoint */
126 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, wp_config);
128 LOG_DEBUG("Add hardware watchpoint %" PRId32 " at %08" TARGET_PRIxADDR
129 " mask %08" PRIx32, wp_num, wp->address, wp->mask);
131 wp_num++;
132 } else if (nds32_v3m->nds32.global_stop) {
133 if (wp->rw == WPT_READ)
134 ld_stop = true;
135 else if (wp->rw == WPT_WRITE)
136 st_stop = true;
137 else if (wp->rw == WPT_ACCESS)
138 ld_stop = st_stop = true;
142 if (nds32_v3m->nds32.global_stop) {
143 uint32_t edm_ctl;
144 aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl);
145 if (ld_stop)
146 edm_ctl |= 0x10;
147 if (st_stop)
148 edm_ctl |= 0x20;
149 aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl);
152 return ERROR_OK;
155 static int nds32_v3m_deactivate_hardware_watchpoint(struct target *target)
157 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
158 struct aice_port_s *aice = target_to_aice(target);
159 struct watchpoint *wp;
160 int32_t wp_num = 0;
161 bool clean_global_stop = false;
163 for (wp = target->watchpoints; wp; wp = wp->next) {
165 if (wp_num < nds32_v3m->used_n_wp) {
166 /* disable watchpoint */
167 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, 0x0);
169 LOG_DEBUG("Remove hardware watchpoint %" PRId32 " at %08" TARGET_PRIxADDR
170 " mask %08" PRIx32, wp_num, wp->address, wp->mask);
171 wp_num++;
172 } else if (nds32_v3m->nds32.global_stop) {
173 clean_global_stop = true;
177 if (clean_global_stop) {
178 uint32_t edm_ctl;
179 aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl);
180 edm_ctl = edm_ctl & (~0x30);
181 aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl);
184 return ERROR_OK;
187 static int nds32_v3m_check_interrupt_stack(struct nds32 *nds32)
189 uint32_t val_ir0;
190 uint32_t value;
192 /* Save interrupt level */
193 nds32_get_mapped_reg(nds32, IR0, &val_ir0);
194 nds32->current_interrupt_level = (val_ir0 >> 1) & 0x3;
196 if (nds32_reach_max_interrupt_level(nds32))
197 LOG_ERROR("<-- TARGET ERROR! Reaching the max interrupt stack level %" PRIu32 ". -->",
198 nds32->current_interrupt_level);
200 /* backup $ir6 to avoid suppressed exception overwrite */
201 nds32_get_mapped_reg(nds32, IR6, &value);
203 return ERROR_OK;
206 static int nds32_v3m_restore_interrupt_stack(struct nds32 *nds32)
208 uint32_t value;
210 /* get backup value from cache */
211 /* then set back to make the register dirty */
212 nds32_get_mapped_reg(nds32, IR0, &value);
213 nds32_set_mapped_reg(nds32, IR0, value);
215 nds32_get_mapped_reg(nds32, IR6, &value);
216 nds32_set_mapped_reg(nds32, IR6, value);
218 return ERROR_OK;
221 static int nds32_v3m_deassert_reset(struct target *target)
223 int retval;
225 CHECK_RETVAL(nds32_poll(target));
227 if (target->state != TARGET_HALTED) {
228 /* reset only */
229 LOG_WARNING("%s: ran after reset and before halt ...",
230 target_name(target));
231 retval = target_halt(target);
232 if (retval != ERROR_OK)
233 return retval;
237 return ERROR_OK;
240 static int nds32_v3m_add_breakpoint(struct target *target,
241 struct breakpoint *breakpoint)
243 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
244 struct nds32 *nds32 = &(nds32_v3m->nds32);
245 int result;
247 if (breakpoint->type == BKPT_HARD) {
248 /* check hardware resource */
249 if (nds32_v3m->next_hbr_index < nds32_v3m->next_hwp_index) {
250 LOG_WARNING("<-- TARGET WARNING! Insert too many "
251 "hardware breakpoints/watchpoints! "
252 "The limit of combined hardware "
253 "breakpoints/watchpoints is %" PRId32 ". -->",
254 nds32_v3m->n_hbr);
255 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
256 "hardware breakpoint: %" PRId32 ", hardware "
257 "watchpoints: %" PRId32 ". -->",
258 nds32_v3m->n_hbr - nds32_v3m->next_hbr_index - 1,
259 nds32_v3m->used_n_wp);
260 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
263 /* update next place to put hardware breakpoint */
264 nds32_v3m->next_hbr_index--;
266 /* hardware breakpoint insertion occurs before 'continue' actually */
267 return ERROR_OK;
268 } else if (breakpoint->type == BKPT_SOFT) {
269 result = nds32_add_software_breakpoint(target, breakpoint);
270 if (ERROR_OK != result) {
271 /* auto convert to hardware breakpoint if failed */
272 if (nds32->auto_convert_hw_bp) {
273 /* convert to hardware breakpoint */
274 breakpoint->type = BKPT_HARD;
276 return nds32_v3m_add_breakpoint(target, breakpoint);
280 return result;
281 } else /* unrecognized breakpoint type */
282 return ERROR_FAIL;
284 return ERROR_OK;
287 static int nds32_v3m_remove_breakpoint(struct target *target,
288 struct breakpoint *breakpoint)
290 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
292 if (breakpoint->type == BKPT_HARD) {
293 if (nds32_v3m->next_hbr_index >= nds32_v3m->n_hbr - 1)
294 return ERROR_FAIL;
296 /* update next place to put hardware breakpoint */
297 nds32_v3m->next_hbr_index++;
299 /* hardware breakpoint removal occurs after 'halted' actually */
300 return ERROR_OK;
301 } else if (breakpoint->type == BKPT_SOFT) {
302 return nds32_remove_software_breakpoint(target, breakpoint);
303 } else /* unrecognized breakpoint type */
304 return ERROR_FAIL;
306 return ERROR_OK;
309 static int nds32_v3m_add_watchpoint(struct target *target,
310 struct watchpoint *watchpoint)
312 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
314 /* check hardware resource */
315 if (nds32_v3m->next_hwp_index >= nds32_v3m->n_hwp) {
316 /* No hardware resource */
317 if (nds32_v3m->nds32.global_stop) {
318 LOG_WARNING("<-- TARGET WARNING! The number of "
319 "watchpoints exceeds the hardware "
320 "resources. Stop at every load/store "
321 "instruction to check for watchpoint matches. -->");
322 return ERROR_OK;
325 LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
326 "watchpoints! The limit of hardware watchpoints "
327 "is %" PRId32 ". -->", nds32_v3m->n_hwp);
328 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
329 "hardware watchpoint: %" PRId32 ". -->",
330 nds32_v3m->used_n_wp);
331 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
334 if (nds32_v3m->next_hwp_index > nds32_v3m->next_hbr_index) {
335 /* No hardware resource */
336 if (nds32_v3m->nds32.global_stop) {
337 LOG_WARNING("<-- TARGET WARNING! The number of "
338 "watchpoints exceeds the hardware "
339 "resources. Stop at every load/store "
340 "instruction to check for watchpoint matches. -->");
341 return ERROR_OK;
344 LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
345 "breakpoints/watchpoints! The limit of combined "
346 "hardware breakpoints/watchpoints is %" PRId32 ". -->",
347 nds32_v3m->n_hbr);
348 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
349 "hardware breakpoint: %" PRId32 ", hardware "
350 "watchpoints: %" PRId32 ". -->",
351 nds32_v3m->n_hbr - nds32_v3m->next_hbr_index - 1,
352 nds32_v3m->used_n_wp);
353 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
356 /* update next place to put hardware watchpoint */
357 nds32_v3m->next_hwp_index++;
358 nds32_v3m->used_n_wp++;
360 return ERROR_OK;
363 static int nds32_v3m_remove_watchpoint(struct target *target,
364 struct watchpoint *watchpoint)
366 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
368 if (nds32_v3m->next_hwp_index <= 0) {
369 if (nds32_v3m->nds32.global_stop)
370 return ERROR_OK;
372 return ERROR_FAIL;
375 /* update next place to put hardware watchpoint */
376 nds32_v3m->next_hwp_index--;
377 nds32_v3m->used_n_wp--;
379 return ERROR_OK;
382 struct nds32_v3_common_callback nds32_v3m_common_callback = {
383 .check_interrupt_stack = nds32_v3m_check_interrupt_stack,
384 .restore_interrupt_stack = nds32_v3m_restore_interrupt_stack,
385 .activate_hardware_breakpoint = nds32_v3m_activate_hardware_breakpoint,
386 .activate_hardware_watchpoint = nds32_v3m_activate_hardware_watchpoint,
387 .deactivate_hardware_breakpoint = nds32_v3m_deactivate_hardware_breakpoint,
388 .deactivate_hardware_watchpoint = nds32_v3m_deactivate_hardware_watchpoint,
391 static int nds32_v3m_target_create(struct target *target, Jim_Interp *interp)
393 struct nds32_v3m_common *nds32_v3m;
395 nds32_v3m = calloc(1, sizeof(*nds32_v3m));
396 if (!nds32_v3m)
397 return ERROR_FAIL;
399 nds32_v3_common_register_callback(&nds32_v3m_common_callback);
400 nds32_v3_target_create_common(target, &(nds32_v3m->nds32));
402 return ERROR_OK;
405 /* talk to the target and set things up */
406 static int nds32_v3m_examine(struct target *target)
408 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
409 struct nds32 *nds32 = &(nds32_v3m->nds32);
410 struct aice_port_s *aice = target_to_aice(target);
412 if (!target_was_examined(target)) {
413 CHECK_RETVAL(nds32_edm_config(nds32));
415 if (nds32->reset_halt_as_examine)
416 CHECK_RETVAL(nds32_reset_halt(nds32));
419 uint32_t edm_cfg;
420 aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CFG, &edm_cfg);
422 /* get the number of hardware breakpoints */
423 nds32_v3m->n_hbr = (edm_cfg & 0x7) + 1;
424 nds32_v3m->used_n_wp = 0;
426 /* get the number of hardware watchpoints */
427 /* If the WP field is hardwired to zero, it means this is a
428 * simple breakpoint. Otherwise, if the WP field is writable
429 * then it means this is a regular watchpoints. */
430 nds32_v3m->n_hwp = 0;
431 for (int32_t i = 0 ; i < nds32_v3m->n_hbr ; i++) {
432 /** check the hardware breakpoint is simple or not */
433 uint32_t tmp_value;
434 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + i, 0x1);
435 aice_read_debug_reg(aice, NDS_EDM_SR_BPC0 + i, &tmp_value);
437 if (tmp_value)
438 nds32_v3m->n_hwp++;
440 /* hardware breakpoint is inserted from high index to low index */
441 nds32_v3m->next_hbr_index = nds32_v3m->n_hbr - 1;
442 /* hardware watchpoint is inserted from low index to high index */
443 nds32_v3m->next_hwp_index = 0;
445 LOG_INFO("%s: total hardware breakpoint %" PRId32 " (simple breakpoint %" PRId32 ")",
446 target_name(target), nds32_v3m->n_hbr, nds32_v3m->n_hbr - nds32_v3m->n_hwp);
447 LOG_INFO("%s: total hardware watchpoint %" PRId32, target_name(target), nds32_v3m->n_hwp);
449 nds32->target->state = TARGET_RUNNING;
450 nds32->target->debug_reason = DBG_REASON_NOTHALTED;
452 target_set_examined(target);
454 return ERROR_OK;
457 /** Holds methods for NDS32 V3m targets. */
458 struct target_type nds32_v3m_target = {
459 .name = "nds32_v3m",
461 .poll = nds32_poll,
462 .arch_state = nds32_arch_state,
464 .target_request_data = nds32_v3_target_request_data,
466 .halt = nds32_halt,
467 .resume = nds32_resume,
468 .step = nds32_step,
470 .assert_reset = nds32_assert_reset,
471 .deassert_reset = nds32_v3m_deassert_reset,
473 /* register access */
474 .get_gdb_reg_list = nds32_get_gdb_reg_list,
476 /* memory access */
477 .read_buffer = nds32_v3_read_buffer,
478 .write_buffer = nds32_v3_write_buffer,
479 .read_memory = nds32_v3_read_memory,
480 .write_memory = nds32_v3_write_memory,
482 .checksum_memory = nds32_v3_checksum_memory,
484 /* breakpoint/watchpoint */
485 .add_breakpoint = nds32_v3m_add_breakpoint,
486 .remove_breakpoint = nds32_v3m_remove_breakpoint,
487 .add_watchpoint = nds32_v3m_add_watchpoint,
488 .remove_watchpoint = nds32_v3m_remove_watchpoint,
489 .hit_watchpoint = nds32_v3_hit_watchpoint,
491 /* MMU */
492 .mmu = nds32_mmu,
493 .virt2phys = nds32_virtual_to_physical,
494 .read_phys_memory = nds32_read_phys_memory,
495 .write_phys_memory = nds32_write_phys_memory,
497 .run_algorithm = nds32_v3_run_algorithm,
499 .commands = nds32_command_handlers,
500 .target_create = nds32_v3m_target_create,
501 .init_target = nds32_v3_init_target,
502 .examine = nds32_v3m_examine,
504 .get_gdb_fileio_info = nds32_get_gdb_fileio_info,
505 .gdb_fileio_end = nds32_gdb_fileio_end,