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 %d 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 %d 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 %d at %08" PRIx32
131 " mask %08" PRIx32
, wp_num
,
132 wp
->address
, wp
->mask
);
135 } else if (nds32_v3m
->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_v3m
->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_v3m_deactivate_hardware_watchpoint(struct target
*target
)
160 struct nds32_v3m_common
*nds32_v3m
= target_to_nds32_v3m(target
);
161 struct aice_port_s
*aice
= target_to_aice(target
);
162 struct watchpoint
*wp
;
164 bool clean_global_stop
= false;
166 for (wp
= target
->watchpoints
; wp
; wp
= wp
->next
) {
168 if (wp_num
< nds32_v3m
->used_n_wp
) {
169 /* disable watchpoint */
170 aice_write_debug_reg(aice
, NDS_EDM_SR_BPC0
+ wp_num
, 0x0);
172 LOG_DEBUG("Remove hardware wathcpoint %d at %08" PRIx32
173 " mask %08" PRIx32
, wp_num
,
174 wp
->address
, wp
->mask
);
176 } else if (nds32_v3m
->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_v3m_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 %d. -->",
202 nds32
->current_interrupt_level
);
204 /* backup $ir6 to avoid suppressed exception overwrite */
205 nds32_get_mapped_reg(nds32
, IR6
, &value
);
210 static int nds32_v3m_restore_interrupt_stack(struct nds32
*nds32
)
214 /* get backup value from cache */
215 /* then set back to make the register dirty */
216 nds32_get_mapped_reg(nds32
, IR0
, &value
);
217 nds32_set_mapped_reg(nds32
, IR0
, value
);
219 nds32_get_mapped_reg(nds32
, IR6
, &value
);
220 nds32_set_mapped_reg(nds32
, IR6
, value
);
225 static int nds32_v3m_deassert_reset(struct target
*target
)
229 CHECK_RETVAL(nds32_poll(target
));
231 if (target
->state
!= TARGET_HALTED
) {
233 LOG_WARNING("%s: ran after reset and before halt ...",
234 target_name(target
));
235 retval
= target_halt(target
);
236 if (retval
!= ERROR_OK
)
244 static int nds32_v3m_add_breakpoint(struct target
*target
,
245 struct breakpoint
*breakpoint
)
247 struct nds32_v3m_common
*nds32_v3m
= target_to_nds32_v3m(target
);
248 struct nds32
*nds32
= &(nds32_v3m
->nds32
);
251 if (breakpoint
->type
== BKPT_HARD
) {
252 /* check hardware resource */
253 if (nds32_v3m
->next_hbr_index
< nds32_v3m
->next_hwp_index
) {
254 LOG_WARNING("<-- TARGET WARNING! Insert too many "
255 "hardware breakpoints/watchpoints! "
256 "The limit of combined hardware "
257 "breakpoints/watchpoints is %d. -->",
259 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
260 "hardware breakpoint: %d, hardware "
261 "watchpoints: %d. -->",
262 nds32_v3m
->n_hbr
- nds32_v3m
->next_hbr_index
- 1,
263 nds32_v3m
->used_n_wp
);
264 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
267 /* update next place to put hardware breakpoint */
268 nds32_v3m
->next_hbr_index
--;
270 /* hardware breakpoint insertion occurs before 'continue' actually */
272 } else if (breakpoint
->type
== BKPT_SOFT
) {
273 result
= nds32_add_software_breakpoint(target
, breakpoint
);
274 if (ERROR_OK
!= result
) {
275 /* auto convert to hardware breakpoint if failed */
276 if (nds32
->auto_convert_hw_bp
) {
277 /* convert to hardware breakpoint */
278 breakpoint
->type
= BKPT_HARD
;
280 return nds32_v3m_add_breakpoint(target
, breakpoint
);
285 } else /* unrecognized breakpoint type */
291 static int nds32_v3m_remove_breakpoint(struct target
*target
,
292 struct breakpoint
*breakpoint
)
294 struct nds32_v3m_common
*nds32_v3m
= target_to_nds32_v3m(target
);
296 if (breakpoint
->type
== BKPT_HARD
) {
297 if (nds32_v3m
->next_hbr_index
>= nds32_v3m
->n_hbr
- 1)
300 /* update next place to put hardware breakpoint */
301 nds32_v3m
->next_hbr_index
++;
303 /* hardware breakpoint removal occurs after 'halted' actually */
305 } else if (breakpoint
->type
== BKPT_SOFT
) {
306 return nds32_remove_software_breakpoint(target
, breakpoint
);
307 } else /* unrecognized breakpoint type */
313 static int nds32_v3m_add_watchpoint(struct target
*target
,
314 struct watchpoint
*watchpoint
)
316 struct nds32_v3m_common
*nds32_v3m
= target_to_nds32_v3m(target
);
318 /* check hardware resource */
319 if (nds32_v3m
->next_hwp_index
>= nds32_v3m
->n_hwp
) {
320 /* No hardware resource */
321 if (nds32_v3m
->nds32
.global_stop
) {
322 LOG_WARNING("<-- TARGET WARNING! The number of "
323 "watchpoints exceeds the hardware "
324 "resources. Stop at every load/store "
325 "instruction to check for watchpoint matches. -->");
329 LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
330 "watchpoints! The limit of hardware watchpoints "
331 "is %d. -->", nds32_v3m
->n_hwp
);
332 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
333 "hardware watchpoint: %d. -->",
334 nds32_v3m
->used_n_wp
);
335 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
338 if (nds32_v3m
->next_hwp_index
> nds32_v3m
->next_hbr_index
) {
339 /* No hardware resource */
340 if (nds32_v3m
->nds32
.global_stop
) {
341 LOG_WARNING("<-- TARGET WARNING! The number of "
342 "watchpoints exceeds the hardware "
343 "resources. Stop at every load/store "
344 "instruction to check for watchpoint matches. -->");
348 LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
349 "breakpoints/watchpoints! The limit of combined "
350 "hardware breakpoints/watchpoints is %d. -->",
352 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
353 "hardware breakpoint: %d, hardware "
354 "watchpoints: %d. -->",
355 nds32_v3m
->n_hbr
- nds32_v3m
->next_hbr_index
- 1,
356 nds32_v3m
->used_n_wp
);
357 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
360 /* update next place to put hardware watchpoint */
361 nds32_v3m
->next_hwp_index
++;
362 nds32_v3m
->used_n_wp
++;
367 static int nds32_v3m_remove_watchpoint(struct target
*target
,
368 struct watchpoint
*watchpoint
)
370 struct nds32_v3m_common
*nds32_v3m
= target_to_nds32_v3m(target
);
372 if (nds32_v3m
->next_hwp_index
<= 0) {
373 if (nds32_v3m
->nds32
.global_stop
)
379 /* update next place to put hardware watchpoint */
380 nds32_v3m
->next_hwp_index
--;
381 nds32_v3m
->used_n_wp
--;
386 struct nds32_v3_common_callback nds32_v3m_common_callback
= {
387 .check_interrupt_stack
= nds32_v3m_check_interrupt_stack
,
388 .restore_interrupt_stack
= nds32_v3m_restore_interrupt_stack
,
389 .activate_hardware_breakpoint
= nds32_v3m_activate_hardware_breakpoint
,
390 .activate_hardware_watchpoint
= nds32_v3m_activate_hardware_watchpoint
,
391 .deactivate_hardware_breakpoint
= nds32_v3m_deactivate_hardware_breakpoint
,
392 .deactivate_hardware_watchpoint
= nds32_v3m_deactivate_hardware_watchpoint
,
395 static int nds32_v3m_target_create(struct target
*target
, Jim_Interp
*interp
)
397 struct nds32_v3m_common
*nds32_v3m
;
399 nds32_v3m
= calloc(1, sizeof(*nds32_v3m
));
403 nds32_v3_common_register_callback(&nds32_v3m_common_callback
);
404 nds32_v3_target_create_common(target
, &(nds32_v3m
->nds32
));
409 /* talk to the target and set things up */
410 static int nds32_v3m_examine(struct target
*target
)
412 struct nds32_v3m_common
*nds32_v3m
= target_to_nds32_v3m(target
);
413 struct nds32
*nds32
= &(nds32_v3m
->nds32
);
414 struct aice_port_s
*aice
= target_to_aice(target
);
416 if (!target_was_examined(target
)) {
417 CHECK_RETVAL(nds32_edm_config(nds32
));
419 if (nds32
->reset_halt_as_examine
)
420 CHECK_RETVAL(nds32_reset_halt(nds32
));
424 aice_read_debug_reg(aice
, NDS_EDM_SR_EDM_CFG
, &edm_cfg
);
426 /* get the number of hardware breakpoints */
427 nds32_v3m
->n_hbr
= (edm_cfg
& 0x7) + 1;
428 nds32_v3m
->used_n_wp
= 0;
430 /* get the number of hardware watchpoints */
431 /* If the WP field is hardwired to zero, it means this is a
432 * simple breakpoint. Otherwise, if the WP field is writable
433 * then it means this is a regular watchpoints. */
434 nds32_v3m
->n_hwp
= 0;
435 for (int32_t i
= 0 ; i
< nds32_v3m
->n_hbr
; i
++) {
436 /** check the hardware breakpoint is simple or not */
438 aice_write_debug_reg(aice
, NDS_EDM_SR_BPC0
+ i
, 0x1);
439 aice_read_debug_reg(aice
, NDS_EDM_SR_BPC0
+ i
, &tmp_value
);
444 /* hardware breakpoint is inserted from high index to low index */
445 nds32_v3m
->next_hbr_index
= nds32_v3m
->n_hbr
- 1;
446 /* hardware watchpoint is inserted from low index to high index */
447 nds32_v3m
->next_hwp_index
= 0;
449 LOG_INFO("%s: total hardware breakpoint %d (simple breakpoint %d)",
450 target_name(target
), nds32_v3m
->n_hbr
, nds32_v3m
->n_hbr
- nds32_v3m
->n_hwp
);
451 LOG_INFO("%s: total hardware watchpoint %d", target_name(target
), nds32_v3m
->n_hwp
);
453 nds32
->target
->state
= TARGET_RUNNING
;
454 nds32
->target
->debug_reason
= DBG_REASON_NOTHALTED
;
456 target_set_examined(target
);
461 /** Holds methods for NDS32 V3m targets. */
462 struct target_type nds32_v3m_target
= {
466 .arch_state
= nds32_arch_state
,
468 .target_request_data
= nds32_v3_target_request_data
,
471 .resume
= nds32_resume
,
474 .assert_reset
= nds32_assert_reset
,
475 .deassert_reset
= nds32_v3m_deassert_reset
,
477 /* register access */
478 .get_gdb_reg_list
= nds32_get_gdb_reg_list
,
481 .read_buffer
= nds32_v3_read_buffer
,
482 .write_buffer
= nds32_v3_write_buffer
,
483 .read_memory
= nds32_v3_read_memory
,
484 .write_memory
= nds32_v3_write_memory
,
486 .checksum_memory
= nds32_v3_checksum_memory
,
488 /* breakpoint/watchpoint */
489 .add_breakpoint
= nds32_v3m_add_breakpoint
,
490 .remove_breakpoint
= nds32_v3m_remove_breakpoint
,
491 .add_watchpoint
= nds32_v3m_add_watchpoint
,
492 .remove_watchpoint
= nds32_v3m_remove_watchpoint
,
493 .hit_watchpoint
= nds32_v3_hit_watchpoint
,
497 .virt2phys
= nds32_virtual_to_physical
,
498 .read_phys_memory
= nds32_read_phys_memory
,
499 .write_phys_memory
= nds32_write_phys_memory
,
501 .run_algorithm
= nds32_v3_run_algorithm
,
503 .commands
= nds32_command_handlers
,
504 .target_create
= nds32_v3m_target_create
,
505 .init_target
= nds32_v3_init_target
,
506 .examine
= nds32_v3m_examine
,
508 .get_gdb_fileio_info
= nds32_get_gdb_fileio_info
,
509 .gdb_fileio_end
= nds32_gdb_fileio_end
,