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 (result
!= ERROR_OK
) {
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 static 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
,