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 %d 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 %d 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 %d at %08" PRIx32
131 " mask %08" PRIx32
, wp_num
,
132 wp
->address
, wp
->mask
);
135 } else if (nds32_v3m
->nds32
.global_stop
) {
136 if (wp
->rw
== WPT_READ
)
138 else if (wp
->rw
== WPT_WRITE
)
140 else if (wp
->rw
== WPT_ACCESS
)
141 ld_stop
= st_stop
= true;
145 if (nds32_v3m
->nds32
.global_stop
) {
147 aice_read_debug_reg(aice
, NDS_EDM_SR_EDM_CTL
, &edm_ctl
);
152 aice_write_debug_reg(aice
, NDS_EDM_SR_EDM_CTL
, edm_ctl
);
158 static int nds32_v3m_deactivate_hardware_watchpoint(struct target
*target
)
160 struct nds32_v3m_common
*nds32_v3m
= target_to_nds32_v3m(target
);
161 struct aice_port_s
*aice
= target_to_aice(target
);
162 struct watchpoint
*wp
;
164 bool clean_global_stop
= false;
166 for (wp
= target
->watchpoints
; wp
; wp
= wp
->next
) {
168 if (wp_num
< nds32_v3m
->used_n_wp
) {
169 /* disable watchpoint */
170 aice_write_debug_reg(aice
, NDS_EDM_SR_BPC0
+ wp_num
, 0x0);
172 LOG_DEBUG("Remove hardware wathcpoint %d at %08" PRIx32
173 " mask %08" PRIx32
, wp_num
,
174 wp
->address
, wp
->mask
);
176 } else if (nds32_v3m
->nds32
.global_stop
) {
177 clean_global_stop
= true;
181 if (clean_global_stop
) {
183 aice_read_debug_reg(aice
, NDS_EDM_SR_EDM_CTL
, &edm_ctl
);
184 edm_ctl
= edm_ctl
& (~0x30);
185 aice_write_debug_reg(aice
, NDS_EDM_SR_EDM_CTL
, edm_ctl
);
191 static int nds32_v3m_check_interrupt_stack(struct nds32
*nds32
)
196 /* Save interrupt level */
197 nds32_get_mapped_reg(nds32
, IR0
, &val_ir0
);
198 nds32
->current_interrupt_level
= (val_ir0
>> 1) & 0x3;
200 if (nds32_reach_max_interrupt_level(nds32
))
201 LOG_ERROR("<-- TARGET ERROR! Reaching the max interrupt stack level %d. -->",
202 nds32
->current_interrupt_level
);
204 /* backup $ir6 to avoid suppressed exception overwrite */
205 nds32_get_mapped_reg(nds32
, IR6
, &value
);
210 static int nds32_v3m_restore_interrupt_stack(struct nds32
*nds32
)
214 /* get backup value from cache */
215 /* then set back to make the register dirty */
216 nds32_get_mapped_reg(nds32
, IR0
, &value
);
217 nds32_set_mapped_reg(nds32
, IR0
, value
);
219 nds32_get_mapped_reg(nds32
, IR6
, &value
);
220 nds32_set_mapped_reg(nds32
, IR6
, value
);
225 static int nds32_v3m_deassert_reset(struct target
*target
)
229 CHECK_RETVAL(nds32_poll(target
));
231 if (target
->state
!= TARGET_HALTED
) {
233 LOG_WARNING("%s: ran after reset and before halt ...",
234 target_name(target
));
235 retval
= target_halt(target
);
236 if (retval
!= ERROR_OK
)
244 static int nds32_v3m_add_breakpoint(struct target
*target
,
245 struct breakpoint
*breakpoint
)
247 struct nds32_v3m_common
*nds32_v3m
= target_to_nds32_v3m(target
);
248 struct nds32
*nds32
= &(nds32_v3m
->nds32
);
251 if (breakpoint
->type
== BKPT_HARD
) {
252 /* check hardware resource */
253 if (nds32_v3m
->next_hbr_index
< nds32_v3m
->next_hwp_index
) {
254 LOG_WARNING("<-- TARGET WARNING! Insert too many "
255 "hardware breakpoints/watchpoints! "
256 "The limit of combined hardware "
257 "breakpoints/watchpoints is %d. -->",
259 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
260 "hardware breakpoint: %d, hardware "
261 "watchpoints: %d. -->",
262 nds32_v3m
->n_hbr
- nds32_v3m
->next_hbr_index
- 1,
263 nds32_v3m
->used_n_wp
);
264 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
267 /* update next place to put hardware breakpoint */
268 nds32_v3m
->next_hbr_index
--;
270 /* hardware breakpoint insertion occurs before 'continue' actually */
272 } else if (breakpoint
->type
== BKPT_SOFT
) {
273 result
= nds32_add_software_breakpoint(target
, breakpoint
);
274 if (ERROR_OK
!= result
) {
275 /* auto convert to hardware breakpoint if failed */
276 if (nds32
->auto_convert_hw_bp
) {
277 /* convert to hardware breakpoint */
278 breakpoint
->type
= BKPT_HARD
;
280 return nds32_v3m_add_breakpoint(target
, breakpoint
);
285 } else /* unrecognized breakpoint type */
291 static int nds32_v3m_remove_breakpoint(struct target
*target
,
292 struct breakpoint
*breakpoint
)
294 struct nds32_v3m_common
*nds32_v3m
= target_to_nds32_v3m(target
);
296 if (breakpoint
->type
== BKPT_HARD
) {
297 if (nds32_v3m
->next_hbr_index
>= nds32_v3m
->n_hbr
- 1)
300 /* update next place to put hardware breakpoint */
301 nds32_v3m
->next_hbr_index
++;
303 /* hardware breakpoint removal occurs after 'halted' actually */
305 } else if (breakpoint
->type
== BKPT_SOFT
) {
306 return nds32_remove_software_breakpoint(target
, breakpoint
);
307 } else /* unrecognized breakpoint type */
313 static int nds32_v3m_add_watchpoint(struct target
*target
,
314 struct watchpoint
*watchpoint
)
316 struct nds32_v3m_common
*nds32_v3m
= target_to_nds32_v3m(target
);
318 /* check hardware resource */
319 if (nds32_v3m
->next_hwp_index
>= nds32_v3m
->n_hwp
) {
320 /* No hardware resource */
321 if (nds32_v3m
->nds32
.global_stop
) {
322 LOG_WARNING("<-- TARGET WARNING! The number of "
323 "watchpoints exceeds the hardware "
324 "resources. Stop at every load/store "
325 "instruction to check for watchpoint matches. -->");
329 LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
330 "watchpoints! The limit of hardware watchpoints "
331 "is %d. -->", nds32_v3m
->n_hwp
);
332 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
333 "hardware watchpoint: %d. -->",
334 nds32_v3m
->used_n_wp
);
335 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
338 if (nds32_v3m
->next_hwp_index
> nds32_v3m
->next_hbr_index
) {
339 /* No hardware resource */
340 if (nds32_v3m
->nds32
.global_stop
) {
341 LOG_WARNING("<-- TARGET WARNING! The number of "
342 "watchpoints exceeds the hardware "
343 "resources. Stop at every load/store "
344 "instruction to check for watchpoint matches. -->");
348 LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
349 "breakpoints/watchpoints! The limit of combined "
350 "hardware breakpoints/watchpoints is %d. -->",
352 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
353 "hardware breakpoint: %d, hardware "
354 "watchpoints: %d. -->",
355 nds32_v3m
->n_hbr
- nds32_v3m
->next_hbr_index
- 1,
356 nds32_v3m
->used_n_wp
);
357 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
360 /* update next place to put hardware watchpoint */
361 nds32_v3m
->next_hwp_index
++;
362 nds32_v3m
->used_n_wp
++;
367 static int nds32_v3m_remove_watchpoint(struct target
*target
,
368 struct watchpoint
*watchpoint
)
370 struct nds32_v3m_common
*nds32_v3m
= target_to_nds32_v3m(target
);
372 if (nds32_v3m
->next_hwp_index
<= 0) {
373 if (nds32_v3m
->nds32
.global_stop
)
379 /* update next place to put hardware watchpoint */
380 nds32_v3m
->next_hwp_index
--;
381 nds32_v3m
->used_n_wp
--;
386 struct nds32_v3_common_callback nds32_v3m_common_callback
= {
387 .check_interrupt_stack
= nds32_v3m_check_interrupt_stack
,
388 .restore_interrupt_stack
= nds32_v3m_restore_interrupt_stack
,
389 .activate_hardware_breakpoint
= nds32_v3m_activate_hardware_breakpoint
,
390 .activate_hardware_watchpoint
= nds32_v3m_activate_hardware_watchpoint
,
391 .deactivate_hardware_breakpoint
= nds32_v3m_deactivate_hardware_breakpoint
,
392 .deactivate_hardware_watchpoint
= nds32_v3m_deactivate_hardware_watchpoint
,
395 static int nds32_v3m_target_create(struct target
*target
, Jim_Interp
*interp
)
397 struct nds32_v3m_common
*nds32_v3m
;
399 nds32_v3m
= calloc(1, sizeof(*nds32_v3m
));
403 nds32_v3_common_register_callback(&nds32_v3m_common_callback
);
404 nds32_v3_target_create_common(target
, &(nds32_v3m
->nds32
));
409 /* talk to the target and set things up */
410 static int nds32_v3m_examine(struct target
*target
)
412 struct nds32_v3m_common
*nds32_v3m
= target_to_nds32_v3m(target
);
413 struct nds32
*nds32
= &(nds32_v3m
->nds32
);
414 struct aice_port_s
*aice
= target_to_aice(target
);
416 if (!target_was_examined(target
)) {
417 CHECK_RETVAL(nds32_edm_config(nds32
));
419 if (nds32
->reset_halt_as_examine
)
420 CHECK_RETVAL(nds32_reset_halt(nds32
));
424 aice_read_debug_reg(aice
, NDS_EDM_SR_EDM_CFG
, &edm_cfg
);
426 /* get the number of hardware breakpoints */
427 nds32_v3m
->n_hbr
= (edm_cfg
& 0x7) + 1;
428 nds32_v3m
->used_n_wp
= 0;
430 /* get the number of hardware watchpoints */
431 /* If the WP field is hardwired to zero, it means this is a
432 * simple breakpoint. Otherwise, if the WP field is writable
433 * then it means this is a regular watchpoints. */
434 nds32_v3m
->n_hwp
= 0;
435 for (int32_t i
= 0 ; i
< nds32_v3m
->n_hbr
; i
++) {
436 /** check the hardware breakpoint is simple or not */
438 aice_write_debug_reg(aice
, NDS_EDM_SR_BPC0
+ i
, 0x1);
439 aice_read_debug_reg(aice
, NDS_EDM_SR_BPC0
+ i
, &tmp_value
);
444 /* hardware breakpoint is inserted from high index to low index */
445 nds32_v3m
->next_hbr_index
= nds32_v3m
->n_hbr
- 1;
446 /* hardware watchpoint is inserted from low index to high index */
447 nds32_v3m
->next_hwp_index
= 0;
449 LOG_INFO("%s: total hardware breakpoint %d (simple breakpoint %d)",
450 target_name(target
), nds32_v3m
->n_hbr
, nds32_v3m
->n_hbr
- nds32_v3m
->n_hwp
);
451 LOG_INFO("%s: total hardware watchpoint %d", target_name(target
), nds32_v3m
->n_hwp
);
453 nds32
->target
->state
= TARGET_RUNNING
;
454 nds32
->target
->debug_reason
= DBG_REASON_NOTHALTED
;
456 target_set_examined(target
);
461 /** Holds methods for NDS32 V3m targets. */
462 struct target_type nds32_v3m_target
= {
466 .arch_state
= nds32_arch_state
,
468 .target_request_data
= nds32_v3_target_request_data
,
471 .resume
= nds32_resume
,
474 .assert_reset
= nds32_assert_reset
,
475 .deassert_reset
= nds32_v3m_deassert_reset
,
477 /* register access */
478 .get_gdb_reg_list
= nds32_get_gdb_reg_list
,
481 .read_buffer
= nds32_v3_read_buffer
,
482 .write_buffer
= nds32_v3_write_buffer
,
483 .read_memory
= nds32_v3_read_memory
,
484 .write_memory
= nds32_v3_write_memory
,
486 .checksum_memory
= nds32_v3_checksum_memory
,
488 /* breakpoint/watchpoint */
489 .add_breakpoint
= nds32_v3m_add_breakpoint
,
490 .remove_breakpoint
= nds32_v3m_remove_breakpoint
,
491 .add_watchpoint
= nds32_v3m_add_watchpoint
,
492 .remove_watchpoint
= nds32_v3m_remove_watchpoint
,
493 .hit_watchpoint
= nds32_v3_hit_watchpoint
,
497 .virt2phys
= nds32_virtual_to_physical
,
498 .read_phys_memory
= nds32_read_phys_memory
,
499 .write_phys_memory
= nds32_write_phys_memory
,
501 .run_algorithm
= nds32_v3_run_algorithm
,
503 .commands
= nds32_command_handlers
,
504 .target_create
= nds32_v3m_target_create
,
505 .init_target
= nds32_v3_init_target
,
506 .examine
= nds32_v3m_examine
,
508 .get_gdb_fileio_info
= nds32_get_gdb_fileio_info
,
509 .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)