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, see <http://www.gnu.org/licenses/>. *
17 ***************************************************************************/
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() */
40 } else if (bp
->type
== BKPT_HARD
) {
42 aice_write_debug_reg(aice
, NDS_EDM_SR_BPA0
+ brp_num
, bp
->address
);
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);
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
,
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
)
75 else if (bp
->type
== BKPT_HARD
)
76 /* disable breakpoint */
77 aice_write_debug_reg(aice
, NDS_EDM_SR_BPC0
+ brp_num
, 0x0);
81 LOG_DEBUG("Remove hardware BP %u at %08" TARGET_PRIxADDR
, brp_num
,
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
;
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
)
111 else if (wp
->rw
== WPT_WRITE
)
113 else if (wp
->rw
== WPT_ACCESS
)
116 /* set/unset physical address bit of BPCn according to PSW.DT */
117 if (nds32_v3m
->nds32
.memory
.address_translation
== false)
121 aice_write_debug_reg(aice
, NDS_EDM_SR_BPA0
+ wp_num
,
122 wp
->address
- (wp
->address
% wp
->length
));
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
);
132 } else if (nds32_v3m
->nds32
.global_stop
) {
133 if (wp
->rw
== WPT_READ
)
135 else if (wp
->rw
== WPT_WRITE
)
137 else if (wp
->rw
== WPT_ACCESS
)
138 ld_stop
= st_stop
= true;
142 if (nds32_v3m
->nds32
.global_stop
) {
144 aice_read_debug_reg(aice
, NDS_EDM_SR_EDM_CTL
, &edm_ctl
);
149 aice_write_debug_reg(aice
, NDS_EDM_SR_EDM_CTL
, edm_ctl
);
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
;
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
);
172 } else if (nds32_v3m
->nds32
.global_stop
) {
173 clean_global_stop
= true;
177 if (clean_global_stop
) {
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
);
187 static int nds32_v3m_check_interrupt_stack(struct nds32
*nds32
)
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
);
206 static int nds32_v3m_restore_interrupt_stack(struct nds32
*nds32
)
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
);
221 static int nds32_v3m_deassert_reset(struct target
*target
)
225 CHECK_RETVAL(nds32_poll(target
));
227 if (target
->state
!= TARGET_HALTED
) {
229 LOG_WARNING("%s: ran after reset and before halt ...",
230 target_name(target
));
231 retval
= target_halt(target
);
232 if (retval
!= 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
);
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
". -->",
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 */
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
);
281 } else /* unrecognized breakpoint type */
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)
296 /* update next place to put hardware breakpoint */
297 nds32_v3m
->next_hbr_index
++;
299 /* hardware breakpoint removal occurs after 'halted' actually */
301 } else if (breakpoint
->type
== BKPT_SOFT
) {
302 return nds32_remove_software_breakpoint(target
, breakpoint
);
303 } else /* unrecognized breakpoint type */
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. -->");
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. -->");
344 LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
345 "breakpoints/watchpoints! The limit of combined "
346 "hardware breakpoints/watchpoints is %" PRId32
". -->",
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
++;
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
)
375 /* update next place to put hardware watchpoint */
376 nds32_v3m
->next_hwp_index
--;
377 nds32_v3m
->used_n_wp
--;
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
));
399 nds32_v3_common_register_callback(&nds32_v3m_common_callback
);
400 nds32_v3_target_create_common(target
, &(nds32_v3m
->nds32
));
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
));
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 */
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
);
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
);
457 /** Holds methods for NDS32 V3m targets. */
458 struct target_type nds32_v3m_target
= {
462 .arch_state
= nds32_arch_state
,
464 .target_request_data
= nds32_v3_target_request_data
,
467 .resume
= nds32_resume
,
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
,
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
,
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
,
Linking to existing account procedure
If you already have an account and want to add another login method
you
MUST first sign in with your existing account and
then change URL to read
https://review.openocd.org/login/?link
to get to this page again but this time it'll work for linking. Thank you.
SSH host keys fingerprints
1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=.. |
|+o.. . |
|*.o . . |
|+B . . . |
|Bo. = o S |
|Oo.+ + = |
|oB=.* = . o |
| =+=.+ + E |
|. .=o . o |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)