Add BCM2835 (as found in Raspberry Pi) interface driver
[openocd.git] / src / target / nds32_v3.c
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 ***************************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "breakpoints.h"
26 #include "nds32_cmd.h"
27 #include "nds32_aice.h"
28 #include "nds32_v3.h"
29 #include "nds32_v3_common.h"
30
31 static int nds32_v3_activate_hardware_breakpoint(struct target *target)
32 {
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;
37
38 for (bp = target->breakpoints; bp; bp = bp->next) {
39 if (bp->type == BKPT_SOFT) {
40 /* already set at nds32_v3_add_breakpoint() */
41 continue;
42 } else if (bp->type == BKPT_HARD) {
43 hbr_index--;
44 /* set address */
45 aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + hbr_index, bp->address);
46 /* set mask */
47 aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + hbr_index, 0);
48 /* set value */
49 aice_write_debug_reg(aice, NDS_EDM_SR_BPV0 + hbr_index, 0);
50
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);
54 else
55 /* enable breakpoint (physical address) */
56 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0xA);
57
58 LOG_DEBUG("Add hardware BP %d at %08" PRIx32, hbr_index,
59 bp->address);
60 } else {
61 return ERROR_FAIL;
62 }
63 }
64
65 return ERROR_OK;
66 }
67
68 static int nds32_v3_deactivate_hardware_breakpoint(struct target *target)
69 {
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;
74
75 for (bp = target->breakpoints; bp; bp = bp->next) {
76 if (bp->type == BKPT_SOFT) {
77 continue;
78 } else if (bp->type == BKPT_HARD) {
79 hbr_index--;
80 /* disable breakpoint */
81 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0x0);
82 } else {
83 return ERROR_FAIL;
84 }
85
86 LOG_DEBUG("Remove hardware BP %d at %08" PRIx32, hbr_index,
87 bp->address);
88 }
89
90 return ERROR_OK;
91 }
92
93 static int nds32_v3_activate_hardware_watchpoint(struct target *target)
94 {
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;
98 int32_t wp_num = 0;
99 uint32_t wp_config = 0;
100 bool ld_stop, st_stop;
101
102 if (nds32_v3->nds32.global_stop)
103 ld_stop = st_stop = false;
104
105 for (wp = target->watchpoints; wp; wp = wp->next) {
106
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;
111
112 if (wp->rw == WPT_READ)
113 wp_config = 0x3;
114 else if (wp->rw == WPT_WRITE)
115 wp_config = 0x5;
116 else if (wp->rw == WPT_ACCESS)
117 wp_config = 0x7;
118
119 /* set/unset physical address bit of BPCn according to PSW.DT */
120 if (nds32_v3->nds32.memory.address_translation == false)
121 wp_config |= 0x8;
122
123 /* set address */
124 aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + wp_num,
125 wp->address - (wp->address % wp->length));
126 /* set mask */
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);
130 /* set value */
131 aice_write_debug_reg(aice, NDS_EDM_SR_BPV0 + wp_num, 0);
132
133 LOG_DEBUG("Add hardware wathcpoint %d at %08" PRIx32 " mask %08" PRIx32,
134 wp_num, wp->address, wp->mask);
135
136 wp_num++;
137 } else if (nds32_v3->nds32.global_stop) {
138 if (wp->rw == WPT_READ)
139 ld_stop = true;
140 else if (wp->rw == WPT_WRITE)
141 st_stop = true;
142 else if (wp->rw == WPT_ACCESS)
143 ld_stop = st_stop = true;
144 }
145 }
146
147 if (nds32_v3->nds32.global_stop) {
148 uint32_t edm_ctl;
149 aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl);
150 if (ld_stop)
151 edm_ctl |= 0x10;
152 if (st_stop)
153 edm_ctl |= 0x20;
154 aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl);
155 }
156
157 return ERROR_OK;
158 }
159
160 static int nds32_v3_deactivate_hardware_watchpoint(struct target *target)
161 {
162 struct aice_port_s *aice = target_to_aice(target);
163 struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
164 int32_t wp_num = 0;
165 struct watchpoint *wp;
166 bool clean_global_stop = false;
167
168 for (wp = target->watchpoints; wp; wp = wp->next) {
169
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);
173
174 LOG_DEBUG("Remove hardware wathcpoint %d at %08" PRIx32
175 " mask %08" PRIx32, wp_num,
176 wp->address, wp->mask);
177 wp_num++;
178 } else if (nds32_v3->nds32.global_stop) {
179 clean_global_stop = true;
180 }
181 }
182
183 if (clean_global_stop) {
184 uint32_t edm_ctl;
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);
188 }
189
190 return ERROR_OK;
191 }
192
193 static int nds32_v3_check_interrupt_stack(struct nds32 *nds32)
194 {
195 uint32_t val_ir0;
196 uint32_t value;
197
198 /* Save interrupt level */
199 nds32_get_mapped_reg(nds32, IR0, &val_ir0);
200 nds32->current_interrupt_level = (val_ir0 >> 1) & 0x3;
201
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);
205
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);
209
210 return ERROR_OK;
211 }
212
213 static int nds32_v3_restore_interrupt_stack(struct nds32 *nds32)
214 {
215 uint32_t value;
216
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);
221
222 nds32_get_mapped_reg(nds32, IR4, &value);
223 nds32_set_mapped_reg(nds32, IR4, value);
224
225 nds32_get_mapped_reg(nds32, IR6, &value);
226 nds32_set_mapped_reg(nds32, IR6, value);
227
228 return ERROR_OK;
229 }
230
231 static int nds32_v3_deassert_reset(struct target *target)
232 {
233 int retval;
234 struct aice_port_s *aice = target_to_aice(target);
235 bool switch_to_v3_stack = false;
236 uint32_t value_edm_ctl;
237
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;
244 } else
245 switch_to_v3_stack = false;
246
247 CHECK_RETVAL(nds32_poll(target));
248
249 if (target->state != TARGET_HALTED) {
250 /* reset only */
251 LOG_WARNING("%s: ran after reset and before halt ...",
252 target_name(target));
253 retval = target_halt(target);
254 if (retval != ERROR_OK)
255 return retval;
256
257 /* call target_poll() to avoid "Halt timed out" */
258 CHECK_RETVAL(target_poll(target));
259 } else {
260 /* reset-halt */
261 jtag_poll_set_enabled(false);
262
263 struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
264 struct nds32 *nds32 = &(nds32_v3->nds32);
265 uint32_t value;
266 uint32_t interrupt_level;
267
268 if (switch_to_v3_stack == true) {
269 /* PSW.INTL-- */
270 nds32_get_mapped_reg(nds32, IR0, &value);
271 interrupt_level = (value >> 1) & 0x3;
272 interrupt_level--;
273 value &= ~(0x6);
274 value |= (interrupt_level << 1);
275 value |= 0x400; /* set PSW.DEX */
276 nds32_set_mapped_reg(nds32, IR0, value);
277
278 /* copy IPC to OIPC */
279 if ((interrupt_level + 1) < nds32->max_interrupt_level) {
280 nds32_get_mapped_reg(nds32, IR9, &value);
281 nds32_set_mapped_reg(nds32, IR11, value);
282 }
283 }
284 }
285
286 return ERROR_OK;
287 }
288
289 static int nds32_v3_add_breakpoint(struct target *target,
290 struct breakpoint *breakpoint)
291 {
292 struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
293 struct nds32 *nds32 = &(nds32_v3->nds32);
294 int result;
295
296 if (breakpoint->type == BKPT_HARD) {
297 /* check hardware resource */
298 if (nds32_v3->n_hbr <= nds32_v3->next_hbr_index) {
299 LOG_WARNING("<-- TARGET WARNING! Insert too many "
300 "hardware breakpoints/watchpoints! "
301 "The limit of combined hardware "
302 "breakpoints/watchpoints is %d. -->",
303 nds32_v3->n_hbr);
304 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
305 "hardware breakpoint: %d, hardware "
306 "watchpoints: %d. -->",
307 nds32_v3->next_hbr_index - nds32_v3->used_n_wp,
308 nds32_v3->used_n_wp);
309 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
310 }
311
312 /* update next place to put hardware breakpoint */
313 nds32_v3->next_hbr_index++;
314
315 /* hardware breakpoint insertion occurs before 'continue' actually */
316 return ERROR_OK;
317 } else if (breakpoint->type == BKPT_SOFT) {
318 result = nds32_add_software_breakpoint(target, breakpoint);
319 if (ERROR_OK != result) {
320 /* auto convert to hardware breakpoint if failed */
321 if (nds32->auto_convert_hw_bp) {
322 /* convert to hardware breakpoint */
323 breakpoint->type = BKPT_HARD;
324
325 return nds32_v3_add_breakpoint(target, breakpoint);
326 }
327 }
328
329 return result;
330 } else /* unrecognized breakpoint type */
331 return ERROR_FAIL;
332
333 return ERROR_OK;
334 }
335
336 static int nds32_v3_remove_breakpoint(struct target *target,
337 struct breakpoint *breakpoint)
338 {
339 struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
340
341 if (breakpoint->type == BKPT_HARD) {
342 if (nds32_v3->next_hbr_index <= 0)
343 return ERROR_FAIL;
344
345 /* update next place to put hardware breakpoint */
346 nds32_v3->next_hbr_index--;
347
348 /* hardware breakpoint removal occurs after 'halted' actually */
349 return ERROR_OK;
350 } else if (breakpoint->type == BKPT_SOFT) {
351 return nds32_remove_software_breakpoint(target, breakpoint);
352 } else /* unrecognized breakpoint type */
353 return ERROR_FAIL;
354
355 return ERROR_OK;
356 }
357
358 static int nds32_v3_add_watchpoint(struct target *target,
359 struct watchpoint *watchpoint)
360 {
361 struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
362
363 /* check hardware resource */
364 if (nds32_v3->n_hbr <= nds32_v3->next_hbr_index) {
365 /* No hardware resource */
366 if (nds32_v3->nds32.global_stop) {
367 LOG_WARNING("<-- TARGET WARNING! The number of "
368 "watchpoints exceeds the hardware "
369 "resources. Stop at every load/store "
370 "instruction to check for watchpoint matches. -->");
371 return ERROR_OK;
372 }
373
374 LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
375 "breakpoints/watchpoints! The limit of combined "
376 "hardware breakpoints/watchpoints is %d. -->",
377 nds32_v3->n_hbr);
378 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
379 "hardware breakpoint: %d, hardware "
380 "watchpoints: %d. -->",
381 nds32_v3->next_hbr_index - nds32_v3->used_n_wp,
382 nds32_v3->used_n_wp);
383
384 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
385 }
386
387 /* update next place to put hardware watchpoint */
388 nds32_v3->next_hbr_index++;
389 nds32_v3->used_n_wp++;
390
391 return ERROR_OK;
392 }
393
394 static int nds32_v3_remove_watchpoint(struct target *target,
395 struct watchpoint *watchpoint)
396 {
397 struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
398
399 if (nds32_v3->next_hbr_index <= 0) {
400 if (nds32_v3->nds32.global_stop)
401 return ERROR_OK;
402
403 return ERROR_FAIL;
404 }
405
406 /* update next place to put hardware breakpoint */
407 nds32_v3->next_hbr_index--;
408 nds32_v3->used_n_wp--;
409
410 return ERROR_OK;
411 }
412
413 struct nds32_v3_common_callback nds32_v3_common_callback = {
414 .check_interrupt_stack = nds32_v3_check_interrupt_stack,
415 .restore_interrupt_stack = nds32_v3_restore_interrupt_stack,
416 .activate_hardware_breakpoint = nds32_v3_activate_hardware_breakpoint,
417 .activate_hardware_watchpoint = nds32_v3_activate_hardware_watchpoint,
418 .deactivate_hardware_breakpoint = nds32_v3_deactivate_hardware_breakpoint,
419 .deactivate_hardware_watchpoint = nds32_v3_deactivate_hardware_watchpoint,
420 };
421
422 static int nds32_v3_target_create(struct target *target, Jim_Interp *interp)
423 {
424 struct nds32_v3_common *nds32_v3;
425
426 nds32_v3 = calloc(1, sizeof(*nds32_v3));
427 if (!nds32_v3)
428 return ERROR_FAIL;
429
430 nds32_v3_common_register_callback(&nds32_v3_common_callback);
431 nds32_v3_target_create_common(target, &(nds32_v3->nds32));
432
433 return ERROR_OK;
434 }
435
436 /* talk to the target and set things up */
437 static int nds32_v3_examine(struct target *target)
438 {
439 struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
440 struct nds32 *nds32 = &(nds32_v3->nds32);
441 struct aice_port_s *aice = target_to_aice(target);
442
443 if (!target_was_examined(target)) {
444 CHECK_RETVAL(nds32_edm_config(nds32));
445
446 if (nds32->reset_halt_as_examine)
447 CHECK_RETVAL(nds32_reset_halt(nds32));
448 }
449
450 uint32_t edm_cfg;
451 aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CFG, &edm_cfg);
452
453 /* get the number of hardware breakpoints */
454 nds32_v3->n_hbr = (edm_cfg & 0x7) + 1;
455
456 /* low interference profiling */
457 if (edm_cfg & 0x100)
458 nds32_v3->low_interference_profile = true;
459 else
460 nds32_v3->low_interference_profile = false;
461
462 nds32_v3->next_hbr_index = 0;
463 nds32_v3->used_n_wp = 0;
464
465 LOG_INFO("%s: total hardware breakpoint %d", target_name(target),
466 nds32_v3->n_hbr);
467
468 nds32->target->state = TARGET_RUNNING;
469 nds32->target->debug_reason = DBG_REASON_NOTHALTED;
470
471 target_set_examined(target);
472
473 return ERROR_OK;
474 }
475
476 /** Holds methods for Andes1337 targets. */
477 struct target_type nds32_v3_target = {
478 .name = "nds32_v3",
479
480 .poll = nds32_poll,
481 .arch_state = nds32_arch_state,
482
483 .target_request_data = nds32_v3_target_request_data,
484
485 .halt = nds32_halt,
486 .resume = nds32_resume,
487 .step = nds32_step,
488
489 .assert_reset = nds32_assert_reset,
490 .deassert_reset = nds32_v3_deassert_reset,
491 .soft_reset_halt = nds32_v3_soft_reset_halt,
492
493 /* register access */
494 .get_gdb_reg_list = nds32_get_gdb_reg_list,
495
496 /* memory access */
497 .read_buffer = nds32_v3_read_buffer,
498 .write_buffer = nds32_v3_write_buffer,
499 .read_memory = nds32_v3_read_memory,
500 .write_memory = nds32_v3_write_memory,
501
502 .checksum_memory = nds32_v3_checksum_memory,
503
504 /* breakpoint/watchpoint */
505 .add_breakpoint = nds32_v3_add_breakpoint,
506 .remove_breakpoint = nds32_v3_remove_breakpoint,
507 .add_watchpoint = nds32_v3_add_watchpoint,
508 .remove_watchpoint = nds32_v3_remove_watchpoint,
509
510 /* MMU */
511 .mmu = nds32_mmu,
512 .virt2phys = nds32_virtual_to_physical,
513 .read_phys_memory = nds32_read_phys_memory,
514 .write_phys_memory = nds32_write_phys_memory,
515
516 .run_algorithm = nds32_v3_run_algorithm,
517
518 .commands = nds32_command_handlers,
519 .target_create = nds32_v3_target_create,
520 .init_target = nds32_v3_init_target,
521 .examine = nds32_v3_examine,
522 };

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)