target/xtensa: virtualize XDM registers
[openocd.git] / src / target / nds32_v3m.c
blob4ea1d38ac59238d4766cc5bc59842ab9afc98f33
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 /***************************************************************************
4 * Copyright (C) 2013 Andes Technology *
5 * Hsiangkai Wang <hkwang@andestech.com> *
6 ***************************************************************************/
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
12 #include "breakpoints.h"
13 #include "nds32_cmd.h"
14 #include "nds32_aice.h"
15 #include "nds32_v3m.h"
16 #include "nds32_v3_common.h"
18 static int nds32_v3m_activate_hardware_breakpoint(struct target *target)
20 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
21 struct aice_port_s *aice = target_to_aice(target);
22 struct breakpoint *bp;
23 unsigned brp_num = nds32_v3m->n_hbr - 1;
25 for (bp = target->breakpoints; bp; bp = bp->next) {
26 if (bp->type == BKPT_SOFT) {
27 /* already set at nds32_v3m_add_breakpoint() */
28 continue;
29 } else if (bp->type == BKPT_HARD) {
30 /* set address */
31 aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + brp_num, bp->address);
32 /* set mask */
33 aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + brp_num, 0);
35 if (nds32_v3m->nds32.memory.address_translation)
36 /* enable breakpoint (virtual address) */
37 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0x2);
38 else
39 /* enable breakpoint (physical address) */
40 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0xA);
42 LOG_DEBUG("Add hardware BP %u at %08" TARGET_PRIxADDR, brp_num,
43 bp->address);
45 brp_num--;
46 } else {
47 return ERROR_FAIL;
51 return ERROR_OK;
54 static int nds32_v3m_deactivate_hardware_breakpoint(struct target *target)
56 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
57 struct aice_port_s *aice = target_to_aice(target);
58 struct breakpoint *bp;
59 unsigned brp_num = nds32_v3m->n_hbr - 1;
61 for (bp = target->breakpoints; bp; bp = bp->next) {
62 if (bp->type == BKPT_SOFT)
63 continue;
64 else if (bp->type == BKPT_HARD)
65 /* disable breakpoint */
66 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0x0);
67 else
68 return ERROR_FAIL;
70 LOG_DEBUG("Remove hardware BP %u at %08" TARGET_PRIxADDR, brp_num,
71 bp->address);
73 brp_num--;
76 return ERROR_OK;
79 static int nds32_v3m_activate_hardware_watchpoint(struct target *target)
81 struct aice_port_s *aice = target_to_aice(target);
82 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
83 struct watchpoint *wp;
84 int32_t wp_num = 0;
85 uint32_t wp_config = 0;
86 bool ld_stop, st_stop;
88 if (nds32_v3m->nds32.global_stop)
89 ld_stop = st_stop = false;
91 for (wp = target->watchpoints; wp; wp = wp->next) {
93 if (wp_num < nds32_v3m->used_n_wp) {
94 wp->mask = wp->length - 1;
95 if ((wp->address % wp->length) != 0)
96 wp->mask = (wp->mask << 1) + 1;
98 if (wp->rw == WPT_READ)
99 wp_config = 0x3;
100 else if (wp->rw == WPT_WRITE)
101 wp_config = 0x5;
102 else if (wp->rw == WPT_ACCESS)
103 wp_config = 0x7;
105 /* set/unset physical address bit of BPCn according to PSW.DT */
106 if (nds32_v3m->nds32.memory.address_translation == false)
107 wp_config |= 0x8;
109 /* set address */
110 aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + wp_num,
111 wp->address - (wp->address % wp->length));
112 /* set mask */
113 aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + wp_num, wp->mask);
114 /* enable watchpoint */
115 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, wp_config);
117 LOG_DEBUG("Add hardware watchpoint %" PRId32 " at %08" TARGET_PRIxADDR
118 " mask %08" PRIx32, wp_num, wp->address, wp->mask);
120 wp_num++;
121 } else if (nds32_v3m->nds32.global_stop) {
122 if (wp->rw == WPT_READ)
123 ld_stop = true;
124 else if (wp->rw == WPT_WRITE)
125 st_stop = true;
126 else if (wp->rw == WPT_ACCESS)
127 ld_stop = st_stop = true;
131 if (nds32_v3m->nds32.global_stop) {
132 uint32_t edm_ctl;
133 aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl);
134 if (ld_stop)
135 edm_ctl |= 0x10;
136 if (st_stop)
137 edm_ctl |= 0x20;
138 aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl);
141 return ERROR_OK;
144 static int nds32_v3m_deactivate_hardware_watchpoint(struct target *target)
146 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
147 struct aice_port_s *aice = target_to_aice(target);
148 struct watchpoint *wp;
149 int32_t wp_num = 0;
150 bool clean_global_stop = false;
152 for (wp = target->watchpoints; wp; wp = wp->next) {
154 if (wp_num < nds32_v3m->used_n_wp) {
155 /* disable watchpoint */
156 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, 0x0);
158 LOG_DEBUG("Remove hardware watchpoint %" PRId32 " at %08" TARGET_PRIxADDR
159 " mask %08" PRIx32, wp_num, wp->address, wp->mask);
160 wp_num++;
161 } else if (nds32_v3m->nds32.global_stop) {
162 clean_global_stop = true;
166 if (clean_global_stop) {
167 uint32_t edm_ctl;
168 aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl);
169 edm_ctl = edm_ctl & (~0x30);
170 aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl);
173 return ERROR_OK;
176 static int nds32_v3m_check_interrupt_stack(struct nds32 *nds32)
178 uint32_t val_ir0;
179 uint32_t value;
181 /* Save interrupt level */
182 nds32_get_mapped_reg(nds32, IR0, &val_ir0);
183 nds32->current_interrupt_level = (val_ir0 >> 1) & 0x3;
185 if (nds32_reach_max_interrupt_level(nds32))
186 LOG_ERROR("<-- TARGET ERROR! Reaching the max interrupt stack level %" PRIu32 ". -->",
187 nds32->current_interrupt_level);
189 /* backup $ir6 to avoid suppressed exception overwrite */
190 nds32_get_mapped_reg(nds32, IR6, &value);
192 return ERROR_OK;
195 static int nds32_v3m_restore_interrupt_stack(struct nds32 *nds32)
197 uint32_t value;
199 /* get backup value from cache */
200 /* then set back to make the register dirty */
201 nds32_get_mapped_reg(nds32, IR0, &value);
202 nds32_set_mapped_reg(nds32, IR0, value);
204 nds32_get_mapped_reg(nds32, IR6, &value);
205 nds32_set_mapped_reg(nds32, IR6, value);
207 return ERROR_OK;
210 static int nds32_v3m_deassert_reset(struct target *target)
212 int retval;
214 CHECK_RETVAL(nds32_poll(target));
216 if (target->state != TARGET_HALTED) {
217 /* reset only */
218 LOG_WARNING("%s: ran after reset and before halt ...",
219 target_name(target));
220 retval = target_halt(target);
221 if (retval != ERROR_OK)
222 return retval;
226 return ERROR_OK;
229 static int nds32_v3m_add_breakpoint(struct target *target,
230 struct breakpoint *breakpoint)
232 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
233 struct nds32 *nds32 = &(nds32_v3m->nds32);
234 int result;
236 if (breakpoint->type == BKPT_HARD) {
237 /* check hardware resource */
238 if (nds32_v3m->next_hbr_index < nds32_v3m->next_hwp_index) {
239 LOG_WARNING("<-- TARGET WARNING! Insert too many "
240 "hardware breakpoints/watchpoints! "
241 "The limit of combined hardware "
242 "breakpoints/watchpoints is %" PRId32 ". -->",
243 nds32_v3m->n_hbr);
244 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
245 "hardware breakpoint: %" PRId32 ", hardware "
246 "watchpoints: %" PRId32 ". -->",
247 nds32_v3m->n_hbr - nds32_v3m->next_hbr_index - 1,
248 nds32_v3m->used_n_wp);
249 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
252 /* update next place to put hardware breakpoint */
253 nds32_v3m->next_hbr_index--;
255 /* hardware breakpoint insertion occurs before 'continue' actually */
256 return ERROR_OK;
257 } else if (breakpoint->type == BKPT_SOFT) {
258 result = nds32_add_software_breakpoint(target, breakpoint);
259 if (result != ERROR_OK) {
260 /* auto convert to hardware breakpoint if failed */
261 if (nds32->auto_convert_hw_bp) {
262 /* convert to hardware breakpoint */
263 breakpoint->type = BKPT_HARD;
265 return nds32_v3m_add_breakpoint(target, breakpoint);
269 return result;
270 } else /* unrecognized breakpoint type */
271 return ERROR_FAIL;
273 return ERROR_OK;
276 static int nds32_v3m_remove_breakpoint(struct target *target,
277 struct breakpoint *breakpoint)
279 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
281 if (breakpoint->type == BKPT_HARD) {
282 if (nds32_v3m->next_hbr_index >= nds32_v3m->n_hbr - 1)
283 return ERROR_FAIL;
285 /* update next place to put hardware breakpoint */
286 nds32_v3m->next_hbr_index++;
288 /* hardware breakpoint removal occurs after 'halted' actually */
289 return ERROR_OK;
290 } else if (breakpoint->type == BKPT_SOFT) {
291 return nds32_remove_software_breakpoint(target, breakpoint);
292 } else /* unrecognized breakpoint type */
293 return ERROR_FAIL;
295 return ERROR_OK;
298 static int nds32_v3m_add_watchpoint(struct target *target,
299 struct watchpoint *watchpoint)
301 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
303 /* check hardware resource */
304 if (nds32_v3m->next_hwp_index >= nds32_v3m->n_hwp) {
305 /* No hardware resource */
306 if (nds32_v3m->nds32.global_stop) {
307 LOG_WARNING("<-- TARGET WARNING! The number of "
308 "watchpoints exceeds the hardware "
309 "resources. Stop at every load/store "
310 "instruction to check for watchpoint matches. -->");
311 return ERROR_OK;
314 LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
315 "watchpoints! The limit of hardware watchpoints "
316 "is %" PRId32 ". -->", nds32_v3m->n_hwp);
317 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
318 "hardware watchpoint: %" PRId32 ". -->",
319 nds32_v3m->used_n_wp);
320 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
323 if (nds32_v3m->next_hwp_index > nds32_v3m->next_hbr_index) {
324 /* No hardware resource */
325 if (nds32_v3m->nds32.global_stop) {
326 LOG_WARNING("<-- TARGET WARNING! The number of "
327 "watchpoints exceeds the hardware "
328 "resources. Stop at every load/store "
329 "instruction to check for watchpoint matches. -->");
330 return ERROR_OK;
333 LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
334 "breakpoints/watchpoints! The limit of combined "
335 "hardware breakpoints/watchpoints is %" PRId32 ". -->",
336 nds32_v3m->n_hbr);
337 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
338 "hardware breakpoint: %" PRId32 ", hardware "
339 "watchpoints: %" PRId32 ". -->",
340 nds32_v3m->n_hbr - nds32_v3m->next_hbr_index - 1,
341 nds32_v3m->used_n_wp);
342 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
345 /* update next place to put hardware watchpoint */
346 nds32_v3m->next_hwp_index++;
347 nds32_v3m->used_n_wp++;
349 return ERROR_OK;
352 static int nds32_v3m_remove_watchpoint(struct target *target,
353 struct watchpoint *watchpoint)
355 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
357 if (nds32_v3m->next_hwp_index <= 0) {
358 if (nds32_v3m->nds32.global_stop)
359 return ERROR_OK;
361 return ERROR_FAIL;
364 /* update next place to put hardware watchpoint */
365 nds32_v3m->next_hwp_index--;
366 nds32_v3m->used_n_wp--;
368 return ERROR_OK;
371 static struct nds32_v3_common_callback nds32_v3m_common_callback = {
372 .check_interrupt_stack = nds32_v3m_check_interrupt_stack,
373 .restore_interrupt_stack = nds32_v3m_restore_interrupt_stack,
374 .activate_hardware_breakpoint = nds32_v3m_activate_hardware_breakpoint,
375 .activate_hardware_watchpoint = nds32_v3m_activate_hardware_watchpoint,
376 .deactivate_hardware_breakpoint = nds32_v3m_deactivate_hardware_breakpoint,
377 .deactivate_hardware_watchpoint = nds32_v3m_deactivate_hardware_watchpoint,
380 static int nds32_v3m_target_create(struct target *target, Jim_Interp *interp)
382 struct nds32_v3m_common *nds32_v3m;
384 nds32_v3m = calloc(1, sizeof(*nds32_v3m));
385 if (!nds32_v3m)
386 return ERROR_FAIL;
388 nds32_v3_common_register_callback(&nds32_v3m_common_callback);
389 nds32_v3_target_create_common(target, &(nds32_v3m->nds32));
391 return ERROR_OK;
394 /* talk to the target and set things up */
395 static int nds32_v3m_examine(struct target *target)
397 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
398 struct nds32 *nds32 = &(nds32_v3m->nds32);
399 struct aice_port_s *aice = target_to_aice(target);
401 if (!target_was_examined(target)) {
402 CHECK_RETVAL(nds32_edm_config(nds32));
404 if (nds32->reset_halt_as_examine)
405 CHECK_RETVAL(nds32_reset_halt(nds32));
408 uint32_t edm_cfg;
409 aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CFG, &edm_cfg);
411 /* get the number of hardware breakpoints */
412 nds32_v3m->n_hbr = (edm_cfg & 0x7) + 1;
413 nds32_v3m->used_n_wp = 0;
415 /* get the number of hardware watchpoints */
416 /* If the WP field is hardwired to zero, it means this is a
417 * simple breakpoint. Otherwise, if the WP field is writable
418 * then it means this is a regular watchpoints. */
419 nds32_v3m->n_hwp = 0;
420 for (int32_t i = 0 ; i < nds32_v3m->n_hbr ; i++) {
421 /** check the hardware breakpoint is simple or not */
422 uint32_t tmp_value;
423 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + i, 0x1);
424 aice_read_debug_reg(aice, NDS_EDM_SR_BPC0 + i, &tmp_value);
426 if (tmp_value)
427 nds32_v3m->n_hwp++;
429 /* hardware breakpoint is inserted from high index to low index */
430 nds32_v3m->next_hbr_index = nds32_v3m->n_hbr - 1;
431 /* hardware watchpoint is inserted from low index to high index */
432 nds32_v3m->next_hwp_index = 0;
434 LOG_INFO("%s: total hardware breakpoint %" PRId32 " (simple breakpoint %" PRId32 ")",
435 target_name(target), nds32_v3m->n_hbr, nds32_v3m->n_hbr - nds32_v3m->n_hwp);
436 LOG_INFO("%s: total hardware watchpoint %" PRId32, target_name(target), nds32_v3m->n_hwp);
438 nds32->target->state = TARGET_RUNNING;
439 nds32->target->debug_reason = DBG_REASON_NOTHALTED;
441 target_set_examined(target);
443 return ERROR_OK;
446 /** Holds methods for NDS32 V3m targets. */
447 struct target_type nds32_v3m_target = {
448 .name = "nds32_v3m",
450 .poll = nds32_poll,
451 .arch_state = nds32_arch_state,
453 .target_request_data = nds32_v3_target_request_data,
455 .halt = nds32_halt,
456 .resume = nds32_resume,
457 .step = nds32_step,
459 .assert_reset = nds32_assert_reset,
460 .deassert_reset = nds32_v3m_deassert_reset,
462 /* register access */
463 .get_gdb_reg_list = nds32_get_gdb_reg_list,
465 /* memory access */
466 .read_buffer = nds32_v3_read_buffer,
467 .write_buffer = nds32_v3_write_buffer,
468 .read_memory = nds32_v3_read_memory,
469 .write_memory = nds32_v3_write_memory,
471 .checksum_memory = nds32_v3_checksum_memory,
473 /* breakpoint/watchpoint */
474 .add_breakpoint = nds32_v3m_add_breakpoint,
475 .remove_breakpoint = nds32_v3m_remove_breakpoint,
476 .add_watchpoint = nds32_v3m_add_watchpoint,
477 .remove_watchpoint = nds32_v3m_remove_watchpoint,
478 .hit_watchpoint = nds32_v3_hit_watchpoint,
480 /* MMU */
481 .mmu = nds32_mmu,
482 .virt2phys = nds32_virtual_to_physical,
483 .read_phys_memory = nds32_read_phys_memory,
484 .write_phys_memory = nds32_write_phys_memory,
486 .run_algorithm = nds32_v3_run_algorithm,
488 .commands = nds32_command_handlers,
489 .target_create = nds32_v3m_target_create,
490 .init_target = nds32_v3_init_target,
491 .examine = nds32_v3m_examine,
493 .get_gdb_fileio_info = nds32_get_gdb_fileio_info,
494 .gdb_fileio_end = nds32_gdb_fileio_end,