aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFranck Jullien <franck.jullien@gmail.com>2013-08-08 23:45:47 +0200
committerSpencer Oliver <spen@spen-soft.co.uk>2013-09-26 09:52:56 +0000
commit4e79b48e2c7e535ef21178a69788c15b571c72ff (patch)
treea3f340d856d4272e3545158ecdc3b32c9a910c73 /src
parentd19fafc8bdb30974e70bfc5a6ce63e7578b6e3b2 (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.c21
-rw-r--r--src/helper/binarybuffer.h1
-rw-r--r--src/target/Makefile.am3
-rw-r--r--src/target/openrisc/Makefile.am15
-rw-r--r--src/target/openrisc/or1k.c1472
-rw-r--r--src/target/openrisc/or1k.h159
-rw-r--r--src/target/openrisc/or1k_du.h77
-rw-r--r--src/target/openrisc/or1k_du_adv.c900
-rw-r--r--src/target/openrisc/or1k_tap.h43
-rw-r--r--src/target/openrisc/or1k_tap_mohor.c65
-rw-r--r--src/target/openrisc/or1k_tap_vjtag.c310
-rw-r--r--src/target/target.c2
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,
+ &regs[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, &reg_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