gdb_server: support File-I/O Remote Protocol Extension
[openocd.git] / src / target / nds32_v3m.c
blobd72d986915fb0246caf49b73a20c354eb1e146c0
1 /***************************************************************************
2 * Copyright (C) 2013 Andes Technology *
3 * Hsiangkai Wang <hkwang@andestech.com> *
4 * *
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. *
9 * *
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. *
14 * *
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 ***************************************************************************/
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
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() */
41 continue;
42 } else if (bp->type == BKPT_HARD) {
43 /* set address */
44 aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + brp_num, bp->address);
45 /* set mask */
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);
51 else
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,
56 bp->address);
58 brp_num--;
59 } else {
60 return ERROR_FAIL;
64 return ERROR_OK;
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)
76 continue;
77 else if (bp->type == BKPT_HARD)
78 /* disable breakpoint */
79 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0x0);
80 else
81 return ERROR_FAIL;
83 LOG_DEBUG("Remove hardware BP %d at %08" PRIx32, brp_num,
84 bp->address);
86 brp_num--;
89 return ERROR_OK;
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;
97 int32_t wp_num = 0;
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)
112 wp_config = 0x3;
113 else if (wp->rw == WPT_WRITE)
114 wp_config = 0x5;
115 else if (wp->rw == WPT_ACCESS)
116 wp_config = 0x7;
118 /* set/unset physical address bit of BPCn according to PSW.DT */
119 if (nds32_v3m->nds32.memory.address_translation == false)
120 wp_config |= 0x8;
122 /* set address */
123 aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + wp_num,
124 wp->address - (wp->address % wp->length));
125 /* set mask */
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);
134 wp_num++;
135 } else if (nds32_v3m->nds32.global_stop) {
136 if (wp->rw == WPT_READ)
137 ld_stop = true;
138 else if (wp->rw == WPT_WRITE)
139 st_stop = true;
140 else if (wp->rw == WPT_ACCESS)
141 ld_stop = st_stop = true;
145 if (nds32_v3m->nds32.global_stop) {
146 uint32_t edm_ctl;
147 aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl);
148 if (ld_stop)
149 edm_ctl |= 0x10;
150 if (st_stop)
151 edm_ctl |= 0x20;
152 aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl);
155 return ERROR_OK;
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;
163 int32_t wp_num = 0;
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);
175 wp_num++;
176 } else if (nds32_v3m->nds32.global_stop) {
177 clean_global_stop = true;
181 if (clean_global_stop) {
182 uint32_t edm_ctl;
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);
188 return ERROR_OK;
191 static int nds32_v3m_check_interrupt_stack(struct nds32 *nds32)
193 uint32_t val_ir0;
194 uint32_t value;
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);
207 return ERROR_OK;
210 static int nds32_v3m_restore_interrupt_stack(struct nds32 *nds32)
212 uint32_t value;
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);
222 return ERROR_OK;
225 static int nds32_v3m_deassert_reset(struct target *target)
227 int retval;
229 CHECK_RETVAL(nds32_poll(target));
231 if (target->state != TARGET_HALTED) {
232 /* reset only */
233 LOG_WARNING("%s: ran after reset and before halt ...",
234 target_name(target));
235 retval = target_halt(target);
236 if (retval != ERROR_OK)
237 return retval;
238 /* call target_poll() to avoid "Halt timed out" */
239 CHECK_RETVAL(target_poll(target));
240 } else {
241 jtag_poll_set_enabled(false);
244 return ERROR_OK;
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);
252 int result;
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. -->",
261 nds32_v3m->n_hbr);
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 */
274 return ERROR_OK;
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);
287 return result;
288 } else /* unrecognized breakpoint type */
289 return ERROR_FAIL;
291 return ERROR_OK;
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)
301 return ERROR_FAIL;
303 /* update next place to put hardware breakpoint */
304 nds32_v3m->next_hbr_index++;
306 /* hardware breakpoint removal occurs after 'halted' actually */
307 return ERROR_OK;
308 } else if (breakpoint->type == BKPT_SOFT) {
309 return nds32_remove_software_breakpoint(target, breakpoint);
310 } else /* unrecognized breakpoint type */
311 return ERROR_FAIL;
313 return ERROR_OK;
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. -->");
329 return ERROR_OK;
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. -->");
348 return ERROR_OK;
351 LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
352 "breakpoints/watchpoints! The limit of combined "
353 "hardware breakpoints/watchpoints is %d. -->",
354 nds32_v3m->n_hbr);
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++;
367 return ERROR_OK;
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)
377 return ERROR_OK;
379 return ERROR_FAIL;
382 /* update next place to put hardware watchpoint */
383 nds32_v3m->next_hwp_index--;
384 nds32_v3m->used_n_wp--;
386 return ERROR_OK;
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));
403 if (!nds32_v3m)
404 return ERROR_FAIL;
406 nds32_v3_common_register_callback(&nds32_v3m_common_callback);
407 nds32_v3_target_create_common(target, &(nds32_v3m->nds32));
409 return ERROR_OK;
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));
426 uint32_t edm_cfg;
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 */
440 uint32_t tmp_value;
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);
444 if (tmp_value)
445 nds32_v3m->n_hwp++;
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);
461 return ERROR_OK;
464 /** Holds methods for NDS32 V3m targets. */
465 struct target_type nds32_v3m_target = {
466 .name = "nds32_v3m",
468 .poll = nds32_poll,
469 .arch_state = nds32_arch_state,
471 .target_request_data = nds32_v3_target_request_data,
473 .halt = nds32_halt,
474 .resume = nds32_resume,
475 .step = nds32_step,
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,
484 /* memory access */
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,
499 /* MMU */
500 .mmu = nds32_mmu,
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,