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
)
238 /* call target_poll() to avoid "Halt timed out" */
239 CHECK_RETVAL(target_poll(target
));
241 jtag_poll_set_enabled(false);
247 static int nds32_v3m_add_breakpoint(struct target
*target
,
248 struct breakpoint
*breakpoint
)
250 struct nds32_v3m_common
*nds32_v3m
= target_to_nds32_v3m(target
);
251 struct nds32
*nds32
= &(nds32_v3m
->nds32
);
254 if (breakpoint
->type
== BKPT_HARD
) {
255 /* check hardware resource */
256 if (nds32_v3m
->next_hbr_index
< nds32_v3m
->next_hwp_index
) {
257 LOG_WARNING("<-- TARGET WARNING! Insert too many "
258 "hardware breakpoints/watchpoints! "
259 "The limit of combined hardware "
260 "breakpoints/watchpoints is %d. -->",
262 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
263 "hardware breakpoint: %d, hardware "
264 "watchpoints: %d. -->",
265 nds32_v3m
->n_hbr
- nds32_v3m
->next_hbr_index
- 1,
266 nds32_v3m
->used_n_wp
);
267 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
270 /* update next place to put hardware breakpoint */
271 nds32_v3m
->next_hbr_index
--;
273 /* hardware breakpoint insertion occurs before 'continue' actually */
275 } else if (breakpoint
->type
== BKPT_SOFT
) {
276 result
= nds32_add_software_breakpoint(target
, breakpoint
);
277 if (ERROR_OK
!= result
) {
278 /* auto convert to hardware breakpoint if failed */
279 if (nds32
->auto_convert_hw_bp
) {
280 /* convert to hardware breakpoint */
281 breakpoint
->type
= BKPT_HARD
;
283 return nds32_v3m_add_breakpoint(target
, breakpoint
);
288 } else /* unrecognized breakpoint type */
294 static int nds32_v3m_remove_breakpoint(struct target
*target
,
295 struct breakpoint
*breakpoint
)
297 struct nds32_v3m_common
*nds32_v3m
= target_to_nds32_v3m(target
);
299 if (breakpoint
->type
== BKPT_HARD
) {
300 if (nds32_v3m
->next_hbr_index
>= nds32_v3m
->n_hbr
- 1)
303 /* update next place to put hardware breakpoint */
304 nds32_v3m
->next_hbr_index
++;
306 /* hardware breakpoint removal occurs after 'halted' actually */
308 } else if (breakpoint
->type
== BKPT_SOFT
) {
309 return nds32_remove_software_breakpoint(target
, breakpoint
);
310 } else /* unrecognized breakpoint type */
316 static int nds32_v3m_add_watchpoint(struct target
*target
,
317 struct watchpoint
*watchpoint
)
319 struct nds32_v3m_common
*nds32_v3m
= target_to_nds32_v3m(target
);
321 /* check hardware resource */
322 if (nds32_v3m
->next_hwp_index
>= nds32_v3m
->n_hwp
) {
323 /* No hardware resource */
324 if (nds32_v3m
->nds32
.global_stop
) {
325 LOG_WARNING("<-- TARGET WARNING! The number of "
326 "watchpoints exceeds the hardware "
327 "resources. Stop at every load/store "
328 "instruction to check for watchpoint matches. -->");
332 LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
333 "watchpoints! The limit of hardware watchpoints "
334 "is %d. -->", nds32_v3m
->n_hwp
);
335 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
336 "hardware watchpoint: %d. -->",
337 nds32_v3m
->used_n_wp
);
338 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
341 if (nds32_v3m
->next_hwp_index
> nds32_v3m
->next_hbr_index
) {
342 /* No hardware resource */
343 if (nds32_v3m
->nds32
.global_stop
) {
344 LOG_WARNING("<-- TARGET WARNING! The number of "
345 "watchpoints exceeds the hardware "
346 "resources. Stop at every load/store "
347 "instruction to check for watchpoint matches. -->");
351 LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
352 "breakpoints/watchpoints! The limit of combined "
353 "hardware breakpoints/watchpoints is %d. -->",
355 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
356 "hardware breakpoint: %d, hardware "
357 "watchpoints: %d. -->",
358 nds32_v3m
->n_hbr
- nds32_v3m
->next_hbr_index
- 1,
359 nds32_v3m
->used_n_wp
);
360 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
363 /* update next place to put hardware watchpoint */
364 nds32_v3m
->next_hwp_index
++;
365 nds32_v3m
->used_n_wp
++;
370 static int nds32_v3m_remove_watchpoint(struct target
*target
,
371 struct watchpoint
*watchpoint
)
373 struct nds32_v3m_common
*nds32_v3m
= target_to_nds32_v3m(target
);
375 if (nds32_v3m
->next_hwp_index
<= 0) {
376 if (nds32_v3m
->nds32
.global_stop
)
382 /* update next place to put hardware watchpoint */
383 nds32_v3m
->next_hwp_index
--;
384 nds32_v3m
->used_n_wp
--;
389 struct nds32_v3_common_callback nds32_v3m_common_callback
= {
390 .check_interrupt_stack
= nds32_v3m_check_interrupt_stack
,
391 .restore_interrupt_stack
= nds32_v3m_restore_interrupt_stack
,
392 .activate_hardware_breakpoint
= nds32_v3m_activate_hardware_breakpoint
,
393 .activate_hardware_watchpoint
= nds32_v3m_activate_hardware_watchpoint
,
394 .deactivate_hardware_breakpoint
= nds32_v3m_deactivate_hardware_breakpoint
,
395 .deactivate_hardware_watchpoint
= nds32_v3m_deactivate_hardware_watchpoint
,
398 static int nds32_v3m_target_create(struct target
*target
, Jim_Interp
*interp
)
400 struct nds32_v3m_common
*nds32_v3m
;
402 nds32_v3m
= calloc(1, sizeof(*nds32_v3m
));
406 nds32_v3_common_register_callback(&nds32_v3m_common_callback
);
407 nds32_v3_target_create_common(target
, &(nds32_v3m
->nds32
));
412 /* talk to the target and set things up */
413 static int nds32_v3m_examine(struct target
*target
)
415 struct nds32_v3m_common
*nds32_v3m
= target_to_nds32_v3m(target
);
416 struct nds32
*nds32
= &(nds32_v3m
->nds32
);
417 struct aice_port_s
*aice
= target_to_aice(target
);
419 if (!target_was_examined(target
)) {
420 CHECK_RETVAL(nds32_edm_config(nds32
));
422 if (nds32
->reset_halt_as_examine
)
423 CHECK_RETVAL(nds32_reset_halt(nds32
));
427 aice_read_debug_reg(aice
, NDS_EDM_SR_EDM_CFG
, &edm_cfg
);
429 /* get the number of hardware breakpoints */
430 nds32_v3m
->n_hbr
= (edm_cfg
& 0x7) + 1;
431 nds32_v3m
->used_n_wp
= 0;
433 /* get the number of hardware watchpoints */
434 /* If the WP field is hardwired to zero, it means this is a
435 * simple breakpoint. Otherwise, if the WP field is writable
436 * then it means this is a regular watchpoints. */
437 nds32_v3m
->n_hwp
= 0;
438 for (int32_t i
= 0 ; i
< nds32_v3m
->n_hbr
; i
++) {
439 /** check the hardware breakpoint is simple or not */
441 aice_write_debug_reg(aice
, NDS_EDM_SR_BPC0
+ i
, 0x1);
442 aice_read_debug_reg(aice
, NDS_EDM_SR_BPC0
+ i
, &tmp_value
);
447 /* hardware breakpoint is inserted from high index to low index */
448 nds32_v3m
->next_hbr_index
= nds32_v3m
->n_hbr
- 1;
449 /* hardware watchpoint is inserted from low index to high index */
450 nds32_v3m
->next_hwp_index
= 0;
452 LOG_INFO("%s: total hardware breakpoint %d (simple breakpoint %d)",
453 target_name(target
), nds32_v3m
->n_hbr
, nds32_v3m
->n_hbr
- nds32_v3m
->n_hwp
);
454 LOG_INFO("%s: total hardware watchpoint %d", target_name(target
), nds32_v3m
->n_hwp
);
456 nds32
->target
->state
= TARGET_RUNNING
;
457 nds32
->target
->debug_reason
= DBG_REASON_NOTHALTED
;
459 target_set_examined(target
);
464 /** Holds methods for NDS32 V3m targets. */
465 struct target_type nds32_v3m_target
= {
469 .arch_state
= nds32_arch_state
,
471 .target_request_data
= nds32_v3_target_request_data
,
474 .resume
= nds32_resume
,
477 .assert_reset
= nds32_assert_reset
,
478 .deassert_reset
= nds32_v3m_deassert_reset
,
479 .soft_reset_halt
= nds32_v3_soft_reset_halt
,
481 /* register access */
482 .get_gdb_reg_list
= nds32_get_gdb_reg_list
,
485 .read_buffer
= nds32_v3_read_buffer
,
486 .write_buffer
= nds32_v3_write_buffer
,
487 .read_memory
= nds32_v3_read_memory
,
488 .write_memory
= nds32_v3_write_memory
,
490 .checksum_memory
= nds32_v3_checksum_memory
,
492 /* breakpoint/watchpoint */
493 .add_breakpoint
= nds32_v3m_add_breakpoint
,
494 .remove_breakpoint
= nds32_v3m_remove_breakpoint
,
495 .add_watchpoint
= nds32_v3m_add_watchpoint
,
496 .remove_watchpoint
= nds32_v3m_remove_watchpoint
,
497 .hit_watchpoint
= nds32_v3_hit_watchpoint
,
501 .virt2phys
= nds32_virtual_to_physical
,
502 .read_phys_memory
= nds32_read_phys_memory
,
503 .write_phys_memory
= nds32_write_phys_memory
,
505 .run_algorithm
= nds32_v3_run_algorithm
,
507 .commands
= nds32_command_handlers
,
508 .target_create
= nds32_v3m_target_create
,
509 .init_target
= nds32_v3_init_target
,
510 .examine
= nds32_v3m_examine
,
512 .get_gdb_fileio_info
= nds32_get_gdb_fileio_info
,
513 .gdb_fileio_end
= nds32_gdb_fileio_end
,