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