Add new target type: OpenRISC47/1547/16
authorFranck Jullien <franck.jullien@gmail.com>
Thu, 8 Aug 2013 21:45:47 +0000 (8 23:45 +0200)
committerSpencer Oliver <spen@spen-soft.co.uk>
Thu, 26 Sep 2013 09:52:56 +0000 (26 09:52 +0000)
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>
16 files changed:
configure.ac
doc/openocd.texi
src/helper/binarybuffer.c
src/helper/binarybuffer.h
src/target/Makefile.am
src/target/openrisc/Makefile.am [new file with mode: 0644]
src/target/openrisc/or1k.c [new file with mode: 0644]
src/target/openrisc/or1k.h [new file with mode: 0644]
src/target/openrisc/or1k_du.h [new file with mode: 0644]
src/target/openrisc/or1k_du_adv.c [new file with mode: 0644]
src/target/openrisc/or1k_tap.h [new file with mode: 0644]
src/target/openrisc/or1k_tap_mohor.c [new file with mode: 0644]
src/target/openrisc/or1k_tap_vjtag.c [new file with mode: 0644]
src/target/target.c
tcl/board/or1k_generic.cfg [new file with mode: 0644]
tcl/target/or1k.cfg [new file with mode: 0644]

index 7e475e7..b713a30 100644 (file)
@@ -1261,6 +1261,7 @@ AC_CONFIG_FILES([
   src/jtag/hla/Makefile
   src/jtag/aice/Makefile
   src/transport/Makefile
+  src/target/openrisc/Makefile
   src/xsvf/Makefile
   src/svf/Makefile
   src/target/Makefile
index 4caefb8..003ec4f 100644 (file)
@@ -4179,6 +4179,17 @@ There are several variants defined:
 @code{pxa26x} ... instruction register length is 5 bits
 @item @code{pxa3xx} ... instruction register length is 11 bits
 @end itemize
+@item @code{openrisc} -- this is an OpenRISC 1000 core.
+The current implementation supports two JTAG TAP cores:
+@itemize @minus
+@item @code{OpenCores TAP} (See: @emph{http://opencores.org/project,jtag})
+@item @code{Altera Virtual JTAG TAP} (See: @emph{http://www.altera.com/literature/ug/ug_virtualjtag.pdf})
+@end itemize
+And two debug interfaces cores:
+@itemize @minus
+@item @code{Advanced debug interface} (See: @emph{http://opencores.org/project,adv_debug_sys})
+@item @code{SoC Debug Interface} (See: @emph{http://opencores.org/project,dbg_interface})
+@end itemize
 @end itemize
 @end deffn
 
@@ -7493,6 +7504,51 @@ the peripherals.
 @xref{targetevents,,Target Events}.
 @end deffn
 
+@section OpenRISC Architecture
+
+The OpenRISC CPU is a soft core. It is used in a programmable SoC which can be
+configured with any of the TAP / Debug Unit available.
+
+@subsection TAP and Debug Unit selection commands
+@deffn Command {tap_select} (@option{vjtag}|@option{mohor})
+Select between the Altera Virtual JTAG and Mohor TAP.
+@end deffn
+@deffn Command {du_select} (@option{adv}|@option{mohor}) [option]
+Select between the Advanced Debug Interface and the classic one.
+
+An option can be passed as a second argument to the debug unit.
+
+When using the Advanced Debug Interface, option = 1 means the RTL core is
+configured with ADBG_USE_HISPEED = 1. This configuration skips status checking
+between bytes while doing read or write bursts.
+@end deffn
+
+@subsection Registers commands
+@deffn Command {addreg} [name] [address] [feature] [reg_group]
+Add a new register in the cpu register list. This register will be
+included in the generated target descriptor file.
+
+@strong{[feature]} must be "org.gnu.gdb.or1k.group[0..10]".
+
+@strong{[reg_group]} can be anything. The default register list defines "system",
+ "dmmu", "immu", "dcache", "icache", "mac", "debug", "perf", "power", "pic"
+ and "timer" groups.
+
+@emph{example:}
+@example
+addreg rtest 0x1234 org.gnu.gdb.or1k.group0 system
+@end example
+
+
+@end deffn
+@deffn Command {readgroup} (@option{group})
+Display all registers in @emph{group}.
+
+@emph{group} can be "system",
+ "dmmu", "immu", "dcache", "icache", "mac", "debug", "perf", "power", "pic",
+ "timer" or any new group created with addreg command.
+@end deffn
+
 @anchor{softwaredebugmessagesandtracing}
 @section Software Debug Messages and Tracing
 @cindex Linux-ARM DCC support
index 5defcda..6fe3664 100644 (file)
@@ -397,3 +397,24 @@ int hexify(char *hex, const char *bin, int count, int out_maxlen)
 
        return cmd_len;
 }
+
+void buffer_shr(void *_buf, unsigned buf_len, unsigned count)
+{
+       unsigned i;
+       unsigned char *buf = _buf;
+       unsigned bytes_to_remove;
+       unsigned shift;
+
+       bytes_to_remove = count / 8;
+       shift = count - (bytes_to_remove * 8);
+
+       for (i = 0; i < (buf_len - 1); i++)
+               buf[i] = (buf[i] >> shift) | ((buf[i+1] << (8 - shift)) & 0xff);
+
+       buf[(buf_len - 1)] = buf[(buf_len - 1)] >> shift;
+
+       if (bytes_to_remove) {
+               memmove(buf, &buf[bytes_to_remove], buf_len - bytes_to_remove);
+               memset(&buf[buf_len - bytes_to_remove], 0, bytes_to_remove);
+       }
+}
index c2d643b..5b86c5f 100644 (file)
@@ -238,5 +238,6 @@ void bit_copy_discard(struct bit_copy_queue *q);
  * used in ti-icdi driver and gdb server */
 int unhexify(char *bin, const char *hex, int count);
 int hexify(char *hex, const char *bin, int count, int out_maxlen);
+void buffer_shr(void *_buf, unsigned buf_len, unsigned count);
 
 #endif /* BINARYBUFFER_H */
index 027cc8e..1560753 100644 (file)
@@ -6,6 +6,9 @@ else
 OOCD_TRACE_FILES =
 endif
 
+SUBDIRS = openrisc
+libtarget_la_LIBADD = $(top_builddir)/src/target/openrisc/libopenrisc.la
+
 BIN2C          = $(top_builddir)/src/helper/bin2char$(EXEEXT_FOR_BUILD)
 
 DEBUG_HANDLER  = $(srcdir)/xscale/debug_handler.bin
diff --git a/src/target/openrisc/Makefile.am b/src/target/openrisc/Makefile.am
new file mode 100644 (file)
index 0000000..61e4742
--- /dev/null
@@ -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 (file)
index 0000000..8d8ad40
--- /dev/null
@@ -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 (file)
index 0000000..5610e01
--- /dev/null
@@ -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 (file)
index 0000000..564241d
--- /dev/null
@@ -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 (file)
index 0000000..6d449e8
--- /dev/null
@@ -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 (file)
index 0000000..64bdef2
--- /dev/null
@@ -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 (file)
index 0000000..7c7f437
--- /dev/null
@@ -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 (file)
index 0000000..ae729a0
--- /dev/null
@@ -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;
+}
index 4a8d9aa..0eb5788 100644 (file)
@@ -101,6 +101,7 @@ extern struct target_type hla_target;
 extern struct target_type nds32_v2_target;
 extern struct target_type nds32_v3_target;
 extern struct target_type nds32_v3m_target;
+extern struct target_type or1k_target;
 
 static struct target_type *target_types[] = {
        &arm7tdmi_target,
@@ -128,6 +129,7 @@ static struct target_type *target_types[] = {
        &nds32_v2_target,
        &nds32_v3_target,
        &nds32_v3m_target,
+       &or1k_target,
        NULL,
 };
 
diff --git a/tcl/board/or1k_generic.cfg b/tcl/board/or1k_generic.cfg
new file mode 100644 (file)
index 0000000..9daa7ab
--- /dev/null
@@ -0,0 +1,42 @@
+# If you want to use the VJTAG TAP, you must set your FPGA TAP ID here
+set FPGATAPID 0x020b30dd
+# Choose your TAP core (VJTAG or MOHOR)
+set TAP_TYPE VJTAG
+# Set your chip name
+set CHIPNAME or1200
+
+source [find target/or1k.cfg]
+
+# Set the adapter speed
+adapter_khz 3000
+
+# Enable the target description feature
+gdb_target_description enable
+
+# Add a new register in the cpu register list. This register will be
+# included in the generated target descriptor file.
+# format is addreg [name] [address] [feature] [reg_group]
+addreg rtest 0x1234 org.gnu.gdb.or1k.group0 system
+
+# Override default init_reset
+proc init_reset {mode} {
+       soft_reset_halt
+       resume
+}
+
+# Target initialization
+init
+echo "Halting processor"
+halt
+
+foreach name [target names] {
+       set y [$name cget -endian]
+       set z [$name cget -type]
+       puts [format "Chip is %s, Endian: %s, type: %s" \
+             $name $y $z]
+}
+
+set c_blue  "\033\[01;34m"
+set c_reset "\033\[0m"
+
+puts [format "%sTarget ready...%s" $c_blue $c_reset]
diff --git a/tcl/target/or1k.cfg b/tcl/target/or1k.cfg
new file mode 100644 (file)
index 0000000..84514ef
--- /dev/null
@@ -0,0 +1,53 @@
+set  _ENDIAN big
+
+if { [info exists CHIPNAME] } {
+   set _CHIPNAME $CHIPNAME
+} else {
+   set _CHIPNAME or1k
+}
+
+if { [info exists TAP_TYPE] } {
+   set _TAP_TYPE $TAP_TYPE
+} else {
+   puts "You need to select a tap type"
+   shutdown
+}
+
+# Configure the target
+if { [string compare $_TAP_TYPE "VJTAG"] == 0 } {
+       if { [info exists FPGATAPID] } {
+          set _FPGATAPID $FPGATAPID
+       } else {
+          puts "You need to set your FPGA JTAG ID"
+               shutdown
+       }
+
+       jtag newtap $_CHIPNAME cpu -irlen 10 -expected-id $_FPGATAPID
+
+       set _TARGETNAME $_CHIPNAME.cpu
+       target create $_TARGETNAME or1k -endian $_ENDIAN -chain-position $_TARGETNAME
+
+       # Select the TAP core we are using
+       tap_select vjtag
+} else {
+       # OpenCores Mohor JTAG TAP ID
+       set _CPUTAPID  0x14951185
+
+       jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID
+
+       set _TARGETNAME $_CHIPNAME.cpu
+       target create $_TARGETNAME or1k -endian $_ENDIAN -chain-position $_TARGETNAME
+
+       # Select the TAP core we are using
+       tap_select mohor
+}
+
+# Select the debug unit core we are using. This debug unit as an option.
+
+proc ADBG_USE_HISPEED {}       { return 1 }
+
+# If ADBG_USE_HISPEED is set (options bit 1), status bits will be skipped
+# on burst reads and writes to improve download speeds.
+# This option must match the RTL configured option.
+
+du_select adv [ADBG_USE_HISPEED]