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
,
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)