aboutsummaryrefslogtreecommitdiff
path: root/src/target/openrisc
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/target/openrisc
parentd19fafc8bdb30974e70bfc5a6ce63e7578b6e3b2 (diff)
downloadriscv-openocd-4e79b48e2c7e535ef21178a69788c15b571c72ff.zip
riscv-openocd-4e79b48e2c7e535ef21178a69788c15b571c72ff.tar.gz
riscv-openocd-4e79b48e2c7e535ef21178a69788c15b571c72ff.tar.bz2
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/target/openrisc')
-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
8 files changed, 3041 insertions, 0 deletions
diff --git a/src/target/openrisc/Makefile.am b/src/target/openrisc/Makefile.am
new file mode 100644
index 0000000..61e4742
--- /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 0000000..8d8ad40
--- /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(target);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Error while calling or1k_restore_context");
+ return retval;
+ }
+
+ /* read debug registers (starting from DMR1 register) */
+ retval = du_core->or1k_jtag_read_cpu(&or1k->jtag, OR1K_DMR1_CPU_REG_ADD,
+ OR1K_DEBUG_REG_NUM, debug_reg_list);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Error while reading debug registers");
+ return retval;
+ }
+
+ /* Clear Debug Reason Register (DRR) */
+ debug_reg_list[OR1K_DEBUG_REG_DRR] = 0;
+
+ /* Clear watchpoint break generation in Debug Mode Register 2 (DMR2) */
+ debug_reg_list[OR1K_DEBUG_REG_DMR2] &= ~OR1K_DMR2_WGB;
+ if (step)
+ /* Set the single step trigger in Debug Mode Register 1 (DMR1) */
+ debug_reg_list[OR1K_DEBUG_REG_DMR1] |= OR1K_DMR1_ST | OR1K_DMR1_BT;
+ else
+ /* Clear the single step trigger in Debug Mode Register 1 (DMR1) */
+ debug_reg_list[OR1K_DEBUG_REG_DMR1] &= ~(OR1K_DMR1_ST | OR1K_DMR1_BT);
+
+ /* Set traps to be handled by the debug unit in the Debug Stop
+ Register (DSR). Check if we have any software breakpoints in
+ place before setting this value - the kernel, for instance,
+ relies on l.trap instructions not stalling the processor ! */
+ if (is_any_soft_breakpoint(target) == true)
+ debug_reg_list[OR1K_DEBUG_REG_DSR] |= OR1K_DSR_TE;
+
+ /* Write debug registers (starting from DMR1 register) */
+ retval = du_core->or1k_jtag_write_cpu(&or1k->jtag, OR1K_DMR1_CPU_REG_ADD,
+ OR1K_DEBUG_REG_NUM, debug_reg_list);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Error while writing back debug registers");
+ return retval;
+ }
+
+ resume_pc = buf_get_u32(or1k->core_cache->reg_list[OR1K_REG_NPC].value,
+ 0, 32);
+
+ /* The front-end may request us not to handle breakpoints */
+ if (handle_breakpoints) {
+ /* Single step past breakpoint at current address */
+ breakpoint = breakpoint_find(target, resume_pc);
+ if (breakpoint) {
+ LOG_DEBUG("Unset breakpoint at 0x%08x", breakpoint->address);
+ retval = or1k_remove_breakpoint(target, breakpoint);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+ }
+
+ /* Unstall time */
+ retval = du_core->or1k_cpu_stall(&or1k->jtag, CPU_UNSTALL);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Error while unstalling the CPU");
+ return retval;
+ }
+
+ if (step)
+ target->debug_reason = DBG_REASON_SINGLESTEP;
+ else
+ target->debug_reason = DBG_REASON_NOTHALTED;
+
+ /* Registers are now invalid */
+ register_cache_invalidate(or1k->core_cache);
+
+ if (!debug_execution) {
+ target->state = TARGET_RUNNING;
+ target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
+ LOG_DEBUG("Target resumed at 0x%08x", resume_pc);
+ } else {
+ target->state = TARGET_DEBUG_RUNNING;
+ target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED);
+ LOG_DEBUG("Target debug resumed at 0x%08x", resume_pc);
+ }
+
+ return ERROR_OK;
+}
+
+static int or1k_resume(struct target *target, int current,
+ uint32_t address, int handle_breakpoints, int debug_execution)
+{
+ return or1k_resume_or_step(target, current, address,
+ handle_breakpoints,
+ debug_execution,
+ NO_SINGLE_STEP);
+}
+
+static int or1k_step(struct target *target, int current,
+ uint32_t address, int handle_breakpoints)
+{
+ return or1k_resume_or_step(target, current, address,
+ handle_breakpoints,
+ 0,
+ SINGLE_STEP);
+
+}
+
+static int or1k_add_breakpoint(struct target *target,
+ struct breakpoint *breakpoint)
+{
+ struct or1k_common *or1k = target_to_or1k(target);
+ struct or1k_du *du_core = or1k_to_du(or1k);
+ uint8_t data;
+
+ LOG_DEBUG("Adding breakpoint: addr 0x%08x, len %d, type %d, set: %d, id: %d",
+ breakpoint->address, breakpoint->length, breakpoint->type,
+ breakpoint->set, breakpoint->unique_id);
+
+ /* Only support SW breakpoints for now. */
+ if (breakpoint->type == BKPT_HARD)
+ LOG_ERROR("HW breakpoints not supported for now. Doing SW breakpoint.");
+
+ /* Read and save the instruction */
+ int retval = du_core->or1k_jtag_read_memory(&or1k->jtag,
+ breakpoint->address,
+ 4,
+ 1,
+ &data);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Error while reading the instruction at 0x%08x",
+ breakpoint->address);
+ return retval;
+ }
+
+ if (breakpoint->orig_instr != NULL)
+ free(breakpoint->orig_instr);
+
+ breakpoint->orig_instr = malloc(breakpoint->length);
+ memcpy(breakpoint->orig_instr, &data, breakpoint->length);
+
+ /* Sub in the OR1K trap instruction */
+ uint32_t or1k_trap_insn = OR1K_TRAP_INSTR;
+ retval = du_core->or1k_jtag_write_memory(&or1k->jtag,
+ breakpoint->address,
+ 4,
+ 1,
+ (uint8_t *)&or1k_trap_insn);
+
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Error while writing OR1K_TRAP_INSTR at 0x%08x",
+ breakpoint->address);
+ return retval;
+ }
+
+ /* invalidate instruction cache */
+ retval = du_core->or1k_jtag_write_cpu(&or1k->jtag,
+ OR1K_ICBIR_CPU_REG_ADD, 1, &breakpoint->address);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Error while invalidating the ICACHE");
+ return retval;
+ }
+
+ return ERROR_OK;
+}
+
+static int or1k_remove_breakpoint(struct target *target,
+ struct breakpoint *breakpoint)
+{
+ struct or1k_common *or1k = target_to_or1k(target);
+ struct or1k_du *du_core = or1k_to_du(or1k);
+
+ LOG_DEBUG("Removing breakpoint: addr 0x%08x, len %d, type %d, set: %d, id: %d",
+ breakpoint->address, breakpoint->length, breakpoint->type,
+ breakpoint->set, breakpoint->unique_id);
+
+ /* Only support SW breakpoints for now. */
+ if (breakpoint->type == BKPT_HARD)
+ LOG_ERROR("HW breakpoints not supported for now. Doing SW breakpoint.");
+
+ /* Replace the removed instruction */
+ int retval = du_core->or1k_jtag_write_memory(&or1k->jtag,
+ breakpoint->address,
+ 4,
+ 1,
+ breakpoint->orig_instr);
+
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Error while writing back the instruction at 0x%08x",
+ breakpoint->address);
+ return retval;
+ }
+
+ /* invalidate instruction cache */
+ retval = du_core->or1k_jtag_write_cpu(&or1k->jtag,
+ OR1K_ICBIR_CPU_REG_ADD, 1, &breakpoint->address);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Error while invalidating the ICACHE");
+ return retval;
+ }
+
+ return ERROR_OK;
+}
+
+static int or1k_add_watchpoint(struct target *target,
+ struct watchpoint *watchpoint)
+{
+ LOG_ERROR("%s: implement me", __func__);
+ return ERROR_OK;
+}
+
+static int or1k_remove_watchpoint(struct target *target,
+ struct watchpoint *watchpoint)
+{
+ LOG_ERROR("%s: implement me", __func__);
+ return ERROR_OK;
+}
+
+static int or1k_read_memory(struct target *target, uint32_t address,
+ uint32_t size, uint32_t count, uint8_t *buffer)
+{
+ struct or1k_common *or1k = target_to_or1k(target);
+ struct or1k_du *du_core = or1k_to_du(or1k);
+
+ LOG_DEBUG("Read memory at 0x%08x, size: %d, count: 0x%08x", address, size, count);
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* Sanitize arguments */
+ if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !buffer) {
+ LOG_ERROR("Bad arguments");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) {
+ LOG_ERROR("Can't handle unaligned memory access");
+ return ERROR_TARGET_UNALIGNED_ACCESS;
+ }
+
+ /* or1k_read_memory with size 4/2 returns uint32_t/uint16_t in host */
+ /* endianness, but byte array should represent target endianness */
+
+ void *t = NULL;
+ if (size > 1) {
+ t = malloc(count * size * sizeof(uint8_t));
+ if (t == NULL) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
+ } else
+ t = buffer;
+
+
+ int retval = du_core->or1k_jtag_read_memory(&or1k->jtag, address,
+ size, count, t);
+
+ if (retval == ERROR_OK) {
+ switch (size) {
+ case 4:
+ target_buffer_set_u32_array(target, buffer, count, t);
+ break;
+ case 2:
+ target_buffer_set_u16_array(target, buffer, count, t);
+ break;
+ }
+ }
+
+ if ((size > 1) && (t != NULL))
+ free(t);
+
+ return ERROR_OK;
+}
+
+static int or1k_write_memory(struct target *target, uint32_t address,
+ uint32_t size, uint32_t count, const uint8_t *buffer)
+{
+ struct or1k_common *or1k = target_to_or1k(target);
+ struct or1k_du *du_core = or1k_to_du(or1k);
+
+ LOG_DEBUG("Write memory at 0x%08x, size: %d, count: 0x%08x", address, size, count);
+
+ if (target->state != TARGET_HALTED) {
+ LOG_WARNING("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* Sanitize arguments */
+ if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !buffer) {
+ LOG_ERROR("Bad arguments");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) {
+ LOG_ERROR("Can't handle unaligned memory access");
+ return ERROR_TARGET_UNALIGNED_ACCESS;
+ }
+
+ /* or1k_write_memory with size 4/2 requires uint32_t/uint16_t in host */
+ /* endianness, but byte array represents target endianness */
+
+ void *t = NULL;
+ if (size > 1) {
+ t = malloc(count * size * sizeof(uint8_t));
+ if (t == NULL) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
+
+ switch (size) {
+ case 4:
+ target_buffer_get_u32_array(target, buffer, count, (uint32_t *)t);
+ break;
+ case 2:
+ target_buffer_get_u16_array(target, buffer, count, (uint16_t *)t);
+ break;
+ }
+ buffer = t;
+ }
+
+ int retval = du_core->or1k_jtag_write_memory(&or1k->jtag, address, size, count, buffer);
+
+ if (t != NULL)
+ free(t);
+
+ if (retval != ERROR_OK)
+ return retval;
+
+ return ERROR_OK;
+}
+
+static int or1k_init_target(struct command_context *cmd_ctx,
+ struct target *target)
+{
+ struct or1k_common *or1k = target_to_or1k(target);
+ struct or1k_du *du_core = or1k_to_du(or1k);
+ struct or1k_jtag *jtag = &or1k->jtag;
+
+ if (du_core == NULL) {
+ LOG_ERROR("No debug unit selected");
+ return ERROR_FAIL;
+ }
+
+ if (jtag->tap_ip == NULL) {
+ LOG_ERROR("No tap selected");
+ return ERROR_FAIL;
+ }
+
+ or1k->jtag.tap = target->tap;
+ or1k->jtag.or1k_jtag_inited = 0;
+ or1k->jtag.or1k_jtag_module_selected = -1;
+
+ or1k_build_reg_cache(target);
+
+ return ERROR_OK;
+}
+
+static int or1k_target_create(struct target *target, Jim_Interp *interp)
+{
+ struct or1k_common *or1k = calloc(1, sizeof(struct or1k_common));
+
+ if (target->tap == NULL)
+ return ERROR_FAIL;
+
+ target->arch_info = or1k;
+
+ or1k_create_reg_list(target);
+
+ or1k_tap_vjtag_register();
+ or1k_tap_mohor_register();
+
+ or1k_du_adv_register();
+
+ return ERROR_OK;
+}
+
+static int or1k_examine(struct target *target)
+{
+ struct or1k_common *or1k = target_to_or1k(target);
+ struct or1k_du *du_core = or1k_to_du(or1k);
+
+ if (!target_was_examined(target)) {
+
+ target_set_examined(target);
+
+ int running;
+
+ int retval = du_core->or1k_is_cpu_running(&or1k->jtag, &running);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Couldn't read the CPU state");
+ return retval;
+ } else {
+ if (running)
+ target->state = TARGET_RUNNING;
+ else {
+ LOG_DEBUG("Target is halted");
+
+ /* This is the first time we examine the target,
+ * it is stalled and we don't know why. Let's
+ * assume this is because of a debug reason.
+ */
+ if (target->state == TARGET_UNKNOWN)
+ target->debug_reason = DBG_REASON_DBGRQ;
+
+ target->state = TARGET_HALTED;
+ }
+ }
+ }
+
+ return ERROR_OK;
+}
+
+static int or1k_arch_state(struct target *target)
+{
+ return ERROR_OK;
+}
+
+static int or1k_get_gdb_reg_list(struct target *target, struct reg **reg_list[],
+ int *reg_list_size, enum target_register_class reg_class)
+{
+ struct or1k_common *or1k = target_to_or1k(target);
+
+ if (reg_class == REG_CLASS_GENERAL) {
+ /* We will have this called whenever GDB connects. */
+ int retval = or1k_save_context(target);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Error while calling or1k_save_context");
+ return retval;
+ }
+ *reg_list_size = OR1KNUMCOREREGS;
+ /* this is free()'d back in gdb_server.c's gdb_get_register_packet() */
+ *reg_list = malloc((*reg_list_size) * sizeof(struct reg *));
+
+ for (int i = 0; i < OR1KNUMCOREREGS; i++)
+ (*reg_list)[i] = &or1k->core_cache->reg_list[i];
+ } else {
+ *reg_list_size = or1k->nb_regs;
+ *reg_list = malloc((*reg_list_size) * sizeof(struct reg *));
+
+ for (int i = 0; i < or1k->nb_regs; i++)
+ (*reg_list)[i] = &or1k->core_cache->reg_list[i];
+ }
+
+ return ERROR_OK;
+
+}
+
+int or1k_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info)
+{
+ return ERROR_FAIL;
+}
+
+static int or1k_checksum_memory(struct target *target, uint32_t address,
+ uint32_t count, uint32_t *checksum) {
+
+ return ERROR_FAIL;
+}
+
+COMMAND_HANDLER(or1k_tap_select_command_handler)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct or1k_common *or1k = target_to_or1k(target);
+ struct or1k_jtag *jtag = &or1k->jtag;
+ struct or1k_tap_ip *or1k_tap;
+
+ if (CMD_ARGC != 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ list_for_each_entry(or1k_tap, &tap_list, list) {
+ if (or1k_tap->name) {
+ if (!strcmp(CMD_ARGV[0], or1k_tap->name)) {
+ jtag->tap_ip = or1k_tap;
+ LOG_INFO("%s tap selected", or1k_tap->name);
+ return ERROR_OK;
+ }
+ }
+ }
+
+ LOG_ERROR("%s unknown, no tap selected", CMD_ARGV[0]);
+ return ERROR_COMMAND_SYNTAX_ERROR;
+}
+
+COMMAND_HANDLER(or1k_tap_list_command_handler)
+{
+ struct or1k_tap_ip *or1k_tap;
+
+ if (CMD_ARGC != 0)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ list_for_each_entry(or1k_tap, &tap_list, list) {
+ if (or1k_tap->name)
+ command_print(CMD_CTX, "%s", or1k_tap->name);
+ }
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(or1k_du_select_command_handler)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct or1k_common *or1k = target_to_or1k(target);
+ struct or1k_jtag *jtag = &or1k->jtag;
+ struct or1k_du *or1k_du;
+
+ if (CMD_ARGC > 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ list_for_each_entry(or1k_du, &du_list, list) {
+ if (or1k_du->name) {
+ if (!strcmp(CMD_ARGV[0], or1k_du->name)) {
+ jtag->du_core = or1k_du;
+ LOG_INFO("%s debug unit selected", or1k_du->name);
+
+ if (CMD_ARGC == 2) {
+ int options;
+ COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], options);
+ or1k_du->options = options;
+ LOG_INFO("Option %x is passed to %s debug unit"
+ , options, or1k_du->name);
+ }
+
+ return ERROR_OK;
+ }
+ }
+ }
+
+ LOG_ERROR("%s unknown, no debug unit selected", CMD_ARGV[0]);
+ return ERROR_COMMAND_SYNTAX_ERROR;
+}
+
+COMMAND_HANDLER(or1k_du_list_command_handler)
+{
+ struct or1k_du *or1k_du;
+
+ if (CMD_ARGC != 0)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ list_for_each_entry(or1k_du, &du_list, list) {
+ if (or1k_du->name)
+ command_print(CMD_CTX, "%s", or1k_du->name);
+ }
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(or1k_addreg_command_handler)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct or1k_core_reg new_reg;
+
+ if (CMD_ARGC != 4)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ new_reg.target = NULL;
+ new_reg.or1k_common = NULL;
+
+ uint32_t addr;
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], addr);
+
+ new_reg.name = strdup(CMD_ARGV[0]);
+ new_reg.spr_num = addr;
+ new_reg.feature = strdup(CMD_ARGV[2]);
+ new_reg.group = strdup(CMD_ARGV[3]);
+
+ or1k_add_reg(target, &new_reg);
+
+ LOG_DEBUG("Add reg \"%s\" @ 0x%08x, group \"%s\", feature \"%s\"",
+ new_reg.name, addr, new_reg.group, new_reg.feature);
+
+ return ERROR_OK;
+}
+
+static const struct command_registration or1k_hw_ip_command_handlers[] = {
+ {
+ "tap_select",
+ .handler = or1k_tap_select_command_handler,
+ .mode = COMMAND_ANY,
+ .usage = "tap_select name",
+ .help = "Select the TAP core to use",
+ },
+ {
+ "tap_list",
+ .handler = or1k_tap_list_command_handler,
+ .mode = COMMAND_ANY,
+ .usage = "tap_list",
+ .help = "Display available TAP core",
+ },
+ {
+ "du_select",
+ .handler = or1k_du_select_command_handler,
+ .mode = COMMAND_ANY,
+ .usage = "du_select name",
+ .help = "Select the Debug Unit core to use",
+ },
+ {
+ "du_list",
+ .handler = or1k_du_list_command_handler,
+ .mode = COMMAND_ANY,
+ .usage = "select_tap name",
+ .help = "Display available Debug Unit core",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration or1k_reg_command_handlers[] = {
+ {
+ "addreg",
+ .handler = or1k_addreg_command_handler,
+ .mode = COMMAND_ANY,
+ .usage = "addreg name addr feature group",
+ .help = "Add a register to the register list",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration or1k_command_handlers[] = {
+ {
+ .chain = or1k_reg_command_handlers,
+ },
+ {
+ .chain = or1k_hw_ip_command_handlers,
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+
+struct target_type or1k_target = {
+ .name = "or1k",
+
+ .poll = or1k_poll,
+ .arch_state = or1k_arch_state,
+
+ .target_request_data = NULL,
+
+ .halt = or1k_halt,
+ .resume = or1k_resume,
+ .step = or1k_step,
+
+ .assert_reset = or1k_assert_reset,
+ .deassert_reset = or1k_deassert_reset,
+ .soft_reset_halt = or1k_soft_reset_halt,
+
+ .get_gdb_reg_list = or1k_get_gdb_reg_list,
+
+ .read_memory = or1k_read_memory,
+ .write_memory = or1k_write_memory,
+ .checksum_memory = or1k_checksum_memory,
+
+ .commands = or1k_command_handlers,
+ .add_breakpoint = or1k_add_breakpoint,
+ .remove_breakpoint = or1k_remove_breakpoint,
+ .add_watchpoint = or1k_add_watchpoint,
+ .remove_watchpoint = or1k_remove_watchpoint,
+
+ .target_create = or1k_target_create,
+ .init_target = or1k_init_target,
+ .examine = or1k_examine,
+
+ .get_gdb_fileio_info = or1k_get_gdb_fileio_info,
+};
diff --git a/src/target/openrisc/or1k.h b/src/target/openrisc/or1k.h
new file mode 100644
index 0000000..5610e01
--- /dev/null
+++ b/src/target/openrisc/or1k.h
@@ -0,0 +1,159 @@
+/***************************************************************************
+ * 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. *
+ ***************************************************************************/
+
+#ifndef OR1K_H
+#define OR1K_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <target/target.h>
+
+/* SPR groups start address */
+#define GROUP0 (0 << 11)
+#define GROUP1 (1 << 11)
+#define GROUP2 (2 << 11)
+#define GROUP3 (3 << 11)
+#define GROUP4 (4 << 11)
+#define GROUP5 (5 << 11)
+#define GROUP6 (6 << 11)
+#define GROUP7 (7 << 11)
+#define GROUP8 (8 << 11)
+#define GROUP9 (9 << 11)
+#define GROUP10 (10 << 11)
+
+/* OR1K registers */
+enum or1k_reg_nums {
+ OR1K_REG_R0 = 0,
+ OR1K_REG_R1,
+ OR1K_REG_R2,
+ OR1K_REG_R3,
+ OR1K_REG_R4,
+ OR1K_REG_R5,
+ OR1K_REG_R6,
+ OR1K_REG_R7,
+ OR1K_REG_R8,
+ OR1K_REG_R9,
+ OR1K_REG_R10,
+ OR1K_REG_R11,
+ OR1K_REG_R12,
+ OR1K_REG_R13,
+ OR1K_REG_R14,
+ OR1K_REG_R15,
+ OR1K_REG_R16,
+ OR1K_REG_R17,
+ OR1K_REG_R18,
+ OR1K_REG_R19,
+ OR1K_REG_R20,
+ OR1K_REG_R21,
+ OR1K_REG_R22,
+ OR1K_REG_R23,
+ OR1K_REG_R24,
+ OR1K_REG_R25,
+ OR1K_REG_R26,
+ OR1K_REG_R27,
+ OR1K_REG_R28,
+ OR1K_REG_R29,
+ OR1K_REG_R30,
+ OR1K_REG_R31,
+ OR1K_REG_PPC,
+ OR1K_REG_NPC,
+ OR1K_REG_SR,
+ OR1KNUMCOREREGS
+};
+
+struct or1k_jtag {
+ struct jtag_tap *tap;
+ int or1k_jtag_inited;
+ int or1k_jtag_module_selected;
+ uint8_t *current_reg_idx;
+ struct or1k_tap_ip *tap_ip;
+ struct or1k_du *du_core;
+};
+
+struct or1k_common {
+ struct or1k_jtag jtag;
+ struct reg_cache *core_cache;
+ uint32_t core_regs[OR1KNUMCOREREGS];
+ int nb_regs;
+ struct or1k_core_reg *arch_info;
+};
+
+static inline struct or1k_common *
+target_to_or1k(struct target *target)
+{
+ return (struct or1k_common *)target->arch_info;
+}
+
+struct or1k_core_reg {
+ const char *name;
+ uint32_t list_num; /* Index in register cache */
+ uint32_t spr_num; /* Number in architecture's SPR space */
+ struct target *target;
+ struct or1k_common *or1k_common;
+ const char *feature; /* feature name in XML tdesc file */
+ const char *group; /* register group in XML tdesc file */
+};
+
+struct or1k_core_reg_init {
+ const char *name;
+ uint32_t spr_num; /* Number in architecture's SPR space */
+ const char *feature; /* feature name in XML tdesc file */
+ const char *group; /* register group in XML tdesc file */
+};
+
+/* ORBIS32 Trap instruction */
+#define OR1K_TRAP_INSTR 0x21000001
+
+enum or1k_debug_reg_nums {
+ OR1K_DEBUG_REG_DMR1 = 0,
+ OR1K_DEBUG_REG_DMR2,
+ OR1K_DEBUG_REG_DCWR0,
+ OR1K_DEBUG_REG_DCWR1,
+ OR1K_DEBUG_REG_DSR,
+ OR1K_DEBUG_REG_DRR,
+ OR1K_DEBUG_REG_NUM
+};
+
+#define NO_SINGLE_STEP 0
+#define SINGLE_STEP 1
+
+/* OR1K Debug registers and bits needed for resuming */
+#define OR1K_DEBUG_REG_BASE GROUP6 /* Debug registers Base address */
+#define OR1K_DMR1_CPU_REG_ADD (OR1K_DEBUG_REG_BASE + 16) /* Debug Mode Register 1 0x3010 */
+#define OR1K_DMR1_ST 0x00400000 /* Single-step trace */
+#define OR1K_DMR1_BT 0x00800000 /* Branch trace */
+#define OR1K_DMR2_WGB 0x003ff000 /* Watchpoints generating breakpoint */
+#define OR1K_DSR_TE 0x00002000 /* Trap exception */
+
+/* OR1K Instruction cache registers needed for invalidating instruction
+ * memory during adding and removing breakpoints.
+ */
+#define OR1K_ICBIR_CPU_REG_ADD ((4 << 11) + 2) /* IC Block Invalidate Register 0x2002 */
+
+#endif
diff --git a/src/target/openrisc/or1k_du.h b/src/target/openrisc/or1k_du.h
new file mode 100644
index 0000000..564241d
--- /dev/null
+++ b/src/target/openrisc/or1k_du.h
@@ -0,0 +1,77 @@
+/***************************************************************************
+ * Copyright (C) 2013 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. *
+ ***************************************************************************/
+
+#ifndef OR1K_DU
+#define OR1K_DU
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define CPU_STALL 0
+#define CPU_UNSTALL 1
+
+#define CPU_RESET 0
+#define CPU_NOT_RESET 1
+
+int or1k_du_adv_register(void);
+
+/* Linear list over all available or1k debug unit */
+extern struct list_head du_list;
+
+struct or1k_du {
+ const char *name;
+ struct list_head list;
+ int options;
+
+ int (*or1k_jtag_init)(struct or1k_jtag *jtag_info);
+
+ int (*or1k_is_cpu_running)(struct or1k_jtag *jtag_info, int *running);
+
+ int (*or1k_cpu_stall)(struct or1k_jtag *jtag_info, int action);
+
+ int (*or1k_cpu_reset)(struct or1k_jtag *jtag_info, int action);
+
+ int (*or1k_jtag_read_cpu)(struct or1k_jtag *jtag_info,
+ uint32_t addr, int count, uint32_t *value);
+
+ int (*or1k_jtag_write_cpu)(struct or1k_jtag *jtag_info,
+ uint32_t addr, int count, const uint32_t *value);
+
+ int (*or1k_jtag_read_memory)(struct or1k_jtag *jtag_info, uint32_t addr, uint32_t size,
+ int count, uint8_t *buffer);
+
+ int (*or1k_jtag_write_memory)(struct or1k_jtag *jtag_info, uint32_t addr, uint32_t size,
+ int count, const uint8_t *buffer);
+};
+
+static inline struct or1k_du *or1k_jtag_to_du(struct or1k_jtag *jtag_info)
+{
+ return (struct or1k_du *)jtag_info->du_core;
+}
+
+static inline struct or1k_du *or1k_to_du(struct or1k_common *or1k)
+{
+ struct or1k_jtag *jtag = &or1k->jtag;
+ return (struct or1k_du *)jtag->du_core;
+}
+
+#endif
+
diff --git a/src/target/openrisc/or1k_du_adv.c b/src/target/openrisc/or1k_du_adv.c
new file mode 100644
index 0000000..6d449e8
--- /dev/null
+++ b/src/target/openrisc/or1k_du_adv.c
@@ -0,0 +1,900 @@
+/***************************************************************************
+ * Copyright (C) 2013 by Franck Jullien *
+ * elec4fun@gmail.com *
+ * *
+ * Inspired from adv_jtag_bridge which is: *
+ * Copyright (C) 2008-2010 Nathan Yawn *
+ * nyawn@opencores.net *
+ * *
+ * And the Mohor interface version of this file which is: *
+ * Copyright (C) 2011 by Julius Baxter *
+ * julius@opencores.org *
+ * *
+ * 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 "or1k_tap.h"
+#include "or1k.h"
+#include "or1k_du.h"
+
+#include <target/target.h>
+#include <jtag/jtag.h>
+
+/* This an option to the adv debug unit.
+ * If this is defined, status bits will be skipped on burst
+ * reads and writes to improve download speeds.
+ * This option must match the RTL configured option.
+ */
+#define ADBG_USE_HISPEED 1
+
+/* Definitions for the top-level debug unit. This really just consists
+ * of a single register, used to select the active debug module ("chain").
+ */
+#define DBG_MODULE_SELECT_REG_SIZE 2
+#define DBG_MAX_MODULES 4
+
+#define DC_WISHBONE 0
+#define DC_CPU0 1
+#define DC_CPU1 2
+#define DC_JSP 3
+
+/* CPU control register bits mask */
+#define DBG_CPU_CR_STALL 0x01
+#define DBG_CPU_CR_RESET 0x02
+
+/* Polynomial for the CRC calculation
+ * Yes, it's backwards. Yes, this is on purpose.
+ * The hardware is designed this way to save on logic and routing,
+ * and it's really all the same to us here.
+ */
+#define ADBG_CRC_POLY 0xedb88320
+
+/* These are for the internal registers in the Wishbone module
+ * The first is the length of the index register,
+ * the indexes of the various registers are defined after that.
+ */
+#define DBG_WB_REG_SEL_LEN 1
+#define DBG_WB_REG_ERROR 0
+
+/* Opcode definitions for the Wishbone module. */
+#define DBG_WB_OPCODE_LEN 4
+#define DBG_WB_CMD_NOP 0x0
+#define DBG_WB_CMD_BWRITE8 0x1
+#define DBG_WB_CMD_BWRITE16 0x2
+#define DBG_WB_CMD_BWRITE32 0x3
+#define DBG_WB_CMD_BREAD8 0x5
+#define DBG_WB_CMD_BREAD16 0x6
+#define DBG_WB_CMD_BREAD32 0x7
+#define DBG_WB_CMD_IREG_WR 0x9
+#define DBG_WB_CMD_IREG_SEL 0xd
+
+/* Internal register definitions for the CPU0 module. */
+#define DBG_CPU0_REG_SEL_LEN 1
+#define DBG_CPU0_REG_STATUS 0
+
+/* Opcode definitions for the first CPU module. */
+#define DBG_CPU0_OPCODE_LEN 4
+#define DBG_CPU0_CMD_NOP 0x0
+#define DBG_CPU0_CMD_BWRITE32 0x3
+#define DBG_CPU0_CMD_BREAD32 0x7
+#define DBG_CPU0_CMD_IREG_WR 0x9
+#define DBG_CPU0_CMD_IREG_SEL 0xd
+
+/* Internal register definitions for the CPU1 module. */
+#define DBG_CPU1_REG_SEL_LEN 1
+#define DBG_CPU1_REG_STATUS 0
+
+/* Opcode definitions for the second CPU module. */
+#define DBG_CPU1_OPCODE_LEN 4
+#define DBG_CPU1_CMD_NOP 0x0
+#define DBG_CPU1_CMD_BWRITE32 0x3
+#define DBG_CPU1_CMD_BREAD32 0x7
+#define DBG_CPU1_CMD_IREG_WR 0x9
+#define DBG_CPU1_CMD_IREG_SEL 0xd
+
+#define MAX_READ_STATUS_WAIT 10
+#define MAX_READ_BUSY_RETRY 2
+#define MAX_READ_CRC_RETRY 2
+#define MAX_WRITE_CRC_RETRY 2
+#define BURST_READ_READY 1
+#define MAX_BUS_ERRORS 2
+
+#define MAX_BURST_SIZE (4 * 1024)
+
+#define STATUS_BYTES 1
+#define CRC_LEN 4
+
+static struct or1k_du or1k_du_adv;
+
+static const char * const chain_name[] = {"WISHBONE", "CPU0", "CPU1", "JSP"};
+
+static uint32_t adbg_compute_crc(uint32_t crc, uint32_t data_in,
+ int length_bits)
+{
+ for (int i = 0; i < length_bits; i++) {
+ uint32_t d, c;
+ d = ((data_in >> i) & 0x1) ? 0xffffffff : 0;
+ c = (crc & 0x1) ? 0xffffffff : 0;
+ crc = crc >> 1;
+ crc = crc ^ ((d ^ c) & ADBG_CRC_POLY);
+ }
+
+ return crc;
+}
+
+static int find_status_bit(void *_buf, int len)
+{
+ int i = 0;
+ int count = 0;
+ int ret = -1;
+ uint8_t *buf = _buf;
+
+ while (!(buf[i] & (1 << count++)) && (i < len)) {
+ if (count == 8) {
+ count = 0;
+ i++;
+ }
+ }
+
+ if (i < len)
+ ret = (i * 8) + count;
+
+ return ret;
+}
+
+static int or1k_adv_jtag_init(struct or1k_jtag *jtag_info)
+{
+ struct or1k_tap_ip *tap_ip = jtag_info->tap_ip;
+
+ int retval = tap_ip->init(jtag_info);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("TAP initialization failed");
+ return retval;
+ }
+
+ /* TAP is now configured to communicate with debug interface */
+ jtag_info->or1k_jtag_inited = 1;
+
+ /* TAP reset - not sure what state debug module chain is in now */
+ jtag_info->or1k_jtag_module_selected = -1;
+
+ jtag_info->current_reg_idx = malloc(DBG_MAX_MODULES * sizeof(uint8_t));
+ memset(jtag_info->current_reg_idx, 0, DBG_MAX_MODULES * sizeof(uint8_t));
+
+ if (or1k_du_adv.options & ADBG_USE_HISPEED)
+ LOG_INFO("adv debug unit is configured with option ADBG_USE_HISPEED");
+
+ LOG_DEBUG("Init done");
+
+ return ERROR_OK;
+
+}
+
+/* Selects one of the modules in the debug unit
+ * (e.g. wishbone unit, CPU0, etc.)
+ */
+static int adbg_select_module(struct or1k_jtag *jtag_info, int chain)
+{
+ if (jtag_info->or1k_jtag_module_selected == chain)
+ return ERROR_OK;
+
+ /* MSB of the data out must be set to 1, indicating a module
+ * select command
+ */
+ uint8_t data = chain | (1 << DBG_MODULE_SELECT_REG_SIZE);
+
+ LOG_DEBUG("Select module: %s", chain_name[chain]);
+
+ struct scan_field field;
+
+ field.num_bits = (DBG_MODULE_SELECT_REG_SIZE + 1);
+ field.out_value = &data;
+ field.in_value = NULL;
+ jtag_add_dr_scan(jtag_info->tap, 1, &field, TAP_IDLE);
+
+ int retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ return retval;
+
+ jtag_info->or1k_jtag_module_selected = chain;
+
+ return ERROR_OK;
+}
+
+/* Set the index of the desired register in the currently selected module
+ * 1 bit module select command
+ * 4 bits opcode
+ * n bits index
+ */
+static int adbg_select_ctrl_reg(struct or1k_jtag *jtag_info, uint8_t regidx)
+{
+ int index_len;
+ uint32_t opcode;
+ uint32_t opcode_len;
+
+ /* If this reg is already selected, don't do a JTAG transaction */
+ if (jtag_info->current_reg_idx[jtag_info->or1k_jtag_module_selected] == regidx)
+ return ERROR_OK;
+
+ switch (jtag_info->or1k_jtag_module_selected) {
+ case DC_WISHBONE:
+ index_len = DBG_WB_REG_SEL_LEN;
+ opcode = DBG_WB_CMD_IREG_SEL;
+ opcode_len = DBG_WB_OPCODE_LEN;
+ break;
+ case DC_CPU0:
+ index_len = DBG_CPU0_REG_SEL_LEN;
+ opcode = DBG_CPU0_CMD_IREG_SEL;
+ opcode_len = DBG_CPU0_OPCODE_LEN;
+ break;
+ case DC_CPU1:
+ index_len = DBG_CPU1_REG_SEL_LEN;
+ opcode = DBG_CPU1_CMD_IREG_SEL;
+ opcode_len = DBG_CPU1_OPCODE_LEN;
+ break;
+ default:
+ LOG_ERROR("Illegal debug chain selected (%i) while selecting control register",
+ jtag_info->or1k_jtag_module_selected);
+ return ERROR_FAIL;
+ }
+
+ /* MSB must be 0 to access modules */
+ uint32_t data = (opcode & ~(1 << opcode_len)) << index_len;
+ data |= regidx;
+
+ struct scan_field field;
+
+ field.num_bits = (opcode_len + 1) + index_len;
+ field.out_value = (uint8_t *)&data;
+ field.in_value = NULL;
+ jtag_add_dr_scan(jtag_info->tap, 1, &field, TAP_IDLE);
+
+ int retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ return retval;
+
+ jtag_info->current_reg_idx[jtag_info->or1k_jtag_module_selected] = regidx;
+
+ return ERROR_OK;
+}
+
+/* Write control register (internal to the debug unit) */
+static int adbg_ctrl_write(struct or1k_jtag *jtag_info, uint8_t regidx,
+ uint32_t *cmd_data, int length_bits)
+{
+ int index_len;
+ uint32_t opcode;
+ uint32_t opcode_len;
+
+ LOG_DEBUG("Write control register %d: 0x%08x", regidx, cmd_data[0]);
+
+ int retval = adbg_select_ctrl_reg(jtag_info, regidx);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Error while calling adbg_select_ctrl_reg");
+ return retval;
+ }
+
+ switch (jtag_info->or1k_jtag_module_selected) {
+ case DC_WISHBONE:
+ index_len = DBG_WB_REG_SEL_LEN;
+ opcode = DBG_WB_CMD_IREG_WR;
+ opcode_len = DBG_WB_OPCODE_LEN;
+ break;
+ case DC_CPU0:
+ index_len = DBG_CPU0_REG_SEL_LEN;
+ opcode = DBG_CPU0_CMD_IREG_WR;
+ opcode_len = DBG_CPU0_OPCODE_LEN;
+ break;
+ case DC_CPU1:
+ index_len = DBG_CPU1_REG_SEL_LEN;
+ opcode = DBG_CPU1_CMD_IREG_WR;
+ opcode_len = DBG_CPU1_OPCODE_LEN;
+ break;
+ default:
+ LOG_ERROR("Illegal debug chain selected (%i) while doing control write",
+ jtag_info->or1k_jtag_module_selected);
+ return ERROR_FAIL;
+ }
+
+ struct scan_field field[2];
+
+ /* MSB must be 0 to access modules */
+ uint32_t data = (opcode & ~(1 << opcode_len)) << index_len;
+ data |= regidx;
+
+ field[0].num_bits = length_bits;
+ field[0].out_value = (uint8_t *)cmd_data;
+ field[0].in_value = NULL;
+
+ field[1].num_bits = (opcode_len + 1) + index_len;
+ field[1].out_value = (uint8_t *)&data;
+ field[1].in_value = NULL;
+
+ jtag_add_dr_scan(jtag_info->tap, 2, field, TAP_IDLE);
+
+ return jtag_execute_queue();
+}
+
+/* Reads control register (internal to the debug unit) */
+static int adbg_ctrl_read(struct or1k_jtag *jtag_info, uint32_t regidx,
+ uint32_t *data, int length_bits)
+{
+
+ int retval = adbg_select_ctrl_reg(jtag_info, regidx);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Error while calling adbg_select_ctrl_reg");
+ return retval;
+ }
+
+ int opcode_len;
+ uint32_t opcode;
+
+ /* There is no 'read' command, We write a NOP to read */
+ switch (jtag_info->or1k_jtag_module_selected) {
+ case DC_WISHBONE:
+ opcode = DBG_WB_CMD_NOP;
+ opcode_len = DBG_WB_OPCODE_LEN;
+ break;
+ case DC_CPU0:
+ opcode = DBG_CPU0_CMD_NOP;
+ opcode_len = DBG_CPU0_OPCODE_LEN;
+ break;
+ case DC_CPU1:
+ opcode = DBG_CPU1_CMD_NOP;
+ opcode_len = DBG_CPU1_OPCODE_LEN;
+ break;
+ default:
+ LOG_ERROR("Illegal debug chain selected (%i) while doing control read",
+ jtag_info->or1k_jtag_module_selected);
+ return ERROR_FAIL;
+ }
+
+ /* Zero MSB = op for module, not top-level debug unit */
+ uint32_t outdata = opcode & ~(0x1 << opcode_len);
+
+ struct scan_field field[2];
+
+ field[0].num_bits = length_bits;
+ field[0].out_value = NULL;
+ field[0].in_value = (uint8_t *)data;
+
+ field[1].num_bits = opcode_len + 1;
+ field[1].out_value = (uint8_t *)&outdata;
+ field[1].in_value = NULL;
+
+ jtag_add_dr_scan(jtag_info->tap, 2, field, TAP_IDLE);
+
+ return jtag_execute_queue();
+}
+
+/* sends out a burst command to the selected module in the debug unit (MSB to LSB):
+ * 1-bit module command
+ * 4-bit opcode
+ * 32-bit address
+ * 16-bit length (of the burst, in words)
+ */
+static int adbg_burst_command(struct or1k_jtag *jtag_info, uint32_t opcode,
+ uint32_t address, uint16_t length_words)
+{
+ uint32_t data[2];
+
+ /* Set up the data */
+ data[0] = length_words | (address << 16);
+ /* MSB must be 0 to access modules */
+ data[1] = ((address >> 16) | ((opcode & 0xf) << 16)) & ~(0x1 << 20);
+
+ struct scan_field field;
+
+ field.num_bits = 53;
+ field.out_value = (uint8_t *)&data[0];
+ field.in_value = NULL;
+
+ jtag_add_dr_scan(jtag_info->tap, 1, &field, TAP_IDLE);
+
+ return jtag_execute_queue();
+}
+
+static int adbg_wb_burst_read(struct or1k_jtag *jtag_info, int size,
+ int count, uint32_t start_address, uint8_t *data)
+{
+ int retry_full_crc = 0;
+ int retry_full_busy = 0;
+ int retval;
+ uint8_t opcode;
+
+ LOG_DEBUG("Doing burst read, word size %d, word count %d, start address 0x%08x",
+ size, count, start_address);
+
+ /* Select the appropriate opcode */
+ switch (jtag_info->or1k_jtag_module_selected) {
+ case DC_WISHBONE:
+ if (size == 1)
+ opcode = DBG_WB_CMD_BREAD8;
+ else if (size == 2)
+ opcode = DBG_WB_CMD_BREAD16;
+ else if (size == 4)
+ opcode = DBG_WB_CMD_BREAD32;
+ else {
+ LOG_WARNING("Tried burst read with invalid word size (%d),"
+ "defaulting to 4-byte words", size);
+ opcode = DBG_WB_CMD_BREAD32;
+ }
+ break;
+ case DC_CPU0:
+ if (size == 4)
+ opcode = DBG_CPU0_CMD_BREAD32;
+ else {
+ LOG_WARNING("Tried burst read with invalid word size (%d),"
+ "defaulting to 4-byte words", size);
+ opcode = DBG_CPU0_CMD_BREAD32;
+ }
+ break;
+ case DC_CPU1:
+ if (size == 4)
+ opcode = DBG_CPU1_CMD_BREAD32;
+ else {
+ LOG_WARNING("Tried burst read with invalid word size (%d),"
+ "defaulting to 4-byte words", size);
+ opcode = DBG_CPU0_CMD_BREAD32;
+ }
+ break;
+ default:
+ LOG_ERROR("Illegal debug chain selected (%i) while doing burst read",
+ jtag_info->or1k_jtag_module_selected);
+ return ERROR_FAIL;
+ }
+
+ int total_size_bytes = count * size;
+ struct scan_field field;
+ uint8_t *in_buffer = malloc(total_size_bytes + CRC_LEN + STATUS_BYTES);
+
+retry_read_full:
+
+ /* Send the BURST READ command, returns TAP to idle state */
+ retval = adbg_burst_command(jtag_info, opcode, start_address, count);
+ if (retval != ERROR_OK)
+ goto out;
+
+ field.num_bits = (total_size_bytes + CRC_LEN + STATUS_BYTES) * 8;
+ field.out_value = NULL;
+ field.in_value = in_buffer;
+
+ jtag_add_dr_scan(jtag_info->tap, 1, &field, TAP_IDLE);
+
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ goto out;
+
+ /* Look for the start bit in the first (STATUS_BYTES * 8) bits */
+ int shift = find_status_bit(in_buffer, STATUS_BYTES);
+
+ /* We expect the status bit to be in the first byte */
+ if (shift < 0) {
+ if (retry_full_busy++ < MAX_READ_BUSY_RETRY) {
+ LOG_WARNING("Burst read timed out");
+ goto retry_read_full;
+ } else {
+ LOG_ERROR("Burst read failed");
+ retval = ERROR_FAIL;
+ goto out;
+ }
+ }
+
+ buffer_shr(in_buffer, total_size_bytes + CRC_LEN + STATUS_BYTES, shift);
+
+ uint32_t crc_read;
+ memcpy(data, in_buffer, total_size_bytes);
+ memcpy(&crc_read, &in_buffer[total_size_bytes], 4);
+
+ uint32_t crc_calc = 0xffffffff;
+ for (int i = 0; i < total_size_bytes; i++)
+ crc_calc = adbg_compute_crc(crc_calc, data[i], 8);
+
+ if (crc_calc != crc_read) {
+ LOG_WARNING("CRC ERROR! Computed 0x%08x, read CRC 0x%08x", crc_calc, crc_read);
+ if (retry_full_crc++ < MAX_READ_CRC_RETRY)
+ goto retry_read_full;
+ else {
+ LOG_ERROR("Burst read failed");
+ retval = ERROR_FAIL;
+ goto out;
+ }
+ } else
+ LOG_DEBUG("CRC OK!");
+
+ /* Now, read the error register, and retry/recompute as necessary */
+ if (jtag_info->or1k_jtag_module_selected == DC_WISHBONE &&
+ !(or1k_du_adv.options & ADBG_USE_HISPEED)) {
+
+ uint32_t err_data[2] = {0, 0};
+ uint32_t addr;
+ int bus_error_retries = 0;
+
+ /* First, just get 1 bit...read address only if necessary */
+ retval = adbg_ctrl_read(jtag_info, DBG_WB_REG_ERROR, err_data, 1);
+ if (retval != ERROR_OK)
+ goto out;
+
+ /* Then we have a problem */
+ if (err_data[0] & 0x1) {
+
+ retval = adbg_ctrl_read(jtag_info, DBG_WB_REG_ERROR, err_data, 33);
+ if (retval != ERROR_OK)
+ goto out;
+
+ addr = (err_data[0] >> 1) | (err_data[1] << 31);
+ LOG_WARNING("WB bus error during burst read, address 0x%08x, retrying!", addr);
+
+ bus_error_retries++;
+ if (bus_error_retries > MAX_BUS_ERRORS) {
+ LOG_ERROR("Max WB bus errors reached during burst read");
+ retval = ERROR_FAIL;
+ goto out;
+ }
+
+ /* Don't call retry_do(), a JTAG reset won't help a WB bus error */
+ /* Write 1 bit, to reset the error register */
+ err_data[0] = 1;
+ retval = adbg_ctrl_write(jtag_info, DBG_WB_REG_ERROR, err_data, 1);
+ if (retval != ERROR_OK)
+ goto out;
+
+ goto retry_read_full;
+ }
+ }
+
+out:
+ free(in_buffer);
+
+ return retval;
+}
+
+/* Set up and execute a burst write to a contiguous set of addresses */
+static int adbg_wb_burst_write(struct or1k_jtag *jtag_info, const uint8_t *data, int size,
+ int count, unsigned long start_address)
+{
+ int retry_full_crc = 0;
+ int retval;
+ uint8_t opcode;
+
+ LOG_DEBUG("Doing burst write, word size %d, word count %d,"
+ "start address 0x%08lx", size, count, start_address);
+
+ /* Select the appropriate opcode */
+ switch (jtag_info->or1k_jtag_module_selected) {
+ case DC_WISHBONE:
+ if (size == 1)
+ opcode = DBG_WB_CMD_BWRITE8;
+ else if (size == 2)
+ opcode = DBG_WB_CMD_BWRITE16;
+ else if (size == 4)
+ opcode = DBG_WB_CMD_BWRITE32;
+ else {
+ LOG_DEBUG("Tried WB burst write with invalid word size (%d),"
+ "defaulting to 4-byte words", size);
+ opcode = DBG_WB_CMD_BWRITE32;
+ }
+ break;
+ case DC_CPU0:
+ if (size == 4)
+ opcode = DBG_CPU0_CMD_BWRITE32;
+ else {
+ LOG_DEBUG("Tried CPU0 burst write with invalid word size (%d),"
+ "defaulting to 4-byte words", size);
+ opcode = DBG_CPU0_CMD_BWRITE32;
+ }
+ break;
+ case DC_CPU1:
+ if (size == 4)
+ opcode = DBG_CPU1_CMD_BWRITE32;
+ else {
+ LOG_DEBUG("Tried CPU1 burst write with invalid word size (%d),"
+ "defaulting to 4-byte words", size);
+ opcode = DBG_CPU0_CMD_BWRITE32;
+ }
+ break;
+ default:
+ LOG_ERROR("Illegal debug chain selected (%i) while doing burst write",
+ jtag_info->or1k_jtag_module_selected);
+ return ERROR_FAIL;
+ }
+
+retry_full_write:
+
+ /* Send the BURST WRITE command, returns TAP to idle state */
+ retval = adbg_burst_command(jtag_info, opcode, start_address, count);
+ if (retval != ERROR_OK)
+ return retval;
+
+ struct scan_field field[3];
+
+ /* Write a start bit so it knows when to start counting */
+ uint8_t value = 1;
+ field[0].num_bits = 1;
+ field[0].out_value = &value;
+ field[0].in_value = NULL;
+
+ uint32_t crc_calc = 0xffffffff;
+ for (int i = 0; i < (count * size); i++)
+ crc_calc = adbg_compute_crc(crc_calc, data[i], 8);
+
+ field[1].num_bits = count * size * 8;
+ field[1].out_value = data;
+ field[1].in_value = NULL;
+
+ field[2].num_bits = 32;
+ field[2].out_value = (uint8_t *)&crc_calc;
+ field[2].in_value = NULL;
+
+ jtag_add_dr_scan(jtag_info->tap, 3, field, TAP_DRSHIFT);
+
+ /* Read the 'CRC match' bit, and go to idle */
+ field[0].num_bits = 1;
+ field[0].out_value = NULL;
+ field[0].in_value = &value;
+ jtag_add_dr_scan(jtag_info->tap, 1, field, TAP_IDLE);
+
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (!value) {
+ LOG_WARNING("CRC ERROR! match bit after write is %i (computed CRC 0x%08x)", value, crc_calc);
+ if (retry_full_crc++ < MAX_WRITE_CRC_RETRY)
+ goto retry_full_write;
+ else
+ return ERROR_FAIL;
+ } else
+ LOG_DEBUG("CRC OK!\n");
+
+ /* Now, read the error register, and retry/recompute as necessary */
+ if (jtag_info->or1k_jtag_module_selected == DC_WISHBONE &&
+ !(or1k_du_adv.options & ADBG_USE_HISPEED)) {
+ uint32_t addr;
+ int bus_error_retries = 0;
+ uint32_t err_data[2] = {0, 0};
+
+ /* First, just get 1 bit...read address only if necessary */
+ retval = adbg_ctrl_read(jtag_info, DBG_WB_REG_ERROR, err_data, 1);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* Then we have a problem */
+ if (err_data[0] & 0x1) {
+
+ retval = adbg_ctrl_read(jtag_info, DBG_WB_REG_ERROR, err_data, 33);
+ if (retval != ERROR_OK)
+ return retval;
+
+ addr = (err_data[0] >> 1) | (err_data[1] << 31);
+ LOG_WARNING("WB bus error during burst write, address 0x%08x, retrying!", addr);
+
+ bus_error_retries++;
+ if (bus_error_retries > MAX_BUS_ERRORS) {
+ LOG_ERROR("Max WB bus errors reached during burst read");
+ retval = ERROR_FAIL;
+ return retval;
+ }
+
+ /* Don't call retry_do(), a JTAG reset won't help a WB bus error */
+ /* Write 1 bit, to reset the error register */
+ err_data[0] = 1;
+ retval = adbg_ctrl_write(jtag_info, DBG_WB_REG_ERROR, err_data, 1);
+ if (retval != ERROR_OK)
+ return retval;
+
+ goto retry_full_write;
+ }
+ }
+
+ return ERROR_OK;
+}
+
+/* Currently hard set in functions to 32-bits */
+static int or1k_adv_jtag_read_cpu(struct or1k_jtag *jtag_info,
+ uint32_t addr, int count, uint32_t *value)
+{
+ if (!jtag_info->or1k_jtag_inited)
+ or1k_adv_jtag_init(jtag_info);
+
+ int retval = adbg_select_module(jtag_info, DC_CPU0);
+ if (retval != ERROR_OK)
+ return retval;
+
+ return adbg_wb_burst_read(jtag_info, 4, count, addr, (uint8_t *)value);
+}
+
+static int or1k_adv_jtag_write_cpu(struct or1k_jtag *jtag_info,
+ uint32_t addr, int count, const uint32_t *value)
+{
+ if (!jtag_info->or1k_jtag_inited)
+ or1k_adv_jtag_init(jtag_info);
+
+ int retval = adbg_select_module(jtag_info, DC_CPU0);
+ if (retval != ERROR_OK)
+ return retval;
+
+ return adbg_wb_burst_write(jtag_info, (uint8_t *)value, 4, count, addr);
+}
+
+static int or1k_adv_cpu_stall(struct or1k_jtag *jtag_info, int action)
+{
+ if (!jtag_info->or1k_jtag_inited)
+ or1k_adv_jtag_init(jtag_info);
+
+ int retval = adbg_select_module(jtag_info, DC_CPU0);
+ if (retval != ERROR_OK)
+ return retval;
+
+ uint32_t cpu_cr;
+ retval = adbg_ctrl_read(jtag_info, DBG_CPU0_REG_STATUS, &cpu_cr, 2);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (action == CPU_STALL)
+ cpu_cr |= DBG_CPU_CR_STALL;
+ else
+ cpu_cr &= ~DBG_CPU_CR_STALL;
+
+ retval = adbg_select_module(jtag_info, DC_CPU0);
+ if (retval != ERROR_OK)
+ return retval;
+
+ return adbg_ctrl_write(jtag_info, DBG_CPU0_REG_STATUS, &cpu_cr, 2);
+}
+
+static int or1k_adv_is_cpu_running(struct or1k_jtag *jtag_info, int *running)
+{
+ if (!jtag_info->or1k_jtag_inited)
+ or1k_adv_jtag_init(jtag_info);
+
+ int retval = adbg_select_module(jtag_info, DC_CPU0);
+ if (retval != ERROR_OK)
+ return retval;
+
+ uint32_t cpu_cr = 0;
+ retval = adbg_ctrl_read(jtag_info, DBG_CPU0_REG_STATUS, &cpu_cr, 2);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (cpu_cr & DBG_CPU_CR_STALL)
+ *running = 0;
+ else
+ *running = 1;
+
+ return ERROR_OK;
+}
+
+static int or1k_adv_cpu_reset(struct or1k_jtag *jtag_info, int action)
+{
+ if (!jtag_info->or1k_jtag_inited)
+ or1k_adv_jtag_init(jtag_info);
+
+ int retval = adbg_select_module(jtag_info, DC_CPU0);
+ if (retval != ERROR_OK)
+ return retval;
+
+ uint32_t cpu_cr;
+ retval = adbg_ctrl_read(jtag_info, DBG_CPU0_REG_STATUS, &cpu_cr, 2);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (action == CPU_RESET)
+ cpu_cr |= DBG_CPU_CR_RESET;
+ else
+ cpu_cr &= ~DBG_CPU_CR_RESET;
+
+ retval = adbg_select_module(jtag_info, DC_CPU0);
+ if (retval != ERROR_OK)
+ return retval;
+
+ return adbg_ctrl_write(jtag_info, DBG_CPU0_REG_STATUS, &cpu_cr, 2);
+}
+
+static int or1k_adv_jtag_read_memory(struct or1k_jtag *jtag_info,
+ uint32_t addr, uint32_t size, int count, uint8_t *buffer)
+{
+ LOG_DEBUG("Reading WB%d at 0x%08x", size * 8, addr);
+
+ if (!jtag_info->or1k_jtag_inited)
+ or1k_adv_jtag_init(jtag_info);
+
+ int retval = adbg_select_module(jtag_info, DC_WISHBONE);
+ if (retval != ERROR_OK)
+ return retval;
+
+ int block_count_left = count;
+ uint32_t block_count_address = addr;
+ uint8_t *block_count_buffer = (uint8_t *)buffer;
+
+ while (block_count_left) {
+
+ int blocks_this_round = (block_count_left > MAX_BURST_SIZE) ?
+ MAX_BURST_SIZE : block_count_left;
+
+ retval = adbg_wb_burst_read(jtag_info, size, blocks_this_round,
+ block_count_address, block_count_buffer);
+ if (retval != ERROR_OK)
+ return retval;
+
+ block_count_left -= blocks_this_round;
+ block_count_address += size * MAX_BURST_SIZE;
+ block_count_buffer += size * MAX_BURST_SIZE;
+ }
+
+ return ERROR_OK;
+}
+
+static int or1k_adv_jtag_write_memory(struct or1k_jtag *jtag_info,
+ uint32_t addr, uint32_t size, int count, const uint8_t *buffer)
+{
+ LOG_DEBUG("Writing WB%d at 0x%08x", size * 8, addr);
+
+ if (!jtag_info->or1k_jtag_inited)
+ or1k_adv_jtag_init(jtag_info);
+
+ int retval = adbg_select_module(jtag_info, DC_WISHBONE);
+ if (retval != ERROR_OK)
+ return retval;
+
+ int block_count_left = count;
+ uint32_t block_count_address = addr;
+ uint8_t *block_count_buffer = (uint8_t *)buffer;
+
+ while (block_count_left) {
+
+ int blocks_this_round = (block_count_left > MAX_BURST_SIZE) ?
+ MAX_BURST_SIZE : block_count_left;
+
+ retval = adbg_wb_burst_write(jtag_info, block_count_buffer,
+ size, blocks_this_round,
+ block_count_address);
+ if (retval != ERROR_OK)
+ return retval;
+
+ block_count_left -= blocks_this_round;
+ block_count_address += size * MAX_BURST_SIZE;
+ block_count_buffer += size * MAX_BURST_SIZE;
+ }
+
+ return ERROR_OK;
+}
+
+static struct or1k_du or1k_du_adv = {
+ .name = "adv",
+ .options = ADBG_USE_HISPEED,
+ .or1k_jtag_init = or1k_adv_jtag_init,
+
+ .or1k_is_cpu_running = or1k_adv_is_cpu_running,
+ .or1k_cpu_stall = or1k_adv_cpu_stall,
+ .or1k_cpu_reset = or1k_adv_cpu_reset,
+
+ .or1k_jtag_read_cpu = or1k_adv_jtag_read_cpu,
+ .or1k_jtag_write_cpu = or1k_adv_jtag_write_cpu,
+
+ .or1k_jtag_read_memory = or1k_adv_jtag_read_memory,
+ .or1k_jtag_write_memory = or1k_adv_jtag_write_memory
+};
+
+int or1k_du_adv_register(void)
+{
+ list_add_tail(&or1k_du_adv.list, &du_list);
+ return 0;
+}
diff --git a/src/target/openrisc/or1k_tap.h b/src/target/openrisc/or1k_tap.h
new file mode 100644
index 0000000..64bdef2
--- /dev/null
+++ b/src/target/openrisc/or1k_tap.h
@@ -0,0 +1,43 @@
+/***************************************************************************
+ * Copyright (C) 2012 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. *
+ ***************************************************************************/
+
+#ifndef _OR1K_TAP_H_
+#define _OR1K_TAP_H_
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <helper/list.h>
+#include "or1k.h"
+
+int or1k_tap_vjtag_register(void);
+int or1k_tap_mohor_register(void);
+
+/* Linear list over all available or1k taps */
+extern struct list_head tap_list;
+
+struct or1k_tap_ip {
+ struct list_head list;
+ int (*init)(struct or1k_jtag *jtag_info);
+ const char *name;
+};
+
+#endif
diff --git a/src/target/openrisc/or1k_tap_mohor.c b/src/target/openrisc/or1k_tap_mohor.c
new file mode 100644
index 0000000..7c7f437
--- /dev/null
+++ b/src/target/openrisc/or1k_tap_mohor.c
@@ -0,0 +1,65 @@
+/***************************************************************************
+ * 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 "or1k_tap.h"
+#include "or1k.h"
+
+#include <jtag/jtag.h>
+
+#define OR1K_TAP_INST_DEBUG 0x8
+
+static int or1k_tap_mohor_init(struct or1k_jtag *jtag_info)
+{
+ LOG_DEBUG("Initialising OpenCores JTAG TAP");
+
+ /* Put TAP into state where it can talk to the debug interface
+ * by shifting in correct value to IR.
+ */
+
+ /* Ensure TAP is reset - maybe not necessary*/
+ jtag_add_tlr();
+
+ struct jtag_tap *tap = jtag_info->tap;
+ struct scan_field field;
+ uint8_t ir_value = OR1K_TAP_INST_DEBUG;
+
+ field.num_bits = tap->ir_length;
+ field.out_value = &ir_value;
+ field.in_value = NULL;
+
+ jtag_add_ir_scan(tap, &field, TAP_IDLE);
+
+ return jtag_execute_queue();
+}
+
+static struct or1k_tap_ip mohor_tap = {
+ .name = "mohor",
+ .init = or1k_tap_mohor_init,
+};
+
+int or1k_tap_mohor_register(void)
+{
+ list_add_tail(&mohor_tap.list, &tap_list);
+ return 0;
+}
diff --git a/src/target/openrisc/or1k_tap_vjtag.c b/src/target/openrisc/or1k_tap_vjtag.c
new file mode 100644
index 0000000..ae729a0
--- /dev/null
+++ b/src/target/openrisc/or1k_tap_vjtag.c
@@ -0,0 +1,310 @@
+/***************************************************************************
+ * 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 "or1k_tap.h"
+#include "or1k.h"
+
+#include <jtag/jtag.h>
+
+/* Contains constants relevant to the Altera Virtual JTAG
+ * device, which are not included in the BSDL.
+ * As of this writing, these are constant across every
+ * device which supports virtual JTAG.
+ */
+
+/* These are commands for the FPGA's IR. */
+#define ALTERA_CYCLONE_CMD_USER1 0x0E
+#define ALTERA_CYCLONE_CMD_USER0 0x0C
+
+/* These defines are for the virtual IR (not the FPGA's)
+ * The virtual TAP was defined in hardware to match the OpenCores native
+ * TAP in both IR size and DEBUG command.
+ */
+#define ALT_VJTAG_IR_SIZE 4
+#define ALT_VJTAG_CMD_DEBUG 0x8
+
+/* SLD node ID. */
+#define JTAG_TO_AVALON_NODE_ID 0x84
+#define VJTAG_NODE_ID 0x08
+#define SIGNAL_TAP_NODE_ID 0x00
+#define SERIAL_FLASH_LOADER_NODE_ID 0x04
+
+#define VER(x) ((x >> 27) & 0x1f)
+#define NB_NODES(x) ((x >> 19) & 0xff)
+#define ID(x) ((x >> 19) & 0xff)
+#define MANUF(x) ((x >> 8) & 0x7ff)
+#define M_WIDTH(x) ((x >> 0) & 0xff)
+#define INST_ID(x) ((x >> 0) & 0xff)
+
+/* tap instructions - Mohor JTAG TAP */
+#define OR1K_TAP_INST_IDCODE 0x2
+#define OR1K_TAP_INST_DEBUG 0x8
+
+static char *id_to_string(unsigned char id)
+{
+ switch (id) {
+ case VJTAG_NODE_ID:
+ return "Virtual JTAG";
+ case JTAG_TO_AVALON_NODE_ID:
+ return "JTAG to avalon bridge";
+ case SIGNAL_TAP_NODE_ID:
+ return "Signal TAP";
+ case SERIAL_FLASH_LOADER_NODE_ID:
+ return "Serial Flash Loader";
+ }
+ return "unknown";
+}
+
+static unsigned char guess_addr_width(unsigned char number_of_nodes)
+{
+ unsigned char width = 0;
+
+ while (number_of_nodes) {
+ number_of_nodes >>= 1;
+ width++;
+ }
+
+ return width;
+}
+
+static int or1k_tap_vjtag_init(struct or1k_jtag *jtag_info)
+{
+ LOG_DEBUG("Initialising Altera Virtual JTAG TAP");
+
+ /* Put TAP into state where it can talk to the debug interface
+ * by shifting in correct value to IR.
+ */
+
+ /* Ensure TAP is reset - maybe not necessary*/
+ jtag_add_tlr();
+
+ /* You can use a custom JTAG controller to discover transactions
+ * necessary to enumerate all Virtual JTAG megafunction instances
+ * from your design atruntime. All SLD nodes and the virtual JTAG
+ * registers that they contain are targeted by two Instruction Register
+ * values, USER0 and USER1.
+ *
+ * The USER1 instruction targets the virtual IR of either the sld_hub
+ * or a SLD node. That is,when the USER1 instruction is issued to
+ * the device, the subsequent DR scans target a specific virtual
+ * IR chain based on an address field contained within the DR scan.
+ * The table below shows how the virtual IR, the DR target of the
+ * USER1 instruction is interpreted.
+ *
+ * The VIR_VALUE in the table below is the virtual IR value for the
+ * target SLD node. The width of this field is m bits in length,
+ * where m is the length of the largest VIR for all of the SLD nodes
+ * in the design. All SLD nodes with VIR lengths of fewer than m
+ * bits must pad VIR_VALUE with zeros up to a length of m.
+ *
+ * -------------------------------+-------------------------------
+ * m + n - 1 m | m -1 0
+ * -------------------------------+-------------------------------
+ * ADDR [(n – 1)..0] | VIR_VALUE [(m – 1)..0]
+ * -------------------------------+-------------------------------
+ *
+ * The ADDR bits act as address values to signal the active SLD node
+ * that the virtual IR shift targets. ADDR is n bits in length, where
+ * n bits must be long enough to encode all SLD nodes within the design,
+ * as shown below.
+ *
+ * n = CEIL(log2(Number of SLD_nodes +1))
+ *
+ * The SLD hub is always 0 in the address map.
+ *
+ * Discovery and enumeration of the SLD instances within a design
+ * requires interrogation of the sld_hub to determine the dimensions
+ * of the USER1 DR (m and n) and associating each SLD instance, specifically
+ * the Virtual JTAG megafunction instances, with an address value
+ * contained within the ADDR bits of the USER1 DR.
+ *
+ * The SLD hub contains the HUB IP Configuration Register and SLD_NODE_INFO
+ * register for each SLD node in the design. The HUB IP configuration register provides
+ * information needed to determine the dimensions of the USER1 DR chain. The
+ * SLD_NODE_INFO register is used to determine the address mapping for Virtual
+ * JTAG instance in your design. This register set is shifted out by issuing the
+ * HUB_INFO instruction. Both the ADDR bits for the SLD hub and the HUB_INFO
+ * instruction is 0 × 0.
+ * Because m and n are unknown at this point, the DR register
+ * (ADDR bits + VIR_VALUE) must be filled with zeros. Shifting a sequence of 64 zeroes
+ * into the USER1 DR is sufficient to cover the most conservative case for m and n.
+ */
+
+ uint8_t t[4];
+ struct scan_field field;
+ struct jtag_tap *tap = jtag_info->tap;
+
+ /* Select VIR */
+ buf_set_u32(t, 0, tap->ir_length, ALTERA_CYCLONE_CMD_USER1);
+ field.num_bits = tap->ir_length;
+ field.out_value = t;
+ field.in_value = NULL;
+ jtag_add_ir_scan(tap, &field, TAP_IDLE);
+
+ /* Select the SLD Hub */
+ field.num_bits = 64;
+ field.out_value = NULL;
+ field.in_value = NULL;
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+
+ /* HUB IP Configuration Register
+ *
+ * When the USER1 and HUB_INFO instruction sequence is issued, the
+ * USER0 instruction must be applied to enable the target register
+ * of the HUB_INFO instruction. The HUB IP configuration register
+ * is shifted out using eight four-bit nibble scans of the DR register.
+ * Each four-bit scan must pass through the UPDATE_DR state before
+ * the next four-bit scan. The 8 scans are assembled into a 32-bit
+ * value with the definitions shown in the table below.
+ *
+ * --------------------------------------------------------------------------------
+ * NIBBLE7 | NIBBLE6 | NIBBLE5 | NIBBLE4 | NIBBLE3 | NIBBLE2 | NIBBLE1 | NIBBLE0
+ * ----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+-----
+ * | | | | | | | | | | | | | | |
+ * ----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+-----
+ * HUB IP version| N | ALTERA_MFG_ID (0x06E) | SUM (m, n)
+ * --------------+-------------------+------------------------+--------------------
+ */
+
+ /* Select VDR */
+ buf_set_u32(t, 0, tap->ir_length, ALTERA_CYCLONE_CMD_USER0);
+ field.num_bits = tap->ir_length;
+ field.out_value = t;
+ field.in_value = NULL;
+ jtag_add_ir_scan(tap, &field, TAP_IDLE);
+
+ int retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ return retval;
+
+ uint8_t nibble;
+ uint32_t hub_info = 0;
+
+ for (int i = 0; i < 8; i++) {
+ field.num_bits = 4;
+ field.out_value = NULL;
+ field.in_value = &nibble;
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ return retval;
+ hub_info = ((hub_info >> 4) | ((nibble & 0xf) << 28));
+ }
+
+ int nb_nodes = NB_NODES(hub_info);
+ int m_width = M_WIDTH(hub_info);
+
+ LOG_DEBUG("SLD HUB Configuration register");
+ LOG_DEBUG("------------------------------");
+ LOG_DEBUG("m_width = %d", m_width);
+ LOG_DEBUG("manufacturer_id = 0x%02x", MANUF(hub_info));
+ LOG_DEBUG("nb_of_node = %d", nb_nodes);
+ LOG_DEBUG("version = %d", VER(hub_info));
+ LOG_DEBUG("VIR length = %d", guess_addr_width(nb_nodes) + m_width);
+
+ /* Because the number of SLD nodes is now known, the Nodes on the hub can be
+ * enumerated by repeating the 8 four-bit nibble scans, once for each Node,
+ * to yield the SLD_NODE_INFO register of each Node. The DR nibble shifts
+ * are a continuation of the HUB_INFO DR shift used to shift out the Hub IP
+ * Configuration register.
+ *
+ * The order of the Nodes as they are shifted out determines the ADDR
+ * values for the Nodes, beginning with, for the first Node SLD_NODE_INFO
+ * shifted out, up to and including, for the last node on the hub. The
+ * tables below show the SLD_NODE_INFO register and a their functional descriptions.
+ *
+ * --------------+-----------+---------------+----------------
+ * 31 27 | 26 19 | 18 8 | 7 0
+ * --------------+-----------+---------------+----------------
+ * Node Version | NODE ID | NODE MFG_ID | NODE INST ID
+ *
+ */
+
+ int vjtag_node_address = -1;
+ int node_index;
+ uint32_t node_info = 0;
+ for (node_index = 0; node_index < nb_nodes; node_index++) {
+
+ for (int i = 0; i < 8; i++) {
+ field.num_bits = 4;
+ field.out_value = NULL;
+ field.in_value = &nibble;
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ return retval;
+ node_info = ((node_info >> 4) | ((nibble & 0xf) << 28));
+ }
+
+ LOG_DEBUG("Node info register");
+ LOG_DEBUG("--------------------");
+ LOG_DEBUG("instance_id = %d", ID(node_info));
+ LOG_DEBUG("manufacturer_id = 0x%02x", MANUF(node_info));
+ LOG_DEBUG("node_id = %d (%s)", ID(node_info),
+ id_to_string(ID(node_info)));
+ LOG_DEBUG("version = %d", VER(node_info));
+
+ if (ID(node_info) == VJTAG_NODE_ID)
+ vjtag_node_address = node_index + 1;
+ }
+
+ if (vjtag_node_address < 0) {
+ LOG_ERROR("No VJTAG TAP instance found !");
+ return ERROR_FAIL;
+ }
+
+ /* Select VIR */
+ t[0] = ALTERA_CYCLONE_CMD_USER1;
+ field.num_bits = tap->ir_length;
+ field.out_value = t;
+ field.in_value = NULL;
+ jtag_add_ir_scan(tap, &field, TAP_IDLE);
+
+ /* Send the DEBUG command to the VJTAG IR */
+ buf_set_u32(t, 0, field.num_bits, (vjtag_node_address << m_width) | ALT_VJTAG_CMD_DEBUG);
+ field.num_bits = guess_addr_width(nb_nodes) + m_width;
+ field.out_value = t;
+ field.in_value = NULL;
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+
+ /* Select the VJTAG DR */
+ t[0] = ALTERA_CYCLONE_CMD_USER0;
+ field.num_bits = tap->ir_length;
+ field.out_value = t;
+ field.in_value = NULL;
+ jtag_add_ir_scan(tap, &field, TAP_IDLE);
+
+ return jtag_execute_queue();
+}
+
+static struct or1k_tap_ip vjtag_tap = {
+ .name = "vjtag",
+ .init = or1k_tap_vjtag_init,
+};
+
+int or1k_tap_vjtag_register(void)
+{
+ list_add_tail(&vjtag_tap.list, &tap_list);
+ return 0;
+}