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"
27 #include "nds32_v3_common.h"
29 static int nds32_v3_activate_hardware_breakpoint(struct target
*target
)
31 struct nds32_v3_common
*nds32_v3
= target_to_nds32_v3(target
);
32 struct aice_port_s
*aice
= target_to_aice(target
);
33 struct breakpoint
*bp
;
34 int32_t hbr_index
= nds32_v3
->next_hbr_index
;
36 for (bp
= target
->breakpoints
; bp
; bp
= bp
->next
) {
37 if (bp
->type
== BKPT_SOFT
) {
38 /* already set at nds32_v3_add_breakpoint() */
40 } else if (bp
->type
== BKPT_HARD
) {
43 aice_write_debug_reg(aice
, NDS_EDM_SR_BPA0
+ hbr_index
, bp
->address
);
45 aice_write_debug_reg(aice
, NDS_EDM_SR_BPAM0
+ hbr_index
, 0);
47 aice_write_debug_reg(aice
, NDS_EDM_SR_BPV0
+ hbr_index
, 0);
49 if (nds32_v3
->nds32
.memory
.address_translation
)
50 /* enable breakpoint (virtual address) */
51 aice_write_debug_reg(aice
, NDS_EDM_SR_BPC0
+ hbr_index
, 0x2);
53 /* enable breakpoint (physical address) */
54 aice_write_debug_reg(aice
, NDS_EDM_SR_BPC0
+ hbr_index
, 0xA);
56 LOG_DEBUG("Add hardware BP %" PRId32
" at %08" TARGET_PRIxADDR
, hbr_index
,
66 static int nds32_v3_deactivate_hardware_breakpoint(struct target
*target
)
68 struct nds32_v3_common
*nds32_v3
= target_to_nds32_v3(target
);
69 struct aice_port_s
*aice
= target_to_aice(target
);
70 struct breakpoint
*bp
;
71 int32_t hbr_index
= nds32_v3
->next_hbr_index
;
73 for (bp
= target
->breakpoints
; bp
; bp
= bp
->next
) {
74 if (bp
->type
== BKPT_SOFT
) {
76 } else if (bp
->type
== BKPT_HARD
) {
78 /* disable breakpoint */
79 aice_write_debug_reg(aice
, NDS_EDM_SR_BPC0
+ hbr_index
, 0x0);
84 LOG_DEBUG("Remove hardware BP %" PRId32
" at %08" TARGET_PRIxADDR
, hbr_index
,
91 static int nds32_v3_activate_hardware_watchpoint(struct target
*target
)
93 struct aice_port_s
*aice
= target_to_aice(target
);
94 struct nds32_v3_common
*nds32_v3
= target_to_nds32_v3(target
);
95 struct watchpoint
*wp
;
97 uint32_t wp_config
= 0;
98 bool ld_stop
, st_stop
;
100 if (nds32_v3
->nds32
.global_stop
)
101 ld_stop
= st_stop
= false;
103 for (wp
= target
->watchpoints
; wp
; wp
= wp
->next
) {
105 if (wp_num
< nds32_v3
->used_n_wp
) {
106 wp
->mask
= wp
->length
- 1;
107 if ((wp
->address
% wp
->length
) != 0)
108 wp
->mask
= (wp
->mask
<< 1) + 1;
110 if (wp
->rw
== WPT_READ
)
112 else if (wp
->rw
== WPT_WRITE
)
114 else if (wp
->rw
== WPT_ACCESS
)
117 /* set/unset physical address bit of BPCn according to PSW.DT */
118 if (nds32_v3
->nds32
.memory
.address_translation
== false)
122 aice_write_debug_reg(aice
, NDS_EDM_SR_BPA0
+ wp_num
,
123 wp
->address
- (wp
->address
% wp
->length
));
125 aice_write_debug_reg(aice
, NDS_EDM_SR_BPAM0
+ wp_num
, wp
->mask
);
126 /* enable watchpoint */
127 aice_write_debug_reg(aice
, NDS_EDM_SR_BPC0
+ wp_num
, wp_config
);
129 aice_write_debug_reg(aice
, NDS_EDM_SR_BPV0
+ wp_num
, 0);
131 LOG_DEBUG("Add hardware watchpoint %" PRId32
" at %08" TARGET_PRIxADDR
" mask %08" PRIx32
,
132 wp_num
, wp
->address
, wp
->mask
);
135 } else if (nds32_v3
->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_v3
->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_v3_deactivate_hardware_watchpoint(struct target
*target
)
160 struct aice_port_s
*aice
= target_to_aice(target
);
161 struct nds32_v3_common
*nds32_v3
= target_to_nds32_v3(target
);
163 struct watchpoint
*wp
;
164 bool clean_global_stop
= false;
166 for (wp
= target
->watchpoints
; wp
; wp
= wp
->next
) {
168 if (wp_num
< nds32_v3
->used_n_wp
) {
169 /* disable watchpoint */
170 aice_write_debug_reg(aice
, NDS_EDM_SR_BPC0
+ wp_num
, 0x0);
172 LOG_DEBUG("Remove hardware watchpoint %" PRId32
" at %08" TARGET_PRIxADDR
173 " mask %08" PRIx32
, wp_num
,
174 wp
->address
, wp
->mask
);
176 } else if (nds32_v3
->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_v3_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 %" PRIu32
". -->",
202 nds32
->current_interrupt_level
);
204 /* backup $ir4 & $ir6 to avoid suppressed exception overwrite */
205 nds32_get_mapped_reg(nds32
, IR4
, &value
);
206 nds32_get_mapped_reg(nds32
, IR6
, &value
);
211 static int nds32_v3_restore_interrupt_stack(struct nds32
*nds32
)
215 /* get backup value from cache */
216 /* then set back to make the register dirty */
217 nds32_get_mapped_reg(nds32
, IR0
, &value
);
218 nds32_set_mapped_reg(nds32
, IR0
, value
);
220 nds32_get_mapped_reg(nds32
, IR4
, &value
);
221 nds32_set_mapped_reg(nds32
, IR4
, value
);
223 nds32_get_mapped_reg(nds32
, IR6
, &value
);
224 nds32_set_mapped_reg(nds32
, IR6
, value
);
229 static int nds32_v3_deassert_reset(struct target
*target
)
232 struct aice_port_s
*aice
= target_to_aice(target
);
233 bool switch_to_v3_stack
= false;
234 uint32_t value_edm_ctl
;
236 aice_read_debug_reg(aice
, NDS_EDM_SR_EDM_CTL
, &value_edm_ctl
);
237 if (((value_edm_ctl
>> 6) & 0x1) == 0) { /* reset to V2 EDM mode */
238 aice_write_debug_reg(aice
, NDS_EDM_SR_EDM_CTL
, value_edm_ctl
| (0x1 << 6));
239 aice_read_debug_reg(aice
, NDS_EDM_SR_EDM_CTL
, &value_edm_ctl
);
240 if (((value_edm_ctl
>> 6) & 0x1) == 1)
241 switch_to_v3_stack
= true;
243 switch_to_v3_stack
= false;
245 CHECK_RETVAL(nds32_poll(target
));
247 if (target
->state
!= TARGET_HALTED
) {
249 LOG_WARNING("%s: ran after reset and before halt ...",
250 target_name(target
));
251 retval
= target_halt(target
);
252 if (retval
!= ERROR_OK
)
257 struct nds32_v3_common
*nds32_v3
= target_to_nds32_v3(target
);
258 struct nds32
*nds32
= &(nds32_v3
->nds32
);
260 uint32_t interrupt_level
;
262 if (switch_to_v3_stack
== true) {
264 nds32_get_mapped_reg(nds32
, IR0
, &value
);
265 interrupt_level
= (value
>> 1) & 0x3;
268 value
|= (interrupt_level
<< 1);
269 value
|= 0x400; /* set PSW.DEX */
270 nds32_set_mapped_reg(nds32
, IR0
, value
);
272 /* copy IPC to OIPC */
273 if ((interrupt_level
+ 1) < nds32
->max_interrupt_level
) {
274 nds32_get_mapped_reg(nds32
, IR9
, &value
);
275 nds32_set_mapped_reg(nds32
, IR11
, value
);
283 static int nds32_v3_add_breakpoint(struct target
*target
,
284 struct breakpoint
*breakpoint
)
286 struct nds32_v3_common
*nds32_v3
= target_to_nds32_v3(target
);
287 struct nds32
*nds32
= &(nds32_v3
->nds32
);
290 if (breakpoint
->type
== BKPT_HARD
) {
291 /* check hardware resource */
292 if (nds32_v3
->n_hbr
<= nds32_v3
->next_hbr_index
) {
293 LOG_WARNING("<-- TARGET WARNING! Insert too many "
294 "hardware breakpoints/watchpoints! "
295 "The limit of combined hardware "
296 "breakpoints/watchpoints is %" PRId32
". -->",
298 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
299 "hardware breakpoint: %" PRId32
", hardware "
300 "watchpoints: %" PRId32
". -->",
301 nds32_v3
->next_hbr_index
- nds32_v3
->used_n_wp
,
302 nds32_v3
->used_n_wp
);
303 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
306 /* update next place to put hardware breakpoint */
307 nds32_v3
->next_hbr_index
++;
309 /* hardware breakpoint insertion occurs before 'continue' actually */
311 } else if (breakpoint
->type
== BKPT_SOFT
) {
312 result
= nds32_add_software_breakpoint(target
, breakpoint
);
313 if (ERROR_OK
!= result
) {
314 /* auto convert to hardware breakpoint if failed */
315 if (nds32
->auto_convert_hw_bp
) {
316 /* convert to hardware breakpoint */
317 breakpoint
->type
= BKPT_HARD
;
319 return nds32_v3_add_breakpoint(target
, breakpoint
);
324 } else /* unrecognized breakpoint type */
330 static int nds32_v3_remove_breakpoint(struct target
*target
,
331 struct breakpoint
*breakpoint
)
333 struct nds32_v3_common
*nds32_v3
= target_to_nds32_v3(target
);
335 if (breakpoint
->type
== BKPT_HARD
) {
336 if (nds32_v3
->next_hbr_index
<= 0)
339 /* update next place to put hardware breakpoint */
340 nds32_v3
->next_hbr_index
--;
342 /* hardware breakpoint removal occurs after 'halted' actually */
344 } else if (breakpoint
->type
== BKPT_SOFT
) {
345 return nds32_remove_software_breakpoint(target
, breakpoint
);
346 } else /* unrecognized breakpoint type */
352 static int nds32_v3_add_watchpoint(struct target
*target
,
353 struct watchpoint
*watchpoint
)
355 struct nds32_v3_common
*nds32_v3
= target_to_nds32_v3(target
);
357 /* check hardware resource */
358 if (nds32_v3
->n_hbr
<= nds32_v3
->next_hbr_index
) {
359 /* No hardware resource */
360 if (nds32_v3
->nds32
.global_stop
) {
361 LOG_WARNING("<-- TARGET WARNING! The number of "
362 "watchpoints exceeds the hardware "
363 "resources. Stop at every load/store "
364 "instruction to check for watchpoint matches. -->");
368 LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
369 "breakpoints/watchpoints! The limit of combined "
370 "hardware breakpoints/watchpoints is %" PRId32
". -->",
372 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
373 "hardware breakpoint: %" PRId32
", hardware "
374 "watchpoints: %" PRId32
". -->",
375 nds32_v3
->next_hbr_index
- nds32_v3
->used_n_wp
,
376 nds32_v3
->used_n_wp
);
378 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
381 /* update next place to put hardware watchpoint */
382 nds32_v3
->next_hbr_index
++;
383 nds32_v3
->used_n_wp
++;
388 static int nds32_v3_remove_watchpoint(struct target
*target
,
389 struct watchpoint
*watchpoint
)
391 struct nds32_v3_common
*nds32_v3
= target_to_nds32_v3(target
);
393 if (nds32_v3
->next_hbr_index
<= 0) {
394 if (nds32_v3
->nds32
.global_stop
)
400 /* update next place to put hardware breakpoint */
401 nds32_v3
->next_hbr_index
--;
402 nds32_v3
->used_n_wp
--;
407 struct nds32_v3_common_callback nds32_v3_common_callback
= {
408 .check_interrupt_stack
= nds32_v3_check_interrupt_stack
,
409 .restore_interrupt_stack
= nds32_v3_restore_interrupt_stack
,
410 .activate_hardware_breakpoint
= nds32_v3_activate_hardware_breakpoint
,
411 .activate_hardware_watchpoint
= nds32_v3_activate_hardware_watchpoint
,
412 .deactivate_hardware_breakpoint
= nds32_v3_deactivate_hardware_breakpoint
,
413 .deactivate_hardware_watchpoint
= nds32_v3_deactivate_hardware_watchpoint
,
416 static int nds32_v3_target_create(struct target
*target
, Jim_Interp
*interp
)
418 struct nds32_v3_common
*nds32_v3
;
420 nds32_v3
= calloc(1, sizeof(*nds32_v3
));
424 nds32_v3_common_register_callback(&nds32_v3_common_callback
);
425 nds32_v3_target_create_common(target
, &(nds32_v3
->nds32
));
430 /* talk to the target and set things up */
431 static int nds32_v3_examine(struct target
*target
)
433 struct nds32_v3_common
*nds32_v3
= target_to_nds32_v3(target
);
434 struct nds32
*nds32
= &(nds32_v3
->nds32
);
435 struct aice_port_s
*aice
= target_to_aice(target
);
437 if (!target_was_examined(target
)) {
438 CHECK_RETVAL(nds32_edm_config(nds32
));
440 if (nds32
->reset_halt_as_examine
)
441 CHECK_RETVAL(nds32_reset_halt(nds32
));
445 aice_read_debug_reg(aice
, NDS_EDM_SR_EDM_CFG
, &edm_cfg
);
447 /* get the number of hardware breakpoints */
448 nds32_v3
->n_hbr
= (edm_cfg
& 0x7) + 1;
450 /* low interference profiling */
452 nds32_v3
->low_interference_profile
= true;
454 nds32_v3
->low_interference_profile
= false;
456 nds32_v3
->next_hbr_index
= 0;
457 nds32_v3
->used_n_wp
= 0;
459 LOG_INFO("%s: total hardware breakpoint %" PRId32
, target_name(target
),
462 nds32
->target
->state
= TARGET_RUNNING
;
463 nds32
->target
->debug_reason
= DBG_REASON_NOTHALTED
;
465 target_set_examined(target
);
470 /** Holds methods for Andes1337 targets. */
471 struct target_type nds32_v3_target
= {
475 .arch_state
= nds32_arch_state
,
477 .target_request_data
= nds32_v3_target_request_data
,
480 .resume
= nds32_resume
,
483 .assert_reset
= nds32_assert_reset
,
484 .deassert_reset
= nds32_v3_deassert_reset
,
486 /* register access */
487 .get_gdb_reg_list
= nds32_get_gdb_reg_list
,
490 .read_buffer
= nds32_v3_read_buffer
,
491 .write_buffer
= nds32_v3_write_buffer
,
492 .read_memory
= nds32_v3_read_memory
,
493 .write_memory
= nds32_v3_write_memory
,
495 .checksum_memory
= nds32_v3_checksum_memory
,
497 /* breakpoint/watchpoint */
498 .add_breakpoint
= nds32_v3_add_breakpoint
,
499 .remove_breakpoint
= nds32_v3_remove_breakpoint
,
500 .add_watchpoint
= nds32_v3_add_watchpoint
,
501 .remove_watchpoint
= nds32_v3_remove_watchpoint
,
502 .hit_watchpoint
= nds32_v3_hit_watchpoint
,
506 .virt2phys
= nds32_virtual_to_physical
,
507 .read_phys_memory
= nds32_read_phys_memory
,
508 .write_phys_memory
= nds32_write_phys_memory
,
510 .run_algorithm
= nds32_v3_run_algorithm
,
512 .commands
= nds32_command_handlers
,
513 .target_create
= nds32_v3_target_create
,
514 .init_target
= nds32_v3_init_target
,
515 .examine
= nds32_v3_examine
,
517 .get_gdb_fileio_info
= nds32_get_gdb_fileio_info
,
518 .gdb_fileio_end
= nds32_gdb_fileio_end
,
520 .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)