Add new target type: OpenRISC 47/1547/16
authorFranck Jullien <franck.jullien@gmail.com>
Thu, 8 Aug 2013 21:45:47 +0000 (23:45 +0200)
committerSpencer Oliver <spen@spen-soft.co.uk>
Thu, 26 Sep 2013 09:52:56 +0000 (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 7e475e731b005da9f844843d93fcf5027ae2da75..b713a30721bd7aa0df52a445c9c8ee67438aba7e 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 4caefb8c899e3b6d4812d084eb06ee39655b02d2..003ec4ff6284cd924702b72979621a7291c17936 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 5defcda4c7c9ad835e88b666c09b8d6f0e97e63c..6fe3664a7fa09e1b94d1bf31623551e2fdad3a63 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 c2d643b13e44e8a9b9d6a2a54bc3081a5b1e7201..5b86c5f4d38a077240c17d33be64982bb12dd2b0 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 027cc8e7308389c5710ae75306a48f2bba3a1dda..1560753664254b2a4cdc97a7d21be34152b92659 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 4a8d9aaafb91b2c5b183f309d59f003af524845f..0eb578828e962f99e7d160ff431b2966c14f443d 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]

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)