diff options
author | Franck Jullien <franck.jullien@gmail.com> | 2013-08-08 23:45:47 +0200 |
---|---|---|
committer | Spencer Oliver <spen@spen-soft.co.uk> | 2013-09-26 09:52:56 +0000 |
commit | 4e79b48e2c7e535ef21178a69788c15b571c72ff (patch) | |
tree | a3f340d856d4272e3545158ecdc3b32c9a910c73 /src | |
parent | d19fafc8bdb30974e70bfc5a6ce63e7578b6e3b2 (diff) |
Add new target type: OpenRISC
Add support for OpenRISC target. This implementation
supports the adv_debug_sys debug unit core. The mohor
dbg_if is not supported. Support for mohor TAP core
and Altera Virtual JTAG core are also provided.
Change-Id: I3b1cfab1bbb28e497c4fca6ed1bd3a4362609b72
Signed-off-by: Franck Jullien <franck.jullien@gmail.com>
Reviewed-on: http://openocd.zylin.com/1547
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/helper/binarybuffer.c | 21 | ||||
-rw-r--r-- | src/helper/binarybuffer.h | 1 | ||||
-rw-r--r-- | src/target/Makefile.am | 3 | ||||
-rw-r--r-- | src/target/openrisc/Makefile.am | 15 | ||||
-rw-r--r-- | src/target/openrisc/or1k.c | 1472 | ||||
-rw-r--r-- | src/target/openrisc/or1k.h | 159 | ||||
-rw-r--r-- | src/target/openrisc/or1k_du.h | 77 | ||||
-rw-r--r-- | src/target/openrisc/or1k_du_adv.c | 900 | ||||
-rw-r--r-- | src/target/openrisc/or1k_tap.h | 43 | ||||
-rw-r--r-- | src/target/openrisc/or1k_tap_mohor.c | 65 | ||||
-rw-r--r-- | src/target/openrisc/or1k_tap_vjtag.c | 310 | ||||
-rw-r--r-- | src/target/target.c | 2 |
12 files changed, 3068 insertions, 0 deletions
diff --git a/src/helper/binarybuffer.c b/src/helper/binarybuffer.c index 5defcda4..6fe3664a 100644 --- a/src/helper/binarybuffer.c +++ b/src/helper/binarybuffer.c @@ -397,3 +397,24 @@ int hexify(char *hex, const char *bin, int count, int out_maxlen) return cmd_len; } + +void buffer_shr(void *_buf, unsigned buf_len, unsigned count) +{ + unsigned i; + unsigned char *buf = _buf; + unsigned bytes_to_remove; + unsigned shift; + + bytes_to_remove = count / 8; + shift = count - (bytes_to_remove * 8); + + for (i = 0; i < (buf_len - 1); i++) + buf[i] = (buf[i] >> shift) | ((buf[i+1] << (8 - shift)) & 0xff); + + buf[(buf_len - 1)] = buf[(buf_len - 1)] >> shift; + + if (bytes_to_remove) { + memmove(buf, &buf[bytes_to_remove], buf_len - bytes_to_remove); + memset(&buf[buf_len - bytes_to_remove], 0, bytes_to_remove); + } +} diff --git a/src/helper/binarybuffer.h b/src/helper/binarybuffer.h index c2d643b1..5b86c5f4 100644 --- a/src/helper/binarybuffer.h +++ b/src/helper/binarybuffer.h @@ -238,5 +238,6 @@ void bit_copy_discard(struct bit_copy_queue *q); * used in ti-icdi driver and gdb server */ int unhexify(char *bin, const char *hex, int count); int hexify(char *hex, const char *bin, int count, int out_maxlen); +void buffer_shr(void *_buf, unsigned buf_len, unsigned count); #endif /* BINARYBUFFER_H */ diff --git a/src/target/Makefile.am b/src/target/Makefile.am index 027cc8e7..15607536 100644 --- a/src/target/Makefile.am +++ b/src/target/Makefile.am @@ -6,6 +6,9 @@ else OOCD_TRACE_FILES = endif +SUBDIRS = openrisc +libtarget_la_LIBADD = $(top_builddir)/src/target/openrisc/libopenrisc.la + BIN2C = $(top_builddir)/src/helper/bin2char$(EXEEXT_FOR_BUILD) DEBUG_HANDLER = $(srcdir)/xscale/debug_handler.bin diff --git a/src/target/openrisc/Makefile.am b/src/target/openrisc/Makefile.am new file mode 100644 index 00000000..61e47429 --- /dev/null +++ b/src/target/openrisc/Makefile.am @@ -0,0 +1,15 @@ +include $(top_srcdir)/common.mk + +noinst_LTLIBRARIES = libopenrisc.la +libopenrisc_la_SOURCES = $(OPENRISC_SRC) + +OPENRISC_SRC = \ + or1k.c \ + or1k_du_adv.c \ + or1k_tap_mohor.c \ + or1k_tap_vjtag.c + +noinst_HEADERS = \ + or1k.h \ + or1k_du.h \ + or1k_tap.h diff --git a/src/target/openrisc/or1k.c b/src/target/openrisc/or1k.c new file mode 100644 index 00000000..8d8ad409 --- /dev/null +++ b/src/target/openrisc/or1k.c @@ -0,0 +1,1472 @@ +/*************************************************************************** + * Copyright (C) 2011 by Julius Baxter * + * julius@opencores.org * + * * + * Copyright (C) 2013 by Marek Czerski * + * ma.czerski@gmail.com * + * * + * Copyright (C) 2013 by Franck Jullien * + * elec4fun@gmail.com * + * * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <jtag/jtag.h> +#include <target/register.h> +#include <target/target.h> +#include <target/breakpoints.h> +#include <target/target_type.h> +#include <helper/fileio.h> +#include "or1k_tap.h" +#include "or1k.h" +#include "or1k_du.h" + +LIST_HEAD(tap_list); +LIST_HEAD(du_list); + +static int or1k_remove_breakpoint(struct target *target, + struct breakpoint *breakpoint); + +static int or1k_read_core_reg(struct target *target, int num); +static int or1k_write_core_reg(struct target *target, int num); + +static struct or1k_core_reg *or1k_core_reg_list_arch_info; + +struct or1k_core_reg_init or1k_init_reg_list[] = { + {"r0" , GROUP0 + 1024, "org.gnu.gdb.or1k.group0", NULL}, + {"r1" , GROUP0 + 1025, "org.gnu.gdb.or1k.group0", NULL}, + {"r2" , GROUP0 + 1026, "org.gnu.gdb.or1k.group0", NULL}, + {"r3" , GROUP0 + 1027, "org.gnu.gdb.or1k.group0", NULL}, + {"r4" , GROUP0 + 1028, "org.gnu.gdb.or1k.group0", NULL}, + {"r5" , GROUP0 + 1029, "org.gnu.gdb.or1k.group0", NULL}, + {"r6" , GROUP0 + 1030, "org.gnu.gdb.or1k.group0", NULL}, + {"r7" , GROUP0 + 1031, "org.gnu.gdb.or1k.group0", NULL}, + {"r8" , GROUP0 + 1032, "org.gnu.gdb.or1k.group0", NULL}, + {"r9" , GROUP0 + 1033, "org.gnu.gdb.or1k.group0", NULL}, + {"r10" , GROUP0 + 1034, "org.gnu.gdb.or1k.group0", NULL}, + {"r11" , GROUP0 + 1035, "org.gnu.gdb.or1k.group0", NULL}, + {"r12" , GROUP0 + 1036, "org.gnu.gdb.or1k.group0", NULL}, + {"r13" , GROUP0 + 1037, "org.gnu.gdb.or1k.group0", NULL}, + {"r14" , GROUP0 + 1038, "org.gnu.gdb.or1k.group0", NULL}, + {"r15" , GROUP0 + 1039, "org.gnu.gdb.or1k.group0", NULL}, + {"r16" , GROUP0 + 1040, "org.gnu.gdb.or1k.group0", NULL}, + {"r17" , GROUP0 + 1041, "org.gnu.gdb.or1k.group0", NULL}, + {"r18" , GROUP0 + 1042, "org.gnu.gdb.or1k.group0", NULL}, + {"r19" , GROUP0 + 1043, "org.gnu.gdb.or1k.group0", NULL}, + {"r20" , GROUP0 + 1044, "org.gnu.gdb.or1k.group0", NULL}, + {"r21" , GROUP0 + 1045, "org.gnu.gdb.or1k.group0", NULL}, + {"r22" , GROUP0 + 1046, "org.gnu.gdb.or1k.group0", NULL}, + {"r23" , GROUP0 + 1047, "org.gnu.gdb.or1k.group0", NULL}, + {"r24" , GROUP0 + 1048, "org.gnu.gdb.or1k.group0", NULL}, + {"r25" , GROUP0 + 1049, "org.gnu.gdb.or1k.group0", NULL}, + {"r26" , GROUP0 + 1050, "org.gnu.gdb.or1k.group0", NULL}, + {"r27" , GROUP0 + 1051, "org.gnu.gdb.or1k.group0", NULL}, + {"r28" , GROUP0 + 1052, "org.gnu.gdb.or1k.group0", NULL}, + {"r29" , GROUP0 + 1053, "org.gnu.gdb.or1k.group0", NULL}, + {"r30" , GROUP0 + 1054, "org.gnu.gdb.or1k.group0", NULL}, + {"r31" , GROUP0 + 1055, "org.gnu.gdb.or1k.group0", NULL}, + {"ppc" , GROUP0 + 18, "org.gnu.gdb.or1k.group0", NULL}, + {"npc" , GROUP0 + 16, "org.gnu.gdb.or1k.group0", NULL}, + {"sr" , GROUP0 + 17, "org.gnu.gdb.or1k.group0", NULL}, + {"vr" , GROUP0 + 0, "org.gnu.gdb.or1k.group0", "system"}, + {"upr" , GROUP0 + 1, "org.gnu.gdb.or1k.group0", "system"}, + {"cpucfgr" , GROUP0 + 2, "org.gnu.gdb.or1k.group0", "system"}, + {"dmmucfgr" , GROUP0 + 3, "org.gnu.gdb.or1k.group0", "system"}, + {"immucfgr" , GROUP0 + 4, "org.gnu.gdb.or1k.group0", "system"}, + {"dccfgr" , GROUP0 + 5, "org.gnu.gdb.or1k.group0", "system"}, + {"iccfgr" , GROUP0 + 6, "org.gnu.gdb.or1k.group0", "system"}, + {"dcfgr" , GROUP0 + 7, "org.gnu.gdb.or1k.group0", "system"}, + {"pccfgr" , GROUP0 + 8, "org.gnu.gdb.or1k.group0", "system"}, + {"fpcsr" , GROUP0 + 20, "org.gnu.gdb.or1k.group0", "system"}, + {"epcr0" , GROUP0 + 32, "org.gnu.gdb.or1k.group0", "system"}, + {"epcr1" , GROUP0 + 33, "org.gnu.gdb.or1k.group0", "system"}, + {"epcr2" , GROUP0 + 34, "org.gnu.gdb.or1k.group0", "system"}, + {"epcr3" , GROUP0 + 35, "org.gnu.gdb.or1k.group0", "system"}, + {"epcr4" , GROUP0 + 36, "org.gnu.gdb.or1k.group0", "system"}, + {"epcr5" , GROUP0 + 37, "org.gnu.gdb.or1k.group0", "system"}, + {"epcr6" , GROUP0 + 38, "org.gnu.gdb.or1k.group0", "system"}, + {"epcr7" , GROUP0 + 39, "org.gnu.gdb.or1k.group0", "system"}, + {"epcr8" , GROUP0 + 40, "org.gnu.gdb.or1k.group0", "system"}, + {"epcr9" , GROUP0 + 41, "org.gnu.gdb.or1k.group0", "system"}, + {"epcr10" , GROUP0 + 42, "org.gnu.gdb.or1k.group0", "system"}, + {"epcr11" , GROUP0 + 43, "org.gnu.gdb.or1k.group0", "system"}, + {"epcr12" , GROUP0 + 44, "org.gnu.gdb.or1k.group0", "system"}, + {"epcr13" , GROUP0 + 45, "org.gnu.gdb.or1k.group0", "system"}, + {"epcr14" , GROUP0 + 46, "org.gnu.gdb.or1k.group0", "system"}, + {"epcr15" , GROUP0 + 47, "org.gnu.gdb.or1k.group0", "system"}, + {"eear0" , GROUP0 + 48, "org.gnu.gdb.or1k.group0", "system"}, + {"eear1" , GROUP0 + 49, "org.gnu.gdb.or1k.group0", "system"}, + {"eear2" , GROUP0 + 50, "org.gnu.gdb.or1k.group0", "system"}, + {"eear3" , GROUP0 + 51, "org.gnu.gdb.or1k.group0", "system"}, + {"eear4" , GROUP0 + 52, "org.gnu.gdb.or1k.group0", "system"}, + {"eear5" , GROUP0 + 53, "org.gnu.gdb.or1k.group0", "system"}, + {"eear6" , GROUP0 + 54, "org.gnu.gdb.or1k.group0", "system"}, + {"eear7" , GROUP0 + 55, "org.gnu.gdb.or1k.group0", "system"}, + {"eear8" , GROUP0 + 56, "org.gnu.gdb.or1k.group0", "system"}, + {"eear9" , GROUP0 + 57, "org.gnu.gdb.or1k.group0", "system"}, + {"eear10" , GROUP0 + 58, "org.gnu.gdb.or1k.group0", "system"}, + {"eear11" , GROUP0 + 59, "org.gnu.gdb.or1k.group0", "system"}, + {"eear12" , GROUP0 + 60, "org.gnu.gdb.or1k.group0", "system"}, + {"eear13" , GROUP0 + 61, "org.gnu.gdb.or1k.group0", "system"}, + {"eear14" , GROUP0 + 62, "org.gnu.gdb.or1k.group0", "system"}, + {"eear15" , GROUP0 + 63, "org.gnu.gdb.or1k.group0", "system"}, + {"esr0" , GROUP0 + 64, "org.gnu.gdb.or1k.group0", "system"}, + {"esr1" , GROUP0 + 65, "org.gnu.gdb.or1k.group0", "system"}, + {"esr2" , GROUP0 + 66, "org.gnu.gdb.or1k.group0", "system"}, + {"esr3" , GROUP0 + 67, "org.gnu.gdb.or1k.group0", "system"}, + {"esr4" , GROUP0 + 68, "org.gnu.gdb.or1k.group0", "system"}, + {"esr5" , GROUP0 + 69, "org.gnu.gdb.or1k.group0", "system"}, + {"esr6" , GROUP0 + 70, "org.gnu.gdb.or1k.group0", "system"}, + {"esr7" , GROUP0 + 71, "org.gnu.gdb.or1k.group0", "system"}, + {"esr8" , GROUP0 + 72, "org.gnu.gdb.or1k.group0", "system"}, + {"esr9" , GROUP0 + 73, "org.gnu.gdb.or1k.group0", "system"}, + {"esr10" , GROUP0 + 74, "org.gnu.gdb.or1k.group0", "system"}, + {"esr11" , GROUP0 + 75, "org.gnu.gdb.or1k.group0", "system"}, + {"esr12" , GROUP0 + 76, "org.gnu.gdb.or1k.group0", "system"}, + {"esr13" , GROUP0 + 77, "org.gnu.gdb.or1k.group0", "system"}, + {"esr14" , GROUP0 + 78, "org.gnu.gdb.or1k.group0", "system"}, + {"esr15" , GROUP0 + 79, "org.gnu.gdb.or1k.group0", "system"}, + + {"dmmuucr" , GROUP1 + 0, "org.gnu.gdb.or1k.group1", "dmmu"}, + {"dmmuupr" , GROUP1 + 1, "org.gnu.gdb.or1k.group1", "dmmu"}, + {"dtlbeir" , GROUP1 + 2, "org.gnu.gdb.or1k.group1", "dmmu"}, + {"datbmr0" , GROUP1 + 4, "org.gnu.gdb.or1k.group1", "dmmu"}, + {"datbmr1" , GROUP1 + 5, "org.gnu.gdb.or1k.group1", "dmmu"}, + {"datbmr2" , GROUP1 + 6, "org.gnu.gdb.or1k.group1", "dmmu"}, + {"datbmr3" , GROUP1 + 7, "org.gnu.gdb.or1k.group1", "dmmu"}, + {"datbtr0" , GROUP1 + 8, "org.gnu.gdb.or1k.group1", "dmmu"}, + {"datbtr1" , GROUP1 + 9, "org.gnu.gdb.or1k.group1", "dmmu"}, + {"datbtr2" , GROUP1 + 10, "org.gnu.gdb.or1k.group1", "dmmu"}, + {"datbtr3" , GROUP1 + 11, "org.gnu.gdb.or1k.group1", "dmmu"}, + + {"immucr" , GROUP2 + 0, "org.gnu.gdb.or1k.group2", "immu"}, + {"immupr" , GROUP2 + 1, "org.gnu.gdb.or1k.group2", "immu"}, + {"itlbeir" , GROUP2 + 2, "org.gnu.gdb.or1k.group2", "immu"}, + {"iatbmr0" , GROUP2 + 4, "org.gnu.gdb.or1k.group2", "immu"}, + {"iatbmr1" , GROUP2 + 5, "org.gnu.gdb.or1k.group2", "immu"}, + {"iatbmr2" , GROUP2 + 6, "org.gnu.gdb.or1k.group2", "immu"}, + {"iatbmr3" , GROUP2 + 7, "org.gnu.gdb.or1k.group2", "immu"}, + {"iatbtr0" , GROUP2 + 8, "org.gnu.gdb.or1k.group2", "immu"}, + {"iatbtr1" , GROUP2 + 9, "org.gnu.gdb.or1k.group2", "immu"}, + {"iatbtr2" , GROUP2 + 10, "org.gnu.gdb.or1k.group2", "immu"}, + {"iatbtr3" , GROUP2 + 11, "org.gnu.gdb.or1k.group2", "immu"}, + + {"dccr" , GROUP3 + 0, "org.gnu.gdb.or1k.group3", "dcache"}, + {"dcbpr" , GROUP3 + 1, "org.gnu.gdb.or1k.group3", "dcache"}, + {"dcbfr" , GROUP3 + 2, "org.gnu.gdb.or1k.group3", "dcache"}, + {"dcbir" , GROUP3 + 3, "org.gnu.gdb.or1k.group3", "dcache"}, + {"dcbwr" , GROUP3 + 4, "org.gnu.gdb.or1k.group3", "dcache"}, + {"dcblr" , GROUP3 + 5, "org.gnu.gdb.or1k.group3", "dcache"}, + + {"iccr" , GROUP4 + 0, "org.gnu.gdb.or1k.group4", "icache"}, + {"icbpr" , GROUP4 + 1, "org.gnu.gdb.or1k.group4", "icache"}, + {"icbir" , GROUP4 + 2, "org.gnu.gdb.or1k.group4", "icache"}, + {"icblr" , GROUP4 + 3, "org.gnu.gdb.or1k.group4", "icache"}, + + {"maclo" , GROUP5 + 0, "org.gnu.gdb.or1k.group5", "mac"}, + {"machi" , GROUP5 + 1, "org.gnu.gdb.or1k.group5", "mac"}, + + {"dvr0" , GROUP6 + 0, "org.gnu.gdb.or1k.group6", "debug"}, + {"dvr1" , GROUP6 + 1, "org.gnu.gdb.or1k.group6", "debug"}, + {"dvr2" , GROUP6 + 2, "org.gnu.gdb.or1k.group6", "debug"}, + {"dvr3" , GROUP6 + 3, "org.gnu.gdb.or1k.group6", "debug"}, + {"dvr4" , GROUP6 + 4, "org.gnu.gdb.or1k.group6", "debug"}, + {"dvr5" , GROUP6 + 5, "org.gnu.gdb.or1k.group6", "debug"}, + {"dvr6" , GROUP6 + 6, "org.gnu.gdb.or1k.group6", "debug"}, + {"dvr7" , GROUP6 + 7, "org.gnu.gdb.or1k.group6", "debug"}, + {"dcr0" , GROUP6 + 8, "org.gnu.gdb.or1k.group6", "debug"}, + {"dcr1" , GROUP6 + 9, "org.gnu.gdb.or1k.group6", "debug"}, + {"dcr2" , GROUP6 + 10, "org.gnu.gdb.or1k.group6", "debug"}, + {"dcr3" , GROUP6 + 11, "org.gnu.gdb.or1k.group6", "debug"}, + {"dcr4" , GROUP6 + 12, "org.gnu.gdb.or1k.group6", "debug"}, + {"dcr5" , GROUP6 + 13, "org.gnu.gdb.or1k.group6", "debug"}, + {"dcr6" , GROUP6 + 14, "org.gnu.gdb.or1k.group6", "debug"}, + {"dcr7" , GROUP6 + 15, "org.gnu.gdb.or1k.group6", "debug"}, + {"dmr1" , GROUP6 + 16, "org.gnu.gdb.or1k.group6", "debug"}, + {"dmr2" , GROUP6 + 17, "org.gnu.gdb.or1k.group6", "debug"}, + {"dcwr0" , GROUP6 + 18, "org.gnu.gdb.or1k.group6", "debug"}, + {"dcwr1" , GROUP6 + 19, "org.gnu.gdb.or1k.group6", "debug"}, + {"dsr" , GROUP6 + 20, "org.gnu.gdb.or1k.group6", "debug"}, + {"drr" , GROUP6 + 21, "org.gnu.gdb.or1k.group6", "debug"}, + + {"pccr0" , GROUP7 + 0, "org.gnu.gdb.or1k.group7", "perf"}, + {"pccr1" , GROUP7 + 1, "org.gnu.gdb.or1k.group7", "perf"}, + {"pccr2" , GROUP7 + 2, "org.gnu.gdb.or1k.group7", "perf"}, + {"pccr3" , GROUP7 + 3, "org.gnu.gdb.or1k.group7", "perf"}, + {"pccr4" , GROUP7 + 4, "org.gnu.gdb.or1k.group7", "perf"}, + {"pccr5" , GROUP7 + 5, "org.gnu.gdb.or1k.group7", "perf"}, + {"pccr6" , GROUP7 + 6, "org.gnu.gdb.or1k.group7", "perf"}, + {"pccr7" , GROUP7 + 7, "org.gnu.gdb.or1k.group7", "perf"}, + {"pcmr0" , GROUP7 + 8, "org.gnu.gdb.or1k.group7", "perf"}, + {"pcmr1" , GROUP7 + 9, "org.gnu.gdb.or1k.group7", "perf"}, + {"pcmr2" , GROUP7 + 10, "org.gnu.gdb.or1k.group7", "perf"}, + {"pcmr3" , GROUP7 + 11, "org.gnu.gdb.or1k.group7", "perf"}, + {"pcmr4" , GROUP7 + 12, "org.gnu.gdb.or1k.group7", "perf"}, + {"pcmr5" , GROUP7 + 13, "org.gnu.gdb.or1k.group7", "perf"}, + {"pcmr6" , GROUP7 + 14, "org.gnu.gdb.or1k.group7", "perf"}, + {"pcmr7" , GROUP7 + 15, "org.gnu.gdb.or1k.group7", "perf"}, + + {"pmr" , GROUP8 + 0, "org.gnu.gdb.or1k.group8", "power"}, + + {"picmr" , GROUP9 + 0, "org.gnu.gdb.or1k.group9", "pic"}, + {"picsr" , GROUP9 + 2, "org.gnu.gdb.or1k.group9", "pic"}, + + {"ttmr" , GROUP10 + 0, "org.gnu.gdb.or1k.group10", "timer"}, + {"ttcr" , GROUP10 + 1, "org.gnu.gdb.or1k.group10", "timer"}, +}; + +static int or1k_add_reg(struct target *target, struct or1k_core_reg *new_reg) +{ + struct or1k_common *or1k = target_to_or1k(target); + int reg_list_size = or1k->nb_regs * sizeof(struct or1k_core_reg); + + or1k_core_reg_list_arch_info = realloc(or1k_core_reg_list_arch_info, + reg_list_size + sizeof(struct or1k_core_reg)); + + memcpy(&or1k_core_reg_list_arch_info[or1k->nb_regs], new_reg, + sizeof(struct or1k_core_reg)); + + or1k_core_reg_list_arch_info[or1k->nb_regs].list_num = or1k->nb_regs; + + or1k->nb_regs++; + + return ERROR_OK; +} + +static int or1k_create_reg_list(struct target *target) +{ + struct or1k_common *or1k = target_to_or1k(target); + + LOG_DEBUG("-"); + + or1k_core_reg_list_arch_info = malloc(ARRAY_SIZE(or1k_init_reg_list) * + sizeof(struct or1k_core_reg)); + + for (int i = 0; i < (int)ARRAY_SIZE(or1k_init_reg_list); i++) { + or1k_core_reg_list_arch_info[i].name = or1k_init_reg_list[i].name; + or1k_core_reg_list_arch_info[i].spr_num = or1k_init_reg_list[i].spr_num; + or1k_core_reg_list_arch_info[i].group = or1k_init_reg_list[i].group; + or1k_core_reg_list_arch_info[i].feature = or1k_init_reg_list[i].feature; + or1k_core_reg_list_arch_info[i].list_num = i; + or1k_core_reg_list_arch_info[i].target = NULL; + or1k_core_reg_list_arch_info[i].or1k_common = NULL; + } + + or1k->nb_regs = ARRAY_SIZE(or1k_init_reg_list); + + struct or1k_core_reg new_reg; + new_reg.target = NULL; + new_reg.or1k_common = NULL; + + char name[32]; + for (int way = 0; way < 4; way++) { + for (int i = 0; i < 128; i++) { + + sprintf(name, "dtlbw%dmr%d", way, i); + new_reg.name = strdup(name); + new_reg.spr_num = GROUP1 + 512 + i + (way * 256); + new_reg.feature = "org.gnu.gdb.or1k.group1"; + new_reg.group = "dmmu"; + or1k_add_reg(target, &new_reg); + + sprintf(name, "dtlbw%dtr%d", way, i); + new_reg.name = strdup(name); + new_reg.spr_num = GROUP1 + 640 + i + (way * 256); + new_reg.feature = "org.gnu.gdb.or1k.group1"; + new_reg.group = "dmmu"; + or1k_add_reg(target, &new_reg); + + + sprintf(name, "itlbw%dmr%d", way, i); + new_reg.name = strdup(name); + new_reg.spr_num = GROUP2 + 512 + i + (way * 256); + new_reg.feature = "org.gnu.gdb.or1k.group2"; + new_reg.group = "immu"; + or1k_add_reg(target, &new_reg); + + + sprintf(name, "itlbw%dtr%d", way, i); + new_reg.name = strdup(name); + new_reg.spr_num = GROUP2 + 640 + i + (way * 256); + new_reg.feature = "org.gnu.gdb.or1k.group2"; + new_reg.group = "immu"; + or1k_add_reg(target, &new_reg); + + } + } + + return ERROR_OK; +} + +static int or1k_jtag_read_regs(struct or1k_common *or1k, uint32_t *regs) +{ + struct or1k_du *du_core = or1k_jtag_to_du(&or1k->jtag); + + LOG_DEBUG("-"); + + return du_core->or1k_jtag_read_cpu(&or1k->jtag, + or1k->arch_info[OR1K_REG_R0].spr_num, OR1K_REG_R31 + 1, + regs + OR1K_REG_R0); +} + +static int or1k_jtag_write_regs(struct or1k_common *or1k, uint32_t *regs) +{ + struct or1k_du *du_core = or1k_jtag_to_du(&or1k->jtag); + + LOG_DEBUG("-"); + + return du_core->or1k_jtag_write_cpu(&or1k->jtag, + or1k->arch_info[OR1K_REG_R0].spr_num, OR1K_REG_R31 + 1, + ®s[OR1K_REG_R0]); +} + +static int or1k_save_context(struct target *target) +{ + struct or1k_common *or1k = target_to_or1k(target); + struct or1k_du *du_core = or1k_to_du(or1k); + int regs_read = 0; + int retval; + + LOG_DEBUG("-"); + + for (int i = 0; i < OR1KNUMCOREREGS; i++) { + if (!or1k->core_cache->reg_list[i].valid) { + if (i == OR1K_REG_PPC || i == OR1K_REG_NPC || i == OR1K_REG_SR) { + retval = du_core->or1k_jtag_read_cpu(&or1k->jtag, + or1k->arch_info[i].spr_num, 1, + &or1k->core_regs[i]); + if (retval != ERROR_OK) + return retval; + } else if (!regs_read) { + /* read gpr registers at once (but only one time in this loop) */ + retval = or1k_jtag_read_regs(or1k, or1k->core_regs); + if (retval != ERROR_OK) + return retval; + /* prevent next reads in this loop */ + regs_read = 1; + } + /* We've just updated the core_reg[i], now update + the core cache */ + or1k_read_core_reg(target, i); + } + } + + return ERROR_OK; +} + +static int or1k_restore_context(struct target *target) +{ + struct or1k_common *or1k = target_to_or1k(target); + struct or1k_du *du_core = or1k_to_du(or1k); + int reg_write = 0; + int retval; + + LOG_DEBUG("-"); + + for (int i = 0; i < OR1KNUMCOREREGS; i++) { + if (or1k->core_cache->reg_list[i].dirty) { + or1k_write_core_reg(target, i); + + if (i == OR1K_REG_PPC || i == OR1K_REG_NPC || i == OR1K_REG_SR) { + retval = du_core->or1k_jtag_write_cpu(&or1k->jtag, + or1k->arch_info[i].spr_num, 1, + &or1k->core_regs[i]); + if (retval != ERROR_OK) { + LOG_ERROR("Error while restoring context"); + return retval; + } + } else + reg_write = 1; + } + } + + if (reg_write) { + /* read gpr registers at once (but only one time in this loop) */ + retval = or1k_jtag_write_regs(or1k, or1k->core_regs); + if (retval != ERROR_OK) { + LOG_ERROR("Error while restoring context"); + return retval; + } + } + + return ERROR_OK; +} + +static int or1k_read_core_reg(struct target *target, int num) +{ + struct or1k_common *or1k = target_to_or1k(target); + struct or1k_du *du_core = or1k_to_du(or1k); + uint32_t reg_value; + + LOG_DEBUG("-"); + + if ((num < 0) || (num >= or1k->nb_regs)) + return ERROR_COMMAND_SYNTAX_ERROR; + + if ((num >= 0) && (num < OR1KNUMCOREREGS)) { + reg_value = or1k->core_regs[num]; + buf_set_u32(or1k->core_cache->reg_list[num].value, 0, 32, reg_value); + LOG_DEBUG("Read core reg %i value 0x%08x", num , reg_value); + or1k->core_cache->reg_list[num].valid = 1; + or1k->core_cache->reg_list[num].dirty = 0; + } else { + /* This is an spr, always read value from HW */ + int retval = du_core->or1k_jtag_read_cpu(&or1k->jtag, + or1k->arch_info[num].spr_num, 1, ®_value); + if (retval != ERROR_OK) { + LOG_ERROR("Error while reading spr 0x%08x", or1k->arch_info[num].spr_num); + return retval; + } + buf_set_u32(or1k->core_cache->reg_list[num].value, 0, 32, reg_value); + LOG_DEBUG("Read spr reg %i value 0x%08x", num , reg_value); + } + + return ERROR_OK; +} + +static int or1k_write_core_reg(struct target *target, int num) +{ + struct or1k_common *or1k = target_to_or1k(target); + + LOG_DEBUG("-"); + + if ((num < 0) || (num >= OR1KNUMCOREREGS)) + return ERROR_COMMAND_SYNTAX_ERROR; + + uint32_t reg_value = buf_get_u32(or1k->core_cache->reg_list[num].value, 0, 32); + or1k->core_regs[num] = reg_value; + LOG_DEBUG("Write core reg %i value 0x%08x", num , reg_value); + or1k->core_cache->reg_list[num].valid = 1; + or1k->core_cache->reg_list[num].dirty = 0; + + return ERROR_OK; +} + +static int or1k_get_core_reg(struct reg *reg) +{ + struct or1k_core_reg *or1k_reg = reg->arch_info; + struct target *target = or1k_reg->target; + + LOG_DEBUG("-"); + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + return or1k_read_core_reg(target, or1k_reg->list_num); +} + +static int or1k_set_core_reg(struct reg *reg, uint8_t *buf) +{ + struct or1k_core_reg *or1k_reg = reg->arch_info; + struct target *target = or1k_reg->target; + struct or1k_common *or1k = target_to_or1k(target); + struct or1k_du *du_core = or1k_to_du(or1k); + uint32_t value = buf_get_u32(buf, 0, 32); + + LOG_DEBUG("-"); + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + if (or1k_reg->list_num < OR1KNUMCOREREGS) { + buf_set_u32(reg->value, 0, 32, value); + reg->dirty = 1; + reg->valid = 1; + } else { + /* This is an spr, write it to the HW */ + int retval = du_core->or1k_jtag_write_cpu(&or1k->jtag, + or1k_reg->spr_num, 1, &value); + if (retval != ERROR_OK) { + LOG_ERROR("Error while writing spr 0x%08x", or1k_reg->spr_num); + return retval; + } + } + + return ERROR_OK; +} + +static const struct reg_arch_type or1k_reg_type = { + .get = or1k_get_core_reg, + .set = or1k_set_core_reg, +}; + +static struct reg_cache *or1k_build_reg_cache(struct target *target) +{ + struct or1k_common *or1k = target_to_or1k(target); + struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); + struct reg_cache *cache = malloc(sizeof(struct reg_cache)); + struct reg *reg_list = malloc((or1k->nb_regs) * sizeof(struct reg)); + struct or1k_core_reg *arch_info = + malloc((or1k->nb_regs) * sizeof(struct or1k_core_reg)); + struct reg_feature *feature; + + LOG_DEBUG("-"); + + /* Build the process context cache */ + cache->name = "OpenRISC 1000 registers"; + cache->next = NULL; + cache->reg_list = reg_list; + cache->num_regs = or1k->nb_regs; + (*cache_p) = cache; + or1k->core_cache = cache; + or1k->arch_info = arch_info; + + for (int i = 0; i < or1k->nb_regs; i++) { + arch_info[i] = or1k_core_reg_list_arch_info[i]; + arch_info[i].target = target; + arch_info[i].or1k_common = or1k; + reg_list[i].name = or1k_core_reg_list_arch_info[i].name; + + feature = malloc(sizeof(struct reg_feature)); + feature->name = or1k_core_reg_list_arch_info[i].feature; + reg_list[i].feature = feature; + + reg_list[i].group = or1k_core_reg_list_arch_info[i].group; + reg_list[i].size = 32; + reg_list[i].value = calloc(1, 4); + reg_list[i].dirty = 0; + reg_list[i].valid = 0; + reg_list[i].type = &or1k_reg_type; + reg_list[i].arch_info = &arch_info[i]; + reg_list[i].number = i; + reg_list[i].exist = true; + } + + return cache; +} + +static int or1k_debug_entry(struct target *target) +{ + LOG_DEBUG("-"); + + int retval = or1k_save_context(target); + if (retval != ERROR_OK) { + LOG_ERROR("Error while calling or1k_save_context"); + return retval; + } + + struct or1k_common *or1k = target_to_or1k(target); + uint32_t addr = or1k->core_regs[OR1K_REG_NPC]; + + if (breakpoint_find(target, addr)) + /* Halted on a breakpoint, step back to permit executing the instruction there */ + retval = or1k_set_core_reg(&or1k->core_cache->reg_list[OR1K_REG_NPC], + (uint8_t *)&addr); + + return retval; +} + +static int or1k_halt(struct target *target) +{ + struct or1k_common *or1k = target_to_or1k(target); + struct or1k_du *du_core = or1k_to_du(or1k); + + LOG_DEBUG("target->state: %s", + target_state_name(target)); + + if (target->state == TARGET_HALTED) { + LOG_DEBUG("Target was already halted"); + return ERROR_OK; + } + + if (target->state == TARGET_UNKNOWN) + LOG_WARNING("Target was in unknown state when halt was requested"); + + if (target->state == TARGET_RESET) { + if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) && + jtag_get_srst()) { + LOG_ERROR("Can't request a halt while in reset if nSRST pulls nTRST"); + return ERROR_TARGET_FAILURE; + } else { + target->debug_reason = DBG_REASON_DBGRQ; + return ERROR_OK; + } + } + + int retval = du_core->or1k_cpu_stall(&or1k->jtag, CPU_STALL); + if (retval != ERROR_OK) { + LOG_ERROR("Impossible to stall the CPU"); + return retval; + } + + target->debug_reason = DBG_REASON_DBGRQ; + + return ERROR_OK; +} + +static int or1k_is_cpu_running(struct target *target, int *running) +{ + struct or1k_common *or1k = target_to_or1k(target); + struct or1k_du *du_core = or1k_to_du(or1k); + int retval; + int tries = 0; + const int RETRIES_MAX = 5; + + /* Have a retry loop to determine of the CPU is running. + If target has been hard reset for any reason, it might take a couple + of goes before it's ready again. + */ + while (tries < RETRIES_MAX) { + + tries++; + + retval = du_core->or1k_is_cpu_running(&or1k->jtag, running); + if (retval != ERROR_OK) { + LOG_WARNING("Debug IF CPU control reg read failure."); + /* Try once to restart the JTAG infrastructure - + quite possibly the board has just been reset. */ + LOG_WARNING("Resetting JTAG TAP state and reconnectiong to debug IF."); + du_core->or1k_jtag_init(&or1k->jtag); + + LOG_WARNING("...attempt %d of %d", tries, RETRIES_MAX); + + alive_sleep(2); + + continue; + } else + return ERROR_OK; + } + + LOG_ERROR("Could not re-establish communication with target"); + return retval; +} + +static int or1k_poll(struct target *target) +{ + int retval; + int running; + + retval = or1k_is_cpu_running(target, &running); + if (retval != ERROR_OK) { + LOG_ERROR("Error while calling or1k_is_cpu_running"); + return retval; + } + + /* check for processor halted */ + if (!running) { + /* It's actually stalled, so update our software's state */ + if ((target->state == TARGET_RUNNING) || + (target->state == TARGET_RESET)) { + + target->state = TARGET_HALTED; + + retval = or1k_debug_entry(target); + if (retval != ERROR_OK) { + LOG_ERROR("Error while calling or1k_debug_entry"); + return retval; + } + + target_call_event_callbacks(target, + TARGET_EVENT_HALTED); + } else if (target->state == TARGET_DEBUG_RUNNING) { + target->state = TARGET_HALTED; + + retval = or1k_debug_entry(target); + if (retval != ERROR_OK) { + LOG_ERROR("Error while calling or1k_debug_entry"); + return retval; + } + + target_call_event_callbacks(target, + TARGET_EVENT_DEBUG_HALTED); + } + } else { /* ... target is running */ + + /* If target was supposed to be stalled, stall it again */ + if (target->state == TARGET_HALTED) { + + target->state = TARGET_RUNNING; + + retval = or1k_halt(target); + if (retval != ERROR_OK) { + LOG_ERROR("Error while calling or1k_halt"); + return retval; + } + + retval = or1k_debug_entry(target); + if (retval != ERROR_OK) { + LOG_ERROR("Error while calling or1k_debug_entry"); + return retval; + } + + target_call_event_callbacks(target, + TARGET_EVENT_DEBUG_HALTED); + } + + target->state = TARGET_RUNNING; + + } + + return ERROR_OK; +} + +static int or1k_assert_reset(struct target *target) +{ + struct or1k_common *or1k = target_to_or1k(target); + struct or1k_du *du_core = or1k_to_du(or1k); + + LOG_DEBUG("-"); + + int retval = du_core->or1k_cpu_reset(&or1k->jtag, CPU_RESET); + if (retval != ERROR_OK) { + LOG_ERROR("Error while asserting RESET"); + return retval; + } + + return ERROR_OK; +} + +static int or1k_deassert_reset(struct target *target) +{ + struct or1k_common *or1k = target_to_or1k(target); + struct or1k_du *du_core = or1k_to_du(or1k); + + LOG_DEBUG("-"); + + int retval = du_core->or1k_cpu_reset(&or1k->jtag, CPU_NOT_RESET); + if (retval != ERROR_OK) { + LOG_ERROR("Error while desasserting RESET"); + return retval; + } + + return ERROR_OK; +} + +static int or1k_soft_reset_halt(struct target *target) +{ + struct or1k_common *or1k = target_to_or1k(target); + struct or1k_du *du_core = or1k_to_du(or1k); + + LOG_DEBUG("-"); + + int retval = du_core->or1k_cpu_stall(&or1k->jtag, CPU_STALL); + if (retval != ERROR_OK) { + LOG_ERROR("Error while stalling the CPU"); + return retval; + } + + retval = or1k_assert_reset(target); + if (retval != ERROR_OK) + return retval; + + retval = or1k_deassert_reset(target); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + +static bool is_any_soft_breakpoint(struct target *target) +{ + struct breakpoint *breakpoint = target->breakpoints; + + LOG_DEBUG("-"); + + while (breakpoint) + if (breakpoint->type == BKPT_SOFT) + return true; + + return false; +} + +static int or1k_resume_or_step(struct target *target, int current, + uint32_t address, int handle_breakpoints, + int debug_execution, int step) +{ + struct or1k_common *or1k = target_to_or1k(target); + struct or1k_du *du_core = or1k_to_du(or1k); + struct breakpoint *breakpoint = NULL; + uint32_t resume_pc; + uint32_t debug_reg_list[OR1K_DEBUG_REG_NUM]; + + LOG_DEBUG("Addr: 0x%x, stepping: %s, handle breakpoints %s\n", + address, step ? "yes" : "no", handle_breakpoints ? "yes" : "no"); + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!debug_execution) + target_free_all_working_areas(target); + + /* current ? continue on current pc : continue at <address> */ + if (!current) + buf_set_u32(or1k->core_cache->reg_list[OR1K_REG_NPC].value, 0, + 32, address); + + int retval = or1k_restore_context(targe |