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"
29 #include "nds32_v3_common.h"
31 static int nds32_v3_activate_hardware_breakpoint(struct target
*target
)
33 struct nds32_v3_common
*nds32_v3
= target_to_nds32_v3(target
);
34 struct aice_port_s
*aice
= target_to_aice(target
);
35 struct breakpoint
*bp
;
36 int32_t hbr_index
= nds32_v3
->next_hbr_index
;
38 for (bp
= target
->breakpoints
; bp
; bp
= bp
->next
) {
39 if (bp
->type
== BKPT_SOFT
) {
40 /* already set at nds32_v3_add_breakpoint() */
42 } else if (bp
->type
== BKPT_HARD
) {
45 aice_write_debug_reg(aice
, NDS_EDM_SR_BPA0
+ hbr_index
, bp
->address
);
47 aice_write_debug_reg(aice
, NDS_EDM_SR_BPAM0
+ hbr_index
, 0);
49 aice_write_debug_reg(aice
, NDS_EDM_SR_BPV0
+ hbr_index
, 0);
51 if (nds32_v3
->nds32
.memory
.address_translation
)
52 /* enable breakpoint (virtual address) */
53 aice_write_debug_reg(aice
, NDS_EDM_SR_BPC0
+ hbr_index
, 0x2);
55 /* enable breakpoint (physical address) */
56 aice_write_debug_reg(aice
, NDS_EDM_SR_BPC0
+ hbr_index
, 0xA);
58 LOG_DEBUG("Add hardware BP %" PRId32
" at %08" PRIx32
, hbr_index
,
68 static int nds32_v3_deactivate_hardware_breakpoint(struct target
*target
)
70 struct nds32_v3_common
*nds32_v3
= target_to_nds32_v3(target
);
71 struct aice_port_s
*aice
= target_to_aice(target
);
72 struct breakpoint
*bp
;
73 int32_t hbr_index
= nds32_v3
->next_hbr_index
;
75 for (bp
= target
->breakpoints
; bp
; bp
= bp
->next
) {
76 if (bp
->type
== BKPT_SOFT
) {
78 } else if (bp
->type
== BKPT_HARD
) {
80 /* disable breakpoint */
81 aice_write_debug_reg(aice
, NDS_EDM_SR_BPC0
+ hbr_index
, 0x0);
86 LOG_DEBUG("Remove hardware BP %" PRId32
" at %08" PRIx32
, hbr_index
,
93 static int nds32_v3_activate_hardware_watchpoint(struct target
*target
)
95 struct aice_port_s
*aice
= target_to_aice(target
);
96 struct nds32_v3_common
*nds32_v3
= target_to_nds32_v3(target
);
97 struct watchpoint
*wp
;
99 uint32_t wp_config
= 0;
100 bool ld_stop
, st_stop
;
102 if (nds32_v3
->nds32
.global_stop
)
103 ld_stop
= st_stop
= false;
105 for (wp
= target
->watchpoints
; wp
; wp
= wp
->next
) {
107 if (wp_num
< nds32_v3
->used_n_wp
) {
108 wp
->mask
= wp
->length
- 1;
109 if ((wp
->address
% wp
->length
) != 0)
110 wp
->mask
= (wp
->mask
<< 1) + 1;
112 if (wp
->rw
== WPT_READ
)
114 else if (wp
->rw
== WPT_WRITE
)
116 else if (wp
->rw
== WPT_ACCESS
)
119 /* set/unset physical address bit of BPCn according to PSW.DT */
120 if (nds32_v3
->nds32
.memory
.address_translation
== false)
124 aice_write_debug_reg(aice
, NDS_EDM_SR_BPA0
+ wp_num
,
125 wp
->address
- (wp
->address
% wp
->length
));
127 aice_write_debug_reg(aice
, NDS_EDM_SR_BPAM0
+ wp_num
, wp
->mask
);
128 /* enable watchpoint */
129 aice_write_debug_reg(aice
, NDS_EDM_SR_BPC0
+ wp_num
, wp_config
);
131 aice_write_debug_reg(aice
, NDS_EDM_SR_BPV0
+ wp_num
, 0);
133 LOG_DEBUG("Add hardware wathcpoint %" PRId32
" at %08" PRIx32
" mask %08" PRIx32
,
134 wp_num
, wp
->address
, wp
->mask
);
137 } else if (nds32_v3
->nds32
.global_stop
) {
138 if (wp
->rw
== WPT_READ
)
140 else if (wp
->rw
== WPT_WRITE
)
142 else if (wp
->rw
== WPT_ACCESS
)
143 ld_stop
= st_stop
= true;
147 if (nds32_v3
->nds32
.global_stop
) {
149 aice_read_debug_reg(aice
, NDS_EDM_SR_EDM_CTL
, &edm_ctl
);
154 aice_write_debug_reg(aice
, NDS_EDM_SR_EDM_CTL
, edm_ctl
);
160 static int nds32_v3_deactivate_hardware_watchpoint(struct target
*target
)
162 struct aice_port_s
*aice
= target_to_aice(target
);
163 struct nds32_v3_common
*nds32_v3
= target_to_nds32_v3(target
);
165 struct watchpoint
*wp
;
166 bool clean_global_stop
= false;
168 for (wp
= target
->watchpoints
; wp
; wp
= wp
->next
) {
170 if (wp_num
< nds32_v3
->used_n_wp
) {
171 /* disable watchpoint */
172 aice_write_debug_reg(aice
, NDS_EDM_SR_BPC0
+ wp_num
, 0x0);
174 LOG_DEBUG("Remove hardware wathcpoint %" PRId32
" at %08" PRIx32
175 " mask %08" PRIx32
, wp_num
,
176 wp
->address
, wp
->mask
);
178 } else if (nds32_v3
->nds32
.global_stop
) {
179 clean_global_stop
= true;
183 if (clean_global_stop
) {
185 aice_read_debug_reg(aice
, NDS_EDM_SR_EDM_CTL
, &edm_ctl
);
186 edm_ctl
= edm_ctl
& (~0x30);
187 aice_write_debug_reg(aice
, NDS_EDM_SR_EDM_CTL
, edm_ctl
);
193 static int nds32_v3_check_interrupt_stack(struct nds32
*nds32
)
198 /* Save interrupt level */
199 nds32_get_mapped_reg(nds32
, IR0
, &val_ir0
);
200 nds32
->current_interrupt_level
= (val_ir0
>> 1) & 0x3;
202 if (nds32_reach_max_interrupt_level(nds32
))
203 LOG_ERROR("<-- TARGET ERROR! Reaching the max interrupt stack level %" PRIu32
". -->",
204 nds32
->current_interrupt_level
);
206 /* backup $ir4 & $ir6 to avoid suppressed exception overwrite */
207 nds32_get_mapped_reg(nds32
, IR4
, &value
);
208 nds32_get_mapped_reg(nds32
, IR6
, &value
);
213 static int nds32_v3_restore_interrupt_stack(struct nds32
*nds32
)
217 /* get backup value from cache */
218 /* then set back to make the register dirty */
219 nds32_get_mapped_reg(nds32
, IR0
, &value
);
220 nds32_set_mapped_reg(nds32
, IR0
, value
);
222 nds32_get_mapped_reg(nds32
, IR4
, &value
);
223 nds32_set_mapped_reg(nds32
, IR4
, value
);
225 nds32_get_mapped_reg(nds32
, IR6
, &value
);
226 nds32_set_mapped_reg(nds32
, IR6
, value
);
231 static int nds32_v3_deassert_reset(struct target
*target
)
234 struct aice_port_s
*aice
= target_to_aice(target
);
235 bool switch_to_v3_stack
= false;
236 uint32_t value_edm_ctl
;
238 aice_read_debug_reg(aice
, NDS_EDM_SR_EDM_CTL
, &value_edm_ctl
);
239 if (((value_edm_ctl
>> 6) & 0x1) == 0) { /* reset to V2 EDM mode */
240 aice_write_debug_reg(aice
, NDS_EDM_SR_EDM_CTL
, value_edm_ctl
| (0x1 << 6));
241 aice_read_debug_reg(aice
, NDS_EDM_SR_EDM_CTL
, &value_edm_ctl
);
242 if (((value_edm_ctl
>> 6) & 0x1) == 1)
243 switch_to_v3_stack
= true;
245 switch_to_v3_stack
= false;
247 CHECK_RETVAL(nds32_poll(target
));
249 if (target
->state
!= TARGET_HALTED
) {
251 LOG_WARNING("%s: ran after reset and before halt ...",
252 target_name(target
));
253 retval
= target_halt(target
);
254 if (retval
!= ERROR_OK
)
259 struct nds32_v3_common
*nds32_v3
= target_to_nds32_v3(target
);
260 struct nds32
*nds32
= &(nds32_v3
->nds32
);
262 uint32_t interrupt_level
;
264 if (switch_to_v3_stack
== true) {
266 nds32_get_mapped_reg(nds32
, IR0
, &value
);
267 interrupt_level
= (value
>> 1) & 0x3;
270 value
|= (interrupt_level
<< 1);
271 value
|= 0x400; /* set PSW.DEX */
272 nds32_set_mapped_reg(nds32
, IR0
, value
);
274 /* copy IPC to OIPC */
275 if ((interrupt_level
+ 1) < nds32
->max_interrupt_level
) {
276 nds32_get_mapped_reg(nds32
, IR9
, &value
);
277 nds32_set_mapped_reg(nds32
, IR11
, value
);
285 static int nds32_v3_add_breakpoint(struct target
*target
,
286 struct breakpoint
*breakpoint
)
288 struct nds32_v3_common
*nds32_v3
= target_to_nds32_v3(target
);
289 struct nds32
*nds32
= &(nds32_v3
->nds32
);
292 if (breakpoint
->type
== BKPT_HARD
) {
293 /* check hardware resource */
294 if (nds32_v3
->n_hbr
<= nds32_v3
->next_hbr_index
) {
295 LOG_WARNING("<-- TARGET WARNING! Insert too many "
296 "hardware breakpoints/watchpoints! "
297 "The limit of combined hardware "
298 "breakpoints/watchpoints is %" PRId32
". -->",
300 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
301 "hardware breakpoint: %" PRId32
", hardware "
302 "watchpoints: %" PRId32
". -->",
303 nds32_v3
->next_hbr_index
- nds32_v3
->used_n_wp
,
304 nds32_v3
->used_n_wp
);
305 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
308 /* update next place to put hardware breakpoint */
309 nds32_v3
->next_hbr_index
++;
311 /* hardware breakpoint insertion occurs before 'continue' actually */
313 } else if (breakpoint
->type
== BKPT_SOFT
) {
314 result
= nds32_add_software_breakpoint(target
, breakpoint
);
315 if (ERROR_OK
!= result
) {
316 /* auto convert to hardware breakpoint if failed */
317 if (nds32
->auto_convert_hw_bp
) {
318 /* convert to hardware breakpoint */
319 breakpoint
->type
= BKPT_HARD
;
321 return nds32_v3_add_breakpoint(target
, breakpoint
);
326 } else /* unrecognized breakpoint type */
332 static int nds32_v3_remove_breakpoint(struct target
*target
,
333 struct breakpoint
*breakpoint
)
335 struct nds32_v3_common
*nds32_v3
= target_to_nds32_v3(target
);
337 if (breakpoint
->type
== BKPT_HARD
) {
338 if (nds32_v3
->next_hbr_index
<= 0)
341 /* update next place to put hardware breakpoint */
342 nds32_v3
->next_hbr_index
--;
344 /* hardware breakpoint removal occurs after 'halted' actually */
346 } else if (breakpoint
->type
== BKPT_SOFT
) {
347 return nds32_remove_software_breakpoint(target
, breakpoint
);
348 } else /* unrecognized breakpoint type */
354 static int nds32_v3_add_watchpoint(struct target
*target
,
355 struct watchpoint
*watchpoint
)
357 struct nds32_v3_common
*nds32_v3
= target_to_nds32_v3(target
);
359 /* check hardware resource */
360 if (nds32_v3
->n_hbr
<= nds32_v3
->next_hbr_index
) {
361 /* No hardware resource */
362 if (nds32_v3
->nds32
.global_stop
) {
363 LOG_WARNING("<-- TARGET WARNING! The number of "
364 "watchpoints exceeds the hardware "
365 "resources. Stop at every load/store "
366 "instruction to check for watchpoint matches. -->");
370 LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
371 "breakpoints/watchpoints! The limit of combined "
372 "hardware breakpoints/watchpoints is %" PRId32
". -->",
374 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
375 "hardware breakpoint: %" PRId32
", hardware "
376 "watchpoints: %" PRId32
". -->",
377 nds32_v3
->next_hbr_index
- nds32_v3
->used_n_wp
,
378 nds32_v3
->used_n_wp
);
380 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
383 /* update next place to put hardware watchpoint */
384 nds32_v3
->next_hbr_index
++;
385 nds32_v3
->used_n_wp
++;
390 static int nds32_v3_remove_watchpoint(struct target
*target
,
391 struct watchpoint
*watchpoint
)
393 struct nds32_v3_common
*nds32_v3
= target_to_nds32_v3(target
);
395 if (nds32_v3
->next_hbr_index
<= 0) {
396 if (nds32_v3
->nds32
.global_stop
)
402 /* update next place to put hardware breakpoint */
403 nds32_v3
->next_hbr_index
--;
404 nds32_v3
->used_n_wp
--;
409 struct nds32_v3_common_callback nds32_v3_common_callback
= {
410 .check_interrupt_stack
= nds32_v3_check_interrupt_stack
,
411 .restore_interrupt_stack
= nds32_v3_restore_interrupt_stack
,
412 .activate_hardware_breakpoint
= nds32_v3_activate_hardware_breakpoint
,
413 .activate_hardware_watchpoint
= nds32_v3_activate_hardware_watchpoint
,
414 .deactivate_hardware_breakpoint
= nds32_v3_deactivate_hardware_breakpoint
,
415 .deactivate_hardware_watchpoint
= nds32_v3_deactivate_hardware_watchpoint
,
418 static int nds32_v3_target_create(struct target
*target
, Jim_Interp
*interp
)
420 struct nds32_v3_common
*nds32_v3
;
422 nds32_v3
= calloc(1, sizeof(*nds32_v3
));
426 nds32_v3_common_register_callback(&nds32_v3_common_callback
);
427 nds32_v3_target_create_common(target
, &(nds32_v3
->nds32
));
432 /* talk to the target and set things up */
433 static int nds32_v3_examine(struct target
*target
)
435 struct nds32_v3_common
*nds32_v3
= target_to_nds32_v3(target
);
436 struct nds32
*nds32
= &(nds32_v3
->nds32
);
437 struct aice_port_s
*aice
= target_to_aice(target
);
439 if (!target_was_examined(target
)) {
440 CHECK_RETVAL(nds32_edm_config(nds32
));
442 if (nds32
->reset_halt_as_examine
)
443 CHECK_RETVAL(nds32_reset_halt(nds32
));
447 aice_read_debug_reg(aice
, NDS_EDM_SR_EDM_CFG
, &edm_cfg
);
449 /* get the number of hardware breakpoints */
450 nds32_v3
->n_hbr
= (edm_cfg
& 0x7) + 1;
452 /* low interference profiling */
454 nds32_v3
->low_interference_profile
= true;
456 nds32_v3
->low_interference_profile
= false;
458 nds32_v3
->next_hbr_index
= 0;
459 nds32_v3
->used_n_wp
= 0;
461 LOG_INFO("%s: total hardware breakpoint %" PRId32
, target_name(target
),
464 nds32
->target
->state
= TARGET_RUNNING
;
465 nds32
->target
->debug_reason
= DBG_REASON_NOTHALTED
;
467 target_set_examined(target
);
472 /** Holds methods for Andes1337 targets. */
473 struct target_type nds32_v3_target
= {
477 .arch_state
= nds32_arch_state
,
479 .target_request_data
= nds32_v3_target_request_data
,
482 .resume
= nds32_resume
,
485 .assert_reset
= nds32_assert_reset
,
486 .deassert_reset
= nds32_v3_deassert_reset
,
488 /* register access */
489 .get_gdb_reg_list
= nds32_get_gdb_reg_list
,
492 .read_buffer
= nds32_v3_read_buffer
,
493 .write_buffer
= nds32_v3_write_buffer
,
494 .read_memory
= nds32_v3_read_memory
,
495 .write_memory
= nds32_v3_write_memory
,
497 .checksum_memory
= nds32_v3_checksum_memory
,
499 /* breakpoint/watchpoint */
500 .add_breakpoint
= nds32_v3_add_breakpoint
,
501 .remove_breakpoint
= nds32_v3_remove_breakpoint
,
502 .add_watchpoint
= nds32_v3_add_watchpoint
,
503 .remove_watchpoint
= nds32_v3_remove_watchpoint
,
504 .hit_watchpoint
= nds32_v3_hit_watchpoint
,
508 .virt2phys
= nds32_virtual_to_physical
,
509 .read_phys_memory
= nds32_read_phys_memory
,
510 .write_phys_memory
= nds32_write_phys_memory
,
512 .run_algorithm
= nds32_v3_run_algorithm
,
514 .commands
= nds32_command_handlers
,
515 .target_create
= nds32_v3_target_create
,
516 .init_target
= nds32_v3_init_target
,
517 .examine
= nds32_v3_examine
,
519 .get_gdb_fileio_info
= nds32_get_gdb_fileio_info
,
520 .gdb_fileio_end
= nds32_gdb_fileio_end
,
522 .profiling
= nds32_profiling
,
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)