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 %d 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 %d 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 %d 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 %d 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 %d. -->",
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 %d. -->",
300 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
301 "hardware breakpoint: %d, hardware "
302 "watchpoints: %d. -->",
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 %d. -->",
374 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
375 "hardware breakpoint: %d, hardware "
376 "watchpoints: %d. -->",
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 %d", 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
,