]> git.sur5r.net Git - openocd/blob - src/target/nds32_v3m.c
flash/nrf5: support for nRF52840 Q1AAC0
[openocd] / src / target / nds32_v3m.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, see <http://www.gnu.org/licenses/>. *
17  ***************************************************************************/
18
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #include "breakpoints.h"
24 #include "nds32_cmd.h"
25 #include "nds32_aice.h"
26 #include "nds32_v3m.h"
27 #include "nds32_v3_common.h"
28
29 static int nds32_v3m_activate_hardware_breakpoint(struct target *target)
30 {
31         struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
32         struct aice_port_s *aice = target_to_aice(target);
33         struct breakpoint *bp;
34         unsigned brp_num = nds32_v3m->n_hbr - 1;
35
36         for (bp = target->breakpoints; bp; bp = bp->next) {
37                 if (bp->type == BKPT_SOFT) {
38                         /* already set at nds32_v3m_add_breakpoint() */
39                         continue;
40                 } else if (bp->type == BKPT_HARD) {
41                         /* set address */
42                         aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + brp_num, bp->address);
43                         /* set mask */
44                         aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + brp_num, 0);
45
46                         if (nds32_v3m->nds32.memory.address_translation)
47                                 /* enable breakpoint (virtual address) */
48                                 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0x2);
49                         else
50                                 /* enable breakpoint (physical address) */
51                                 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0xA);
52
53                         LOG_DEBUG("Add hardware BP %u at %08" TARGET_PRIxADDR, brp_num,
54                                         bp->address);
55
56                         brp_num--;
57                 } else {
58                         return ERROR_FAIL;
59                 }
60         }
61
62         return ERROR_OK;
63 }
64
65 static int nds32_v3m_deactivate_hardware_breakpoint(struct target *target)
66 {
67         struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
68         struct aice_port_s *aice = target_to_aice(target);
69         struct breakpoint *bp;
70         unsigned brp_num = nds32_v3m->n_hbr - 1;
71
72         for (bp = target->breakpoints; bp; bp = bp->next) {
73                 if (bp->type == BKPT_SOFT)
74                         continue;
75                 else if (bp->type == BKPT_HARD)
76                         /* disable breakpoint */
77                         aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0x0);
78                 else
79                         return ERROR_FAIL;
80
81                 LOG_DEBUG("Remove hardware BP %u at %08" TARGET_PRIxADDR, brp_num,
82                                 bp->address);
83
84                 brp_num--;
85         }
86
87         return ERROR_OK;
88 }
89
90 static int nds32_v3m_activate_hardware_watchpoint(struct target *target)
91 {
92         struct aice_port_s *aice = target_to_aice(target);
93         struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
94         struct watchpoint *wp;
95         int32_t  wp_num = 0;
96         uint32_t wp_config = 0;
97         bool ld_stop, st_stop;
98
99         if (nds32_v3m->nds32.global_stop)
100                 ld_stop = st_stop = false;
101
102         for (wp = target->watchpoints; wp; wp = wp->next) {
103
104                 if (wp_num < nds32_v3m->used_n_wp) {
105                         wp->mask = wp->length - 1;
106                         if ((wp->address % wp->length) != 0)
107                                 wp->mask = (wp->mask << 1) + 1;
108
109                         if (wp->rw == WPT_READ)
110                                 wp_config = 0x3;
111                         else if (wp->rw == WPT_WRITE)
112                                 wp_config = 0x5;
113                         else if (wp->rw == WPT_ACCESS)
114                                 wp_config = 0x7;
115
116                         /* set/unset physical address bit of BPCn according to PSW.DT */
117                         if (nds32_v3m->nds32.memory.address_translation == false)
118                                 wp_config |= 0x8;
119
120                         /* set address */
121                         aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + wp_num,
122                                         wp->address - (wp->address % wp->length));
123                         /* set mask */
124                         aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + wp_num, wp->mask);
125                         /* enable watchpoint */
126                         aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, wp_config);
127
128                         LOG_DEBUG("Add hardware watchpoint %" PRId32 " at %08" TARGET_PRIxADDR
129                                         " mask %08" PRIx32, wp_num, wp->address, wp->mask);
130
131                         wp_num++;
132                 } else if (nds32_v3m->nds32.global_stop) {
133                         if (wp->rw == WPT_READ)
134                                 ld_stop = true;
135                         else if (wp->rw == WPT_WRITE)
136                                 st_stop = true;
137                         else if (wp->rw == WPT_ACCESS)
138                                 ld_stop = st_stop = true;
139                 }
140         }
141
142         if (nds32_v3m->nds32.global_stop) {
143                 uint32_t edm_ctl;
144                 aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl);
145                 if (ld_stop)
146                         edm_ctl |= 0x10;
147                 if (st_stop)
148                         edm_ctl |= 0x20;
149                 aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl);
150         }
151
152         return ERROR_OK;
153 }
154
155 static int nds32_v3m_deactivate_hardware_watchpoint(struct target *target)
156 {
157         struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
158         struct aice_port_s *aice = target_to_aice(target);
159         struct watchpoint *wp;
160         int32_t wp_num = 0;
161         bool clean_global_stop = false;
162
163         for (wp = target->watchpoints; wp; wp = wp->next) {
164
165                 if (wp_num < nds32_v3m->used_n_wp) {
166                         /* disable watchpoint */
167                         aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, 0x0);
168
169                         LOG_DEBUG("Remove hardware watchpoint %" PRId32 " at %08" TARGET_PRIxADDR
170                                         " mask %08" PRIx32, wp_num, wp->address, wp->mask);
171                         wp_num++;
172                 } else if (nds32_v3m->nds32.global_stop) {
173                         clean_global_stop = true;
174                 }
175         }
176
177         if (clean_global_stop) {
178                 uint32_t edm_ctl;
179                 aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl);
180                 edm_ctl = edm_ctl & (~0x30);
181                 aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl);
182         }
183
184         return ERROR_OK;
185 }
186
187 static int nds32_v3m_check_interrupt_stack(struct nds32 *nds32)
188 {
189         uint32_t val_ir0;
190         uint32_t value;
191
192         /* Save interrupt level */
193         nds32_get_mapped_reg(nds32, IR0, &val_ir0);
194         nds32->current_interrupt_level = (val_ir0 >> 1) & 0x3;
195
196         if (nds32_reach_max_interrupt_level(nds32))
197                 LOG_ERROR("<-- TARGET ERROR! Reaching the max interrupt stack level %" PRIu32 ". -->",
198                                 nds32->current_interrupt_level);
199
200         /* backup $ir6 to avoid suppressed exception overwrite */
201         nds32_get_mapped_reg(nds32, IR6, &value);
202
203         return ERROR_OK;
204 }
205
206 static int nds32_v3m_restore_interrupt_stack(struct nds32 *nds32)
207 {
208         uint32_t value;
209
210         /* get backup value from cache */
211         /* then set back to make the register dirty */
212         nds32_get_mapped_reg(nds32, IR0, &value);
213         nds32_set_mapped_reg(nds32, IR0, value);
214
215         nds32_get_mapped_reg(nds32, IR6, &value);
216         nds32_set_mapped_reg(nds32, IR6, value);
217
218         return ERROR_OK;
219 }
220
221 static int nds32_v3m_deassert_reset(struct target *target)
222 {
223         int retval;
224
225         CHECK_RETVAL(nds32_poll(target));
226
227         if (target->state != TARGET_HALTED) {
228                 /* reset only */
229                 LOG_WARNING("%s: ran after reset and before halt ...",
230                                 target_name(target));
231                 retval = target_halt(target);
232                 if (retval != ERROR_OK)
233                         return retval;
234
235         }
236
237         return ERROR_OK;
238 }
239
240 static int nds32_v3m_add_breakpoint(struct target *target,
241                 struct breakpoint *breakpoint)
242 {
243         struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
244         struct nds32 *nds32 = &(nds32_v3m->nds32);
245         int result;
246
247         if (breakpoint->type == BKPT_HARD) {
248                 /* check hardware resource */
249                 if (nds32_v3m->next_hbr_index < nds32_v3m->next_hwp_index) {
250                         LOG_WARNING("<-- TARGET WARNING! Insert too many "
251                                         "hardware breakpoints/watchpoints! "
252                                         "The limit of combined hardware "
253                                         "breakpoints/watchpoints is %" PRId32 ". -->",
254                                         nds32_v3m->n_hbr);
255                         LOG_WARNING("<-- TARGET STATUS: Inserted number of "
256                                         "hardware breakpoint: %" PRId32 ", hardware "
257                                         "watchpoints: %" PRId32 ". -->",
258                                         nds32_v3m->n_hbr - nds32_v3m->next_hbr_index - 1,
259                                         nds32_v3m->used_n_wp);
260                         return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
261                 }
262
263                 /* update next place to put hardware breakpoint */
264                 nds32_v3m->next_hbr_index--;
265
266                 /* hardware breakpoint insertion occurs before 'continue' actually */
267                 return ERROR_OK;
268         } else if (breakpoint->type == BKPT_SOFT) {
269                 result = nds32_add_software_breakpoint(target, breakpoint);
270                 if (ERROR_OK != result) {
271                         /* auto convert to hardware breakpoint if failed */
272                         if (nds32->auto_convert_hw_bp) {
273                                 /* convert to hardware breakpoint */
274                                 breakpoint->type = BKPT_HARD;
275
276                                 return nds32_v3m_add_breakpoint(target, breakpoint);
277                         }
278                 }
279
280                 return result;
281         } else /* unrecognized breakpoint type */
282                 return ERROR_FAIL;
283
284         return ERROR_OK;
285 }
286
287 static int nds32_v3m_remove_breakpoint(struct target *target,
288                 struct breakpoint *breakpoint)
289 {
290         struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
291
292         if (breakpoint->type == BKPT_HARD) {
293                 if (nds32_v3m->next_hbr_index >= nds32_v3m->n_hbr - 1)
294                         return ERROR_FAIL;
295
296                 /* update next place to put hardware breakpoint */
297                 nds32_v3m->next_hbr_index++;
298
299                 /* hardware breakpoint removal occurs after 'halted' actually */
300                 return ERROR_OK;
301         } else if (breakpoint->type == BKPT_SOFT) {
302                 return nds32_remove_software_breakpoint(target, breakpoint);
303         } else /* unrecognized breakpoint type */
304                 return ERROR_FAIL;
305
306         return ERROR_OK;
307 }
308
309 static int nds32_v3m_add_watchpoint(struct target *target,
310                 struct watchpoint *watchpoint)
311 {
312         struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
313
314         /* check hardware resource */
315         if (nds32_v3m->next_hwp_index >= nds32_v3m->n_hwp) {
316                 /* No hardware resource */
317                 if (nds32_v3m->nds32.global_stop) {
318                         LOG_WARNING("<-- TARGET WARNING! The number of "
319                                         "watchpoints exceeds the hardware "
320                                         "resources. Stop at every load/store "
321                                         "instruction to check for watchpoint matches. -->");
322                         return ERROR_OK;
323                 }
324
325                 LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
326                                 "watchpoints! The limit of hardware watchpoints "
327                                 "is %" PRId32 ". -->", nds32_v3m->n_hwp);
328                 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
329                                 "hardware watchpoint: %" PRId32 ". -->",
330                                 nds32_v3m->used_n_wp);
331                 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
332         }
333
334         if (nds32_v3m->next_hwp_index > nds32_v3m->next_hbr_index) {
335                 /* No hardware resource */
336                 if (nds32_v3m->nds32.global_stop) {
337                         LOG_WARNING("<-- TARGET WARNING! The number of "
338                                         "watchpoints exceeds the hardware "
339                                         "resources. Stop at every load/store "
340                                         "instruction to check for watchpoint matches. -->");
341                         return ERROR_OK;
342                 }
343
344                 LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
345                                 "breakpoints/watchpoints! The limit of combined "
346                                 "hardware breakpoints/watchpoints is %" PRId32 ". -->",
347                                 nds32_v3m->n_hbr);
348                 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
349                                 "hardware breakpoint: %" PRId32 ", hardware "
350                                 "watchpoints: %" PRId32 ". -->",
351                                 nds32_v3m->n_hbr - nds32_v3m->next_hbr_index - 1,
352                                 nds32_v3m->used_n_wp);
353                 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
354         }
355
356         /* update next place to put hardware watchpoint */
357         nds32_v3m->next_hwp_index++;
358         nds32_v3m->used_n_wp++;
359
360         return ERROR_OK;
361 }
362
363 static int nds32_v3m_remove_watchpoint(struct target *target,
364                 struct watchpoint *watchpoint)
365 {
366         struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
367
368         if (nds32_v3m->next_hwp_index <= 0) {
369                 if (nds32_v3m->nds32.global_stop)
370                         return ERROR_OK;
371
372                 return ERROR_FAIL;
373         }
374
375         /* update next place to put hardware watchpoint */
376         nds32_v3m->next_hwp_index--;
377         nds32_v3m->used_n_wp--;
378
379         return ERROR_OK;
380 }
381
382 struct nds32_v3_common_callback nds32_v3m_common_callback = {
383         .check_interrupt_stack = nds32_v3m_check_interrupt_stack,
384         .restore_interrupt_stack = nds32_v3m_restore_interrupt_stack,
385         .activate_hardware_breakpoint = nds32_v3m_activate_hardware_breakpoint,
386         .activate_hardware_watchpoint = nds32_v3m_activate_hardware_watchpoint,
387         .deactivate_hardware_breakpoint = nds32_v3m_deactivate_hardware_breakpoint,
388         .deactivate_hardware_watchpoint = nds32_v3m_deactivate_hardware_watchpoint,
389 };
390
391 static int nds32_v3m_target_create(struct target *target, Jim_Interp *interp)
392 {
393         struct nds32_v3m_common *nds32_v3m;
394
395         nds32_v3m = calloc(1, sizeof(*nds32_v3m));
396         if (!nds32_v3m)
397                 return ERROR_FAIL;
398
399         nds32_v3_common_register_callback(&nds32_v3m_common_callback);
400         nds32_v3_target_create_common(target, &(nds32_v3m->nds32));
401
402         return ERROR_OK;
403 }
404
405 /* talk to the target and set things up */
406 static int nds32_v3m_examine(struct target *target)
407 {
408         struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
409         struct nds32 *nds32 = &(nds32_v3m->nds32);
410         struct aice_port_s *aice = target_to_aice(target);
411
412         if (!target_was_examined(target)) {
413                 CHECK_RETVAL(nds32_edm_config(nds32));
414
415                 if (nds32->reset_halt_as_examine)
416                         CHECK_RETVAL(nds32_reset_halt(nds32));
417         }
418
419         uint32_t edm_cfg;
420         aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CFG, &edm_cfg);
421
422         /* get the number of hardware breakpoints */
423         nds32_v3m->n_hbr = (edm_cfg & 0x7) + 1;
424         nds32_v3m->used_n_wp = 0;
425
426         /* get the number of hardware watchpoints */
427         /* If the WP field is hardwired to zero, it means this is a
428          * simple breakpoint.  Otherwise, if the WP field is writable
429          * then it means this is a regular watchpoints. */
430         nds32_v3m->n_hwp = 0;
431         for (int32_t i = 0 ; i < nds32_v3m->n_hbr ; i++) {
432                 /** check the hardware breakpoint is simple or not */
433                 uint32_t tmp_value;
434                 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + i, 0x1);
435                 aice_read_debug_reg(aice, NDS_EDM_SR_BPC0 + i, &tmp_value);
436
437                 if (tmp_value)
438                         nds32_v3m->n_hwp++;
439         }
440         /* hardware breakpoint is inserted from high index to low index */
441         nds32_v3m->next_hbr_index = nds32_v3m->n_hbr - 1;
442         /* hardware watchpoint is inserted from low index to high index */
443         nds32_v3m->next_hwp_index = 0;
444
445         LOG_INFO("%s: total hardware breakpoint %" PRId32 " (simple breakpoint %" PRId32 ")",
446                         target_name(target), nds32_v3m->n_hbr, nds32_v3m->n_hbr - nds32_v3m->n_hwp);
447         LOG_INFO("%s: total hardware watchpoint %" PRId32, target_name(target), nds32_v3m->n_hwp);
448
449         nds32->target->state = TARGET_RUNNING;
450         nds32->target->debug_reason = DBG_REASON_NOTHALTED;
451
452         target_set_examined(target);
453
454         return ERROR_OK;
455 }
456
457 /** Holds methods for NDS32 V3m targets. */
458 struct target_type nds32_v3m_target = {
459         .name = "nds32_v3m",
460
461         .poll = nds32_poll,
462         .arch_state = nds32_arch_state,
463
464         .target_request_data = nds32_v3_target_request_data,
465
466         .halt = nds32_halt,
467         .resume = nds32_resume,
468         .step = nds32_step,
469
470         .assert_reset = nds32_assert_reset,
471         .deassert_reset = nds32_v3m_deassert_reset,
472
473         /* register access */
474         .get_gdb_reg_list = nds32_get_gdb_reg_list,
475
476         /* memory access */
477         .read_buffer = nds32_v3_read_buffer,
478         .write_buffer = nds32_v3_write_buffer,
479         .read_memory = nds32_v3_read_memory,
480         .write_memory = nds32_v3_write_memory,
481
482         .checksum_memory = nds32_v3_checksum_memory,
483
484         /* breakpoint/watchpoint */
485         .add_breakpoint = nds32_v3m_add_breakpoint,
486         .remove_breakpoint = nds32_v3m_remove_breakpoint,
487         .add_watchpoint = nds32_v3m_add_watchpoint,
488         .remove_watchpoint = nds32_v3m_remove_watchpoint,
489         .hit_watchpoint = nds32_v3_hit_watchpoint,
490
491         /* MMU */
492         .mmu = nds32_mmu,
493         .virt2phys = nds32_virtual_to_physical,
494         .read_phys_memory = nds32_read_phys_memory,
495         .write_phys_memory = nds32_write_phys_memory,
496
497         .run_algorithm = nds32_v3_run_algorithm,
498
499         .commands = nds32_command_handlers,
500         .target_create = nds32_v3m_target_create,
501         .init_target = nds32_v3_init_target,
502         .examine = nds32_v3m_examine,
503
504         .get_gdb_fileio_info = nds32_get_gdb_fileio_info,
505         .gdb_fileio_end = nds32_gdb_fileio_end,
506 };