mips: Add MIPS64 support 21/2321/28
authorPeter Mamonov <pmamonov@gmail.com>
Tue, 23 Sep 2014 08:46:02 +0000 (12:46 +0400)
committerPaul Fertser <fercerpav@gmail.com>
Thu, 28 Nov 2019 16:59:15 +0000 (16:59 +0000)
The patch adds support for processors implementing MIPS64 instruction set.

Change-Id: I79a983dfdead81553457a0f3e9e739a9785afaac
Signed-off-by: Konstantin Kostyukhin <kost@niisi.msk.ru>
Signed-off-by: Andrey Sidorov <anysidorov@gmail.com>
Signed-off-by: Aleksey Kuleshov <rndfax@yandex.ru>
Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
Signed-off-by: Peter Mamonov <pmamonov@gmail.com>
Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
CC: Dongxue Zhang <elta.era@gmail.com>
CC: Paul Fertser <fercerpav@gmail.com>
CC: Salvador Arroyo <sarroyofdez@yahoo.es>
CC: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-on: http://openocd.zylin.com/2321
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
src/target/Makefile.am
src/target/mips64.c [new file with mode: 0644]
src/target/mips64.h [new file with mode: 0644]
src/target/mips64_pracc.c [new file with mode: 0644]
src/target/mips64_pracc.h [new file with mode: 0644]
src/target/mips_ejtag.c
src/target/mips_ejtag.h

index afa5f49..2a7cc4b 100644 (file)
@@ -32,6 +32,7 @@ noinst_LTLIBRARIES += %D%/libtarget.la
 
 if TARGET64
 %C%_libtarget_la_SOURCES +=$(ARMV8_SRC)
+%C%_libtarget_la_SOURCES +=$(MIPS64_SRC)
 endif
 
 TARGET_CORE_SRC = \
@@ -120,6 +121,13 @@ MIPS32_SRC = \
        %D%/mips32_dmaacc.c \
        %D%/mips_ejtag.c
 
+MIPS64_SRC = \
+       %D%/mips64.c \
+       %D%/mips32_pracc.c \
+       %D%/mips64_pracc.c \
+       %D%/trace.c \
+       %D%/mips_ejtag.c
+
 NDS32_SRC = \
        %D%/nds32.c \
        %D%/nds32_reg.c \
@@ -193,10 +201,12 @@ ESIRISC_SRC = \
        %D%/etm_dummy.h \
        %D%/image.h \
        %D%/mips32.h \
+       %D%/mips64.h \
        %D%/mips_m4k.h \
        %D%/mips_ejtag.h \
        %D%/mips32_pracc.h \
        %D%/mips32_dmaacc.h \
+       %D%/mips64_pracc.h \
        %D%/oocd_trace.h \
        %D%/register.h \
        %D%/target.h \
diff --git a/src/target/mips64.c b/src/target/mips64.c
new file mode 100644 (file)
index 0000000..f65aec1
--- /dev/null
@@ -0,0 +1,627 @@
+/*
+ * Support for processors implementing MIPS64 instruction set
+ *
+ * Copyright (C) 2014 by Andrey Sidorov <anysidorov@gmail.com>
+ * Copyright (C) 2014 by Aleksey Kuleshov <rndfax@yandex.ru>
+ * Copyright (C) 2014 by Antony Pavlov <antonynpavlov@gmail.com>
+ * Copyright (C) 2014 by Peter Mamonov <pmamonov@gmail.com>
+ *
+ * Based on the work of:
+ *   Copyright (C) 2008 by Spencer Oliver
+ *   Copyright (C) 2008 by David T.L. Wong
+ *   Copyright (C) 2010 by Konstantin Kostyukhin, Nikolay Shmyrev
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if BUILD_TARGET64 == 1
+
+#include "mips64.h"
+
+static const struct {
+       unsigned id;
+       const char *name;
+       enum reg_type type;
+       const char *group;
+       const char *feature;
+       int flag;
+} mips64_regs[] = {
+       {  0,  "r0", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       {  1,  "r1", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       {  2,  "r2", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       {  3,  "r3", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       {  4,  "r4", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       {  5,  "r5", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       {  6,  "r6", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       {  7,  "r7", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       {  8,  "r8", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       {  9,  "r9", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       { 10, "r10", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       { 11, "r11", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       { 12, "r12", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       { 13, "r13", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       { 14, "r14", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       { 15, "r15", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       { 16, "r16", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       { 17, "r17", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       { 18, "r18", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       { 19, "r19", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       { 20, "r20", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       { 21, "r21", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       { 22, "r22", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       { 23, "r23", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       { 24, "r24", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       { 25, "r25", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       { 26, "r26", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       { 27, "r27", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       { 28, "r28", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       { 29, "r29", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       { 30, "r30", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       { 31, "r31", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       { 32, "lo", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       { 33, "hi", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
+       { MIPS64_NUM_CORE_REGS + 0, "pc", REG_TYPE_UINT64, NULL,
+               "org.gnu.gdb.mips.cpu", 0 },
+       { MIPS64_NUM_CORE_REGS + 1, "Random", REG_TYPE_UINT32, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 2, "Entrylo_0", REG_TYPE_UINT64, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 3, "Entrylo_1", REG_TYPE_UINT64, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 4, "Context", REG_TYPE_UINT64, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 5, "Pagemask", REG_TYPE_UINT32, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 6, "Wired", REG_TYPE_UINT32, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 7, "badvaddr", REG_TYPE_UINT64, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 8, "Count", REG_TYPE_UINT32, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 9, "EntryHi", REG_TYPE_UINT64, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 10, "Compare", REG_TYPE_UINT32, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 11, "status", REG_TYPE_UINT32, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 12, "cause", REG_TYPE_UINT32, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 13, "EPC", REG_TYPE_UINT64, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 14, "PrID", REG_TYPE_UINT32, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 15, "Config", REG_TYPE_UINT32, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 16, "LLA", REG_TYPE_UINT32, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 17, "WatchLo0", REG_TYPE_UINT64, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 18, "WatchLo1", REG_TYPE_UINT64, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 19, "WatchHi0", REG_TYPE_UINT32, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 20, "WatchHi1", REG_TYPE_UINT32, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 21, "Xcontext", REG_TYPE_UINT64, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 22, "ChipMemCtrl", REG_TYPE_UINT32, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 23, "Debug", REG_TYPE_UINT32, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 24, "Perfcount, sel=0", REG_TYPE_UINT32, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 25, "Perfcount, sel=1", REG_TYPE_UINT64, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 26, "Perfcount, sel=2", REG_TYPE_UINT32, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 27, "Perfcount, sel=3", REG_TYPE_UINT64, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 28, "ECC", REG_TYPE_UINT32, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 29, "CacheErr", REG_TYPE_UINT32, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 30, "TagLo", REG_TYPE_UINT32, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 31, "TagHi", REG_TYPE_UINT32, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 32, "DataHi", REG_TYPE_UINT64, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_REGS + 33, "EEPC", REG_TYPE_UINT64, NULL,
+               "org.gnu.gdb.mips.cp0", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 0,  "f0", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 1,  "f1", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 2,  "f2", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 3,  "f3", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 4, "f4", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 5,  "f5", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 6,  "f6", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 7,  "f7", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 8,  "f8", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 9,  "f9", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 10, "f10", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 11, "f11", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 12, "f12", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 13, "f13", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 14, "f14", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 15, "f15", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 16, "f16", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 17, "f17", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 18, "f18", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 19, "f19", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 20, "f20", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 21, "f21", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 22, "f22", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 23, "f23", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 24, "f24", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 25, "f25", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 26, "f26", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 27, "f27", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 28, "f28", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 29, "f29", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 30, "f30", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 31, "f31", REG_TYPE_IEEE_DOUBLE, NULL,
+                "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 32, "fcsr", REG_TYPE_INT, "float",
+               "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 33, "fir", REG_TYPE_INT, "float",
+               "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 34, "fconfig", REG_TYPE_INT, "float",
+               "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 35, "fccr", REG_TYPE_INT, "float",
+               "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 36, "fexr", REG_TYPE_INT, "float",
+               "org.gnu.gdb.mips.fpu", 0 },
+       { MIPS64_NUM_CORE_C0_REGS + 37, "fenr", REG_TYPE_INT, "float",
+               "org.gnu.gdb.mips.fpu", 0 },
+};
+
+static int reg_type2size(enum reg_type type)
+{
+       switch (type) {
+       case REG_TYPE_UINT32:
+       case REG_TYPE_INT:
+               return 32;
+       case REG_TYPE_UINT64:
+       case REG_TYPE_IEEE_DOUBLE:
+               return 64;
+       default:
+               return 64;
+       }
+}
+
+static int mips64_get_core_reg(struct reg *reg)
+{
+       int retval;
+       struct mips64_core_reg *mips64_reg = reg->arch_info;
+       struct target *target = mips64_reg->target;
+       struct mips64_common *mips64_target = target->arch_info;
+
+       if (target->state != TARGET_HALTED)
+               return ERROR_TARGET_NOT_HALTED;
+
+       retval = mips64_target->read_core_reg(target, mips64_reg->num);
+
+       return retval;
+}
+
+static int mips64_set_core_reg(struct reg *reg, uint8_t *buf)
+{
+       struct mips64_core_reg *mips64_reg = reg->arch_info;
+       struct target *target = mips64_reg->target;
+       uint64_t value = buf_get_u64(buf, 0, 64);
+
+       if (target->state != TARGET_HALTED)
+               return ERROR_TARGET_NOT_HALTED;
+
+       buf_set_u64(reg->value, 0, 64, value);
+       reg->dirty = 1;
+       reg->valid = 1;
+
+       return ERROR_OK;
+}
+
+static int mips64_read_core_reg(struct target *target, int num)
+{
+       uint64_t reg_value;
+
+       /* get pointers to arch-specific information */
+       struct mips64_common *mips64 = target->arch_info;
+
+       if ((num < 0) || (num >= MIPS64_NUM_REGS))
+               return ERROR_COMMAND_ARGUMENT_INVALID;
+
+       reg_value = mips64->core_regs[num];
+       buf_set_u64(mips64->core_cache->reg_list[num].value, 0, 64, reg_value);
+       mips64->core_cache->reg_list[num].valid = 1;
+       mips64->core_cache->reg_list[num].dirty = 0;
+
+       return ERROR_OK;
+}
+
+static int mips64_write_core_reg(struct target *target, int num)
+{
+       uint64_t reg_value;
+
+       /* get pointers to arch-specific information */
+       struct mips64_common *mips64 = target->arch_info;
+
+       if ((num < 0) || (num >= MIPS64_NUM_REGS))
+               return ERROR_COMMAND_ARGUMENT_INVALID;
+
+       reg_value = buf_get_u64(mips64->core_cache->reg_list[num].value, 0, 64);
+       mips64->core_regs[num] = reg_value;
+       LOG_DEBUG("write core reg %i value 0x%" PRIx64 "", num , reg_value);
+       mips64->core_cache->reg_list[num].valid = 1;
+       mips64->core_cache->reg_list[num].dirty = 0;
+
+       return ERROR_OK;
+}
+
+int mips64_invalidate_core_regs(struct target *target)
+{
+       /* get pointers to arch-specific information */
+       struct mips64_common *mips64 = target->arch_info;
+       unsigned int i;
+
+       for (i = 0; i < mips64->core_cache->num_regs; i++) {
+               mips64->core_cache->reg_list[i].valid = 0;
+               mips64->core_cache->reg_list[i].dirty = 0;
+       }
+
+       return ERROR_OK;
+}
+
+
+int mips64_get_gdb_reg_list(struct target *target, struct reg **reg_list[],
+       int *reg_list_size, enum target_register_class reg_class)
+{
+       /* get pointers to arch-specific information */
+       struct mips64_common *mips64 = target->arch_info;
+       register int i;
+
+       /* include floating point registers */
+       *reg_list_size = MIPS64_NUM_REGS;
+       *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
+
+       for (i = 0; i < MIPS64_NUM_REGS; i++)
+               (*reg_list)[i] = &mips64->core_cache->reg_list[i];
+
+       return ERROR_OK;
+}
+
+int mips64_save_context(struct target *target)
+{
+       int retval;
+       struct mips64_common *mips64 = target->arch_info;
+       struct mips_ejtag *ejtag_info = &mips64->ejtag_info;
+
+       retval = mips64_pracc_read_regs(ejtag_info, mips64->core_regs);
+       if (retval != ERROR_OK)
+               return retval;
+
+       for (unsigned i = 0; i < MIPS64_NUM_REGS; i++)
+                       retval = mips64->read_core_reg(target, i);
+
+       return retval;
+}
+
+int mips64_restore_context(struct target *target)
+{
+       struct mips64_common *mips64 = target->arch_info;
+       struct mips_ejtag *ejtag_info = &mips64->ejtag_info;
+
+       for (unsigned i = 0; i < MIPS64_NUM_REGS; i++) {
+               if (mips64->core_cache->reg_list[i].dirty)
+                       mips64->write_core_reg(target, i);
+       }
+
+       return mips64_pracc_write_regs(ejtag_info, mips64->core_regs);
+}
+
+int mips64_arch_state(struct target *target)
+{
+       struct mips64_common *mips64 = target->arch_info;
+       struct reg *pc = &mips64->core_cache->reg_list[MIPS64_PC];
+
+       if (mips64->common_magic != MIPS64_COMMON_MAGIC) {
+               LOG_ERROR("BUG: called for a non-MIPS64 target");
+               exit(-1);
+       }
+
+       LOG_USER("target halted due to %s, pc: 0x%" PRIx64 "",
+                debug_reason_name(target), buf_get_u64(pc->value, 0, 64));
+
+       return ERROR_OK;
+}
+
+static const struct reg_arch_type mips64_reg_type = {
+       .get = mips64_get_core_reg,
+       .set = mips64_set_core_reg,
+};
+
+int mips64_build_reg_cache(struct target *target)
+{
+       /* get pointers to arch-specific information */
+       struct mips64_common *mips64 = target->arch_info;
+       struct reg_cache **cache_p, *cache;
+       struct mips64_core_reg *arch_info = NULL;
+       struct reg *reg_list = NULL;
+       unsigned i;
+
+       cache = calloc(1, sizeof(*cache));
+       if (!cache) {
+               LOG_ERROR("unable to allocate cache");
+               return ERROR_FAIL;
+       }
+
+       reg_list = calloc(MIPS64_NUM_REGS, sizeof(*reg_list));
+       if (!reg_list) {
+               LOG_ERROR("unable to allocate reg_list");
+               goto alloc_fail;
+       }
+
+       arch_info = calloc(MIPS64_NUM_REGS, sizeof(*arch_info));
+       if (!arch_info) {
+               LOG_ERROR("unable to allocate arch_info");
+               goto alloc_fail;
+       }
+
+       for (i = 0; i < MIPS64_NUM_REGS; i++) {
+               struct mips64_core_reg *a = &arch_info[i];
+               struct reg *r = &reg_list[i];
+
+               r->arch_info = &arch_info[i];
+               r->caller_save = true;  /* gdb defaults to true */
+               r->exist = true;
+               r->feature = &a->feature;
+               r->feature->name = mips64_regs[i].feature;
+               r->group = mips64_regs[i].group;
+               r->name = mips64_regs[i].name;
+               r->number = i;
+               r->reg_data_type = &a->reg_data_type;
+               r->reg_data_type->type = mips64_regs[i].type;
+               r->size = reg_type2size(mips64_regs[i].type);
+               r->type = &mips64_reg_type;
+               r->value = &a->value[0];
+
+               a->mips64_common = mips64;
+               a->num = mips64_regs[i].id;
+               a->target = target;
+       }
+
+       cache->name = "mips64 registers";
+       cache->reg_list = reg_list;
+       cache->num_regs = MIPS64_NUM_REGS;
+
+       cache_p = register_get_last_cache_p(&target->reg_cache);
+       (*cache_p) = cache;
+
+       mips64->core_cache = cache;
+
+       return ERROR_OK;
+
+alloc_fail:
+       free(cache);
+       free(reg_list);
+       free(arch_info);
+
+       return ERROR_FAIL;
+}
+
+int mips64_init_arch_info(struct target *target, struct mips64_common *mips64,
+                         struct jtag_tap *tap)
+{
+       mips64->bp_scanned = false;
+       mips64->common_magic = MIPS64_COMMON_MAGIC;
+       mips64->data_break_list = NULL;
+       mips64->ejtag_info.tap = tap;
+       mips64->fast_data_area = NULL;
+       mips64->mips64mode32 = false;
+       mips64->read_core_reg = mips64_read_core_reg;
+       mips64->write_core_reg = mips64_write_core_reg;
+
+       return ERROR_OK;
+}
+
+int mips64_run_algorithm(struct target *target, int num_mem_params,
+                        struct mem_param *mem_params, int num_reg_params,
+                        struct reg_param *reg_params, target_addr_t entry_point,
+                        target_addr_t exit_point, int timeout_ms, void *arch_info)
+{
+       /* TODO */
+       return ERROR_OK;
+}
+
+int mips64_examine(struct target *target)
+{
+       struct mips64_common *mips64 = target->arch_info;
+
+       if (target_was_examined(target))
+               return ERROR_OK;
+
+       /* TODO: why we do not do mips64_configure_break_unit() here? */
+       mips64->bp_scanned = false;
+       mips64->num_data_bpoints = 0;
+       mips64->num_data_bpoints_avail = 0;
+       mips64->num_inst_bpoints = 0;
+       mips64->num_inst_bpoints_avail = 0;
+
+       target_set_examined(target);
+
+       return ERROR_OK;
+}
+
+static int mips64_configure_i_break_unit(struct target *target)
+{
+       /* get pointers to arch-specific information */
+       struct mips64_common *mips64 = target->arch_info;
+       struct mips64_comparator *ibl;
+       uint64_t bpinfo;
+       int retval;
+       int i;
+
+       /* get number of inst breakpoints */
+       retval = target_read_u64(target, EJTAG64_V25_IBS, &bpinfo);
+       if (retval != ERROR_OK)
+               return retval;
+
+       mips64->num_inst_bpoints = (bpinfo >> 24) & 0x0F;
+       mips64->num_inst_bpoints_avail = mips64->num_inst_bpoints;
+       ibl = calloc(mips64->num_inst_bpoints, sizeof(*ibl));
+       if (!ibl) {
+               LOG_ERROR("unable to allocate inst_break_list");
+               return ERROR_FAIL;
+       }
+
+       for (i = 0; i < mips64->num_inst_bpoints; i++)
+               ibl[i].reg_address = EJTAG64_V25_IBA0 + (0x100 * i);
+
+       mips64->inst_break_list = ibl;
+       /* clear IBIS reg */
+       retval = target_write_u64(target, EJTAG64_V25_IBS, 0);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return ERROR_OK;
+}
+
+static int mips64_configure_d_break_unit(struct target *target)
+{
+       struct mips64_common *mips64 = target->arch_info;
+       struct mips64_comparator *dbl;
+       uint64_t bpinfo;
+       int retval;
+       int i;
+
+       /* get number of data breakpoints */
+       retval = target_read_u64(target, EJTAG64_V25_DBS, &bpinfo);
+       if (retval != ERROR_OK)
+               return retval;
+
+       mips64->num_data_bpoints = (bpinfo >> 24) & 0x0F;
+       mips64->num_data_bpoints_avail = mips64->num_data_bpoints;
+
+       dbl = calloc(mips64->num_data_bpoints, sizeof(*dbl));
+
+       if (!dbl) {
+               LOG_ERROR("unable to allocate data_break_list");
+               return ERROR_FAIL;
+       }
+
+       for (i = 0; i < mips64->num_data_bpoints; i++)
+               dbl[i].reg_address = EJTAG64_V25_DBA0 + (0x100 * i);
+
+       mips64->data_break_list = dbl;
+
+       /* clear DBIS reg */
+       retval = target_write_u64(target, EJTAG64_V25_DBS, 0);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return ERROR_OK;
+}
+
+int mips64_configure_break_unit(struct target *target)
+{
+       struct mips64_common *mips64 = target->arch_info;
+       uint64_t dcr;
+       int retval;
+
+       if (mips64->bp_scanned)
+               return ERROR_OK;
+
+       /* get info about breakpoint support */
+       retval = target_read_u64(target, EJTAG64_DCR, &dcr);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (dcr & EJTAG64_DCR_IB) {
+               retval = mips64_configure_i_break_unit(target);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       if (dcr & EJTAG64_DCR_DB) {
+               retval = mips64_configure_d_break_unit(target);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       LOG_DEBUG("DCR 0x%" PRIx64 " numinst %i numdata %i", dcr,
+                 mips64->num_inst_bpoints, mips64->num_data_bpoints);
+
+       mips64->bp_scanned = true;
+
+       return ERROR_OK;
+}
+
+int mips64_enable_interrupts(struct target *target, bool enable)
+{
+       int retval;
+       bool update = false;
+       uint64_t dcr;
+
+       /* read debug control register */
+       retval = target_read_u64(target, EJTAG64_DCR, &dcr);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (enable) {
+               if (!(dcr & EJTAG64_DCR_INTE)) {
+                       /* enable interrupts */
+                       dcr |= EJTAG64_DCR_INTE;
+                       update = true;
+               }
+       } else {
+               if (dcr & EJTAG64_DCR_INTE) {
+                       /* disable interrupts */
+                       dcr &= ~(uint64_t)EJTAG64_DCR_INTE;
+                       update = true;
+               }
+       }
+
+       if (update) {
+               retval = target_write_u64(target, EJTAG64_DCR, dcr);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       return ERROR_OK;
+}
+
+#endif /* BUILD_TARGET64 */
diff --git a/src/target/mips64.h b/src/target/mips64.h
new file mode 100644 (file)
index 0000000..3453e4e
--- /dev/null
@@ -0,0 +1,226 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Support for processors implementing MIPS64 instruction set
+ *
+ * Copyright (C) 2014 by Andrey Sidorov <anysidorov@gmail.com>
+ * Copyright (C) 2014 by Aleksey Kuleshov <rndfax@yandex.ru>
+ * Copyright (C) 2014-2019 by Peter Mamonov <pmamonov@gmail.com>
+ *
+ * Based on the work of:
+ *     Copyright (C) 2008 by Spencer Oliver
+ *     Copyright (C) 2008 by David T.L. Wong
+ *     Copyright (C) 2010 by Konstantin Kostyukhin, Nikolay Shmyrev
+ */
+
+#ifndef OPENOCD_TARGET_MIPS64_H
+#define OPENOCD_TARGET_MIPS64_H
+
+#include "target.h"
+#include "register.h"
+#include "mips64_pracc.h"
+
+#define MIPS64_COMMON_MAGIC            0xB640B640
+
+/* MIPS64 CP0 registers */
+#define MIPS64_C0_INDEX                0
+#define MIPS64_C0_RANDOM       1
+#define MIPS64_C0_ENTRYLO0     2
+#define MIPS64_C0_ENTRYLO1     3
+#define MIPS64_C0_CONTEXT      4
+#define MIPS64_C0_PAGEMASK     5
+#define MIPS64_C0_WIRED                6
+#define MIPS64_C0_BADVADDR     8
+#define MIPS64_C0_COUNT                9
+#define MIPS64_C0_ENTRYHI      10
+#define MIPS64_C0_COMPARE      11
+#define MIPS64_C0_STATUS       12
+#define MIPS64_C0_CAUSE                13
+#define MIPS64_C0_EPC          14
+#define MIPS64_C0_PRID         15
+#define MIPS64_C0_CONFIG       16
+#define MIPS64_C0_LLA          17
+#define MIPS64_C0_WATCHLO      18
+#define MIPS64_C0_WATCHHI      19
+#define MIPS64_C0_XCONTEXT     20
+#define MIPS64_C0_MEMCTRL      22
+#define MIPS64_C0_DEBUG                23
+#define MIPS64_C0_DEPC         24
+#define MIPS64_C0_PERFCOUNT    25
+#define MIPS64_C0_ECC          26
+#define MIPS64_C0_CACHERR      27
+#define MIPS64_C0_TAGLO                28
+#define MIPS64_C0_TAGHI                29
+#define MIPS64_C0_DATAHI       29
+#define MIPS64_C0_EEPC         30
+
+/* MIPS64 CP1 registers */
+#define MIPS64_C1_FIR          0
+#define MIPS64_C1_FCONFIG      24
+#define MIPS64_C1_FCSR         31
+#define MIPS64_C1_FCCR         25
+#define MIPS64_C1_FEXR         26
+#define MIPS64_C1_FENR         28
+
+/* offsets into mips64 register cache */
+#define MIPS64_NUM_CORE_REGS   34
+#define MIPS64_NUM_C0_REGS     34
+#define MIPS64_NUM_FP_REGS     38
+
+#define MIPS64_NUM_REGS                (MIPS64_NUM_CORE_REGS + \
+                                MIPS64_NUM_C0_REGS + \
+                                MIPS64_NUM_FP_REGS)
+
+#define MIPS64_NUM_CORE_C0_REGS        (MIPS64_NUM_CORE_REGS + MIPS64_NUM_C0_REGS)
+
+#define MIPS64_PC              MIPS64_NUM_CORE_REGS
+
+struct mips64_comparator {
+       bool used;
+       uint64_t bp_value;
+       uint64_t reg_address;
+};
+
+struct mips64_common {
+       uint32_t common_magic;
+       void *arch_info;
+       struct reg_cache *core_cache;
+       struct mips_ejtag ejtag_info;
+       uint64_t core_regs[MIPS64_NUM_REGS];
+
+       struct working_area *fast_data_area;
+
+       bool bp_scanned;
+       int num_inst_bpoints;
+       int num_data_bpoints;
+       int num_inst_bpoints_avail;
+       int num_data_bpoints_avail;
+       struct mips64_comparator *inst_break_list;
+       struct mips64_comparator *data_break_list;
+
+       /* register cache to processor synchronization */
+       int (*read_core_reg)(struct target *target, int num);
+       int (*write_core_reg)(struct target *target, int num);
+
+       bool mips64mode32;
+};
+
+struct mips64_core_reg {
+       uint32_t num;
+       struct target *target;
+       struct mips64_common *mips64_common;
+       uint8_t value[8];
+       struct reg_feature feature;
+       struct reg_data_type reg_data_type;
+};
+
+#define MIPS64_OP_SRL  0x02
+#define MIPS64_OP_BEQ  0x04
+#define MIPS64_OP_BNE  0x05
+#define MIPS64_OP_ADDI 0x08
+#define MIPS64_OP_ANDI 0x0c
+#define MIPS64_OP_DADDI        0x18
+#define MIPS64_OP_DADDIU       0x19
+#define MIPS64_OP_AND  0x24
+#define MIPS64_OP_LUI  0x0F
+#define MIPS64_OP_LW   0x23
+#define MIPS64_OP_LD   0x37
+#define MIPS64_OP_LBU  0x24
+#define MIPS64_OP_LHU  0x25
+#define MIPS64_OP_MFHI 0x10
+#define MIPS64_OP_MTHI 0x11
+#define MIPS64_OP_MFLO 0x12
+#define MIPS64_OP_MTLO 0x13
+#define MIPS64_OP_SB   0x28
+#define MIPS64_OP_SH   0x29
+#define MIPS64_OP_SW   0x2B
+#define MIPS64_OP_SD   0x3F
+#define MIPS64_OP_ORI  0x0D
+#define MIPS64_OP_JR   0x08
+
+#define MIPS64_OP_COP0 0x10
+#define MIPS64_OP_COP1 0x11
+#define MIPS64_OP_COP2 0x12
+
+#define MIPS64_COP_MF  0x00
+#define MIPS64_COP_DMF 0x01
+#define MIPS64_COP_MT  0x04
+#define MIPS64_COP_DMT 0x05
+#define MIPS64_COP_CF  0x02
+#define MIPS64_COP_CT  0x06
+
+#define MIPS64_R_INST(opcode, rs, rt, rd, shamt, funct) \
+(((opcode) << 26) | ((rs) << 21) | ((rt) << 16) | ((rd) << 11) | ((shamt) << 6) | (funct))
+#define MIPS64_I_INST(opcode, rs, rt, immd)    (((opcode) << 26) | ((rs) << 21) | ((rt) << 16) | (immd))
+#define MIPS64_J_INST(opcode, addr)    (((opcode) << 26) | (addr))
+
+#define MIPS64_NOP                     0
+#define MIPS64_ADDI(tar, src, val)     MIPS64_I_INST(MIPS64_OP_ADDI, src, tar, val)
+#define MIPS64_DADDI(tar, src, val)    MIPS64_I_INST(MIPS64_OP_DADDI, src, tar, val)
+#define MIPS64_DADDIU(tar, src, val)   MIPS64_I_INST(MIPS64_OP_DADDIU, src, tar, val)
+#define MIPS64_AND(reg, off, val)      MIPS64_R_INST(0, off, val, reg, 0, MIPS64_OP_AND)
+#define MIPS64_ANDI(d, s, im)          MIPS64_I_INST(MIPS64_OP_ANDI, s, d, im)
+#define MIPS64_SRL(d, w, sh)           MIPS64_R_INST(0, 0, w, d, sh, MIPS64_OP_SRL)
+#define MIPS64_B(off)                  MIPS64_BEQ(0, 0, off)
+#define MIPS64_BEQ(src, tar, off)      MIPS64_I_INST(MIPS64_OP_BEQ, src, tar, off)
+#define MIPS64_BNE(src, tar, off)      MIPS64_I_INST(MIPS64_OP_BNE, src, tar, off)
+#define MIPS64_MFC0(gpr, cpr, sel)     MIPS64_R_INST(MIPS64_OP_COP0, MIPS64_COP_MF, gpr, cpr, 0, sel)
+#define MIPS64_DMFC0(gpr, cpr, sel)    MIPS64_R_INST(MIPS64_OP_COP0, MIPS64_COP_DMF, gpr, cpr, 0, sel)
+#define MIPS64_MTC0(gpr, cpr, sel)     MIPS64_R_INST(MIPS64_OP_COP0, MIPS64_COP_MT, gpr, cpr, 0, sel)
+#define MIPS64_DMTC0(gpr, cpr, sel)    MIPS64_R_INST(MIPS64_OP_COP0, MIPS64_COP_DMT, gpr, cpr, 0, sel)
+#define MIPS64_MFC1(gpr, cpr, sel)     MIPS64_R_INST(MIPS64_OP_COP1, MIPS64_COP_MF, gpr, cpr, 0, 0)
+#define MIPS64_DMFC1(gpr, cpr, sel)    MIPS64_R_INST(MIPS64_OP_COP1, MIPS64_COP_DMF, gpr, cpr, 0, 0)
+#define MIPS64_MTC1(gpr, cpr, sel)     MIPS64_R_INST(MIPS64_OP_COP1, MIPS64_COP_MT, gpr, cpr, 0, 0)
+#define MIPS64_DMTC1(gpr, cpr, sel)    MIPS64_R_INST(MIPS64_OP_COP1, MIPS64_COP_DMT, gpr, cpr, 0, 0)
+#define MIPS64_MFC2(gpr, cpr, sel)     MIPS64_R_INST(MIPS64_OP_COP2, MIPS64_COP_MF, gpr, cpr, 0, sel)
+#define MIPS64_MTC2(gpr, cpr, sel)     MIPS64_R_INST(MIPS64_OP_COP2, MIPS64_COP_MT, gpr, cpr, 0, sel)
+#define MIPS64_CFC1(gpr, cpr, sel)     MIPS64_R_INST(MIPS64_OP_COP1, MIPS64_COP_CF, gpr, cpr, 0, 0)
+#define MIPS64_CTC1(gpr, cpr, sel)     MIPS64_R_INST(MIPS64_OP_COP1, MIPS64_COP_CT, gpr, cpr, 0, 0)
+#define MIPS64_CFC2(gpr, cpr, sel)     MIPS64_R_INST(MIPS64_OP_COP2, MIPS64_COP_CF, gpr, cpr, 0, sel)
+#define MIPS64_CTC2(gpr, cpr, sel)     MIPS64_R_INST(MIPS64_OP_COP2, MIPS64_COP_CT, gpr, cpr, 0, sel)
+#define MIPS64_LBU(reg, off, base)     MIPS64_I_INST(MIPS64_OP_LBU, base, reg, off)
+#define MIPS64_LHU(reg, off, base)     MIPS64_I_INST(MIPS64_OP_LHU, base, reg, off)
+#define MIPS64_LUI(reg, val)           MIPS64_I_INST(MIPS64_OP_LUI, 0, reg, val)
+#define MIPS64_LW(reg, off, base)      MIPS64_I_INST(MIPS64_OP_LW, base, reg, off)
+#define MIPS64_LD(reg, off, base)      MIPS64_I_INST(MIPS64_OP_LD, base, reg, off)
+#define MIPS64_MFLO(reg)               MIPS64_R_INST(0, 0, 0, reg, 0, MIPS64_OP_MFLO)
+#define MIPS64_MFHI(reg)               MIPS64_R_INST(0, 0, 0, reg, 0, MIPS64_OP_MFHI)
+#define MIPS64_MTLO(reg)               MIPS64_R_INST(0, reg, 0, 0, 0, MIPS64_OP_MTLO)
+#define MIPS64_MTHI(reg)               MIPS64_R_INST(0, reg, 0, 0, 0, MIPS64_OP_MTHI)
+#define MIPS64_ORI(src, tar, val)      MIPS64_I_INST(MIPS64_OP_ORI, src, tar, val)
+#define MIPS64_SB(reg, off, base)      MIPS64_I_INST(MIPS64_OP_SB, base, reg, off)
+#define MIPS64_SH(reg, off, base)      MIPS64_I_INST(MIPS64_OP_SH, base, reg, off)
+#define MIPS64_SW(reg, off, base)      MIPS64_I_INST(MIPS64_OP_SW, base, reg, off)
+#define MIPS64_SD(reg, off, base)      MIPS64_I_INST(MIPS64_OP_SD, base, reg, off)
+#define MIPS64_CACHE(op, reg, off)     (47 << 26 | (reg) << 21 | (op) << 16 | (off))
+#define MIPS64_SYNCI(reg, off)         (1 << 26 | (reg) << 21 | 0x1f << 16 | (off))
+#define MIPS64_JR(reg)                 MIPS64_R_INST(0, reg, 0, 0, 0, MIPS64_OP_JR)
+
+/* ejtag specific instructions */
+#define MIPS64_DRET                    0x4200001F
+#define MIPS64_SDBBP                   0x7000003F
+#define MIPS64_SDBBP_LE                        0x3f000007
+#define MIPS64_SDBBP_SIZE              4
+#define MIPS16_SDBBP_SIZE              2
+
+#define MIPS64_SYNC                    0x0000000F
+
+int mips64_arch_state(struct target *target);
+int mips64_init_arch_info(struct target *target, struct mips64_common *mips64, struct jtag_tap *tap);
+int mips64_restore_context(struct target *target);
+int mips64_save_context(struct target *target);
+int mips64_build_reg_cache(struct target *target);
+int mips64_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params,
+       int num_reg_params, struct reg_param *reg_params,
+       target_addr_t entry_point, target_addr_t exit_point,
+       int timeout_ms, void *arch_info);
+int mips64_configure_break_unit(struct target *target);
+int mips64_enable_interrupts(struct target *target, bool enable);
+int mips64_examine(struct target *target);
+
+int mips64_register_commands(struct command_context *cmd_ctx);
+int mips64_invalidate_core_regs(struct target *target);
+int mips64_get_gdb_reg_list(struct target *target,
+       struct reg **reg_list[], int *reg_list_size,
+       enum target_register_class reg_class);
+
+#endif /* OPENOCD_TARGET_MIPS64_H */
diff --git a/src/target/mips64_pracc.c b/src/target/mips64_pracc.c
new file mode 100644 (file)
index 0000000..57addc7
--- /dev/null
@@ -0,0 +1,1431 @@
+/*
+ * Support for processors implementing MIPS64 instruction set
+ *
+ *   Copyright (C) 2014 by Andrey Sidorov <anysidorov@gmail.com>
+ *   Copyright (C) 2014 by Aleksey Kuleshov <rndfax@yandex.ru>
+ *   Copyright (C) 2014-2019 by Peter Mamonov <pmamonov@gmail.com>
+ *
+ *   Based on the work of:
+ *       Copyright (C) 2008 by Spencer Oliver
+ *       Copyright (C) 2008 by David T.L. Wong
+ *       Copyright (C) 2010 by Konstantin Kostyukhin, Nikolay Shmyrev
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if BUILD_TARGET64 == 1
+
+#include "mips64.h"
+#include "mips64_pracc.h"
+
+#include "time_support.h"
+
+#define STACK_DEPTH    32
+
+typedef struct {
+       uint64_t *local_iparam;
+       unsigned num_iparam;
+       uint64_t *local_oparam;
+       unsigned num_oparam;
+       const uint32_t *code;
+       unsigned code_len;
+       uint64_t stack[STACK_DEPTH];
+       unsigned stack_offset;
+       struct mips_ejtag *ejtag_info;
+} mips64_pracc_context;
+
+static int wait_for_pracc_rw(struct mips_ejtag *ejtag_info, uint32_t *ctrl)
+{
+       uint32_t ejtag_ctrl;
+       int nt = 5;
+       int rc;
+
+       while (1) {
+               mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
+               ejtag_ctrl = ejtag_info->ejtag_ctrl;
+               rc = mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
+               if (rc != ERROR_OK)
+                       return rc;
+
+               if (ejtag_ctrl & EJTAG_CTRL_PRACC)
+                       break;
+               LOG_DEBUG("DEBUGMODULE: No memory access in progress!\n");
+               if (nt == 0)
+                       return ERROR_JTAG_DEVICE_ERROR;
+               nt--;
+       }
+
+       *ctrl = ejtag_ctrl;
+       return ERROR_OK;
+}
+
+static int mips64_pracc_exec_read(mips64_pracc_context *ctx, uint64_t address)
+{
+       struct mips_ejtag *ejtag_info = ctx->ejtag_info;
+       unsigned offset;
+       uint32_t ejtag_ctrl;
+       uint64_t data;
+       int rc;
+
+       if ((address >= MIPS64_PRACC_PARAM_IN)
+           && (address < MIPS64_PRACC_PARAM_IN + ctx->num_iparam * MIPS64_PRACC_DATA_STEP)) {
+
+               offset = (address - MIPS64_PRACC_PARAM_IN) / MIPS64_PRACC_DATA_STEP;
+
+               if (offset >= MIPS64_PRACC_PARAM_IN_SIZE) {
+                       LOG_ERROR("Error: iparam size exceeds MIPS64_PRACC_PARAM_IN_SIZE");
+                       return ERROR_JTAG_DEVICE_ERROR;
+               }
+
+               if (ctx->local_iparam == NULL) {
+                       LOG_ERROR("Error: unexpected reading of input parameter");
+                       return ERROR_JTAG_DEVICE_ERROR;
+               }
+
+               data = ctx->local_iparam[offset];
+               LOG_DEBUG("Reading %" PRIx64 " at %" PRIx64, data, address);
+
+       } else if ((address >= MIPS64_PRACC_PARAM_OUT)
+                  && (address < MIPS64_PRACC_PARAM_OUT + ctx->num_oparam * MIPS64_PRACC_DATA_STEP)) {
+
+               offset = (address - MIPS64_PRACC_PARAM_OUT) / MIPS64_PRACC_DATA_STEP;
+               if (ctx->local_oparam == NULL) {
+                       LOG_ERROR("Error: unexpected reading of output parameter");
+                       return ERROR_JTAG_DEVICE_ERROR;
+               }
+
+               data = ctx->local_oparam[offset];
+               LOG_DEBUG("Reading %" PRIx64 " at %" PRIx64, data, address);
+
+       } else if ((address >= MIPS64_PRACC_TEXT)
+                  && (address < MIPS64_PRACC_TEXT + ctx->code_len * MIPS64_PRACC_ADDR_STEP)) {
+
+               offset = ((address & ~7ull) - MIPS64_PRACC_TEXT) / MIPS64_PRACC_ADDR_STEP;
+               data = (uint64_t)ctx->code[offset] << 32;
+               if (offset + 1 < ctx->code_len)
+                       data |= (uint64_t)ctx->code[offset + 1];
+
+               LOG_DEBUG("Running commands %" PRIx64 " at %" PRIx64, data,
+                         address);
+
+       } else if ((address & ~7llu) == MIPS64_PRACC_STACK) {
+
+               /* load from our debug stack */
+               if (ctx->stack_offset == 0) {
+                       LOG_ERROR("Error reading from stack: stack is empty");
+                       return ERROR_JTAG_DEVICE_ERROR;
+               }
+
+               data = ctx->stack[--ctx->stack_offset];
+               LOG_DEBUG("Reading %" PRIx64 " at %" PRIx64, data, address);
+
+       } else {
+               /* TODO: send JMP 0xFF200000 instruction. Hopefully processor jump back
+                * to start of debug vector */
+
+               data = 0;
+               LOG_ERROR("Error reading unexpected address %" PRIx64, address);
+               return ERROR_JTAG_DEVICE_ERROR;
+       }
+
+       /* Send the data out */
+       mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_DATA);
+       rc = mips_ejtag_drscan_64(ctx->ejtag_info, &data);
+       if (rc != ERROR_OK)
+               return rc;
+
+       /* Clear the access pending bit (let the processor eat!) */
+
+       ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC;
+       mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_CONTROL);
+       rc = mips_ejtag_drscan_32(ctx->ejtag_info, &ejtag_ctrl);
+       if (rc != ERROR_OK)
+               return rc;
+
+       jtag_add_clocks(5);
+
+       return jtag_execute_queue();
+}
+
+static int mips64_pracc_exec_write(mips64_pracc_context *ctx, uint64_t address)
+{
+       uint32_t ejtag_ctrl;
+       uint64_t data;
+       unsigned offset;
+       struct mips_ejtag *ejtag_info = ctx->ejtag_info;
+       int rc;
+
+       mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_DATA);
+       rc = mips_ejtag_drscan_64(ctx->ejtag_info, &data);
+       if (rc != ERROR_OK)
+               return rc;
+
+       /* Clear access pending bit */
+       ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC;
+       mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_CONTROL);
+       rc = mips_ejtag_drscan_32(ctx->ejtag_info, &ejtag_ctrl);
+       if (rc != ERROR_OK)
+               return rc;
+
+       jtag_add_clocks(5);
+       rc = jtag_execute_queue();
+       if (rc != ERROR_OK)
+               return rc;
+
+       LOG_DEBUG("Writing %" PRIx64 " at %" PRIx64, data, address);
+
+       if ((address >= MIPS64_PRACC_PARAM_IN)
+               && (address < MIPS64_PRACC_PARAM_IN + ctx->num_iparam * MIPS64_PRACC_DATA_STEP)) {
+               offset = (address - MIPS64_PRACC_PARAM_IN) / MIPS64_PRACC_DATA_STEP;
+               if (ctx->local_iparam == NULL) {
+                       LOG_ERROR("Error: unexpected writing of input parameter");
+                       return ERROR_JTAG_DEVICE_ERROR;
+               }
+               ctx->local_iparam[offset] = data;
+       } else if ((address >= MIPS64_PRACC_PARAM_OUT)
+               && (address < MIPS64_PRACC_PARAM_OUT + ctx->num_oparam * MIPS64_PRACC_DATA_STEP)) {
+               offset = (address - MIPS64_PRACC_PARAM_OUT) / MIPS64_PRACC_DATA_STEP;
+               if (ctx->local_oparam == NULL) {
+                       LOG_ERROR("Error: unexpected writing of output parameter");
+                       return ERROR_JTAG_DEVICE_ERROR;
+               }
+               ctx->local_oparam[offset] = data;
+       } else if (address == MIPS64_PRACC_STACK) {
+               /* save data onto our stack */
+               if (ctx->stack_offset >= STACK_DEPTH) {
+                       LOG_ERROR("Error: PrAcc stack depth exceeded");
+                       return ERROR_FAIL;
+               }
+               ctx->stack[ctx->stack_offset++] = data;
+       } else {
+               LOG_ERROR("Error writing unexpected address 0x%" PRIx64, address);
+               return ERROR_JTAG_DEVICE_ERROR;
+       }
+
+       return ERROR_OK;
+}
+
+int mips64_pracc_exec(struct mips_ejtag *ejtag_info,
+                     unsigned code_len, const uint32_t *code,
+                     unsigned num_param_in, uint64_t *param_in,
+                     unsigned num_param_out, uint64_t *param_out)
+{
+       uint32_t ejtag_ctrl;
+       uint64_t address = 0, address_prev = 0, data;
+       mips64_pracc_context ctx;
+       int retval;
+       int pass = 0;
+       bool first_time_call = true;
+       unsigned i;
+
+       for (i = 0; i < code_len; i++)
+               LOG_DEBUG("%08x", code[i]);
+
+       ctx.local_iparam = param_in;
+       ctx.local_oparam = param_out;
+       ctx.num_iparam = num_param_in;
+       ctx.num_oparam = num_param_out;
+       ctx.code = code;
+       ctx.code_len = code_len;
+       ctx.ejtag_info = ejtag_info;
+       ctx.stack_offset = 0;
+
+       while (true) {
+               uint32_t address32;
+               retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl);
+               if (retval != ERROR_OK) {
+                       LOG_DEBUG("ERROR wait_for_pracc_rw");
+                       return retval;
+               }
+               if (pass)
+                       address_prev = address;
+               else
+                       address_prev = 0;
+               address32 = data = 0;
+
+               mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
+               mips_ejtag_drscan_32(ejtag_info, &address32);
+               LOG_DEBUG("-> %08x", address32);
+               address = 0xffffffffff200000ull | address32;
+
+               int psz = (ejtag_ctrl >> 29) & 3;
+               int address20 = address & 7;
+               switch (psz) {
+               case 3:
+                       if (address20 != 7) {
+                               LOG_ERROR("PSZ=%d ADDRESS[2:0]=%d: not supported", psz, address20);
+                               return ERROR_FAIL;
+                       }
+                       address &= ~7ull;
+                       break;
+               case 2:
+                       if (address20 != 0 && address20 != 4) {
+                               LOG_ERROR("PSZ=%d ADDRESS[2:0]=%d: not supported", psz, address20);
+                               return ERROR_FAIL;
+                       }
+                       break;
+               default:
+                       LOG_ERROR("PSZ=%d ADDRESS[2:0]=%d: not supported", psz, address20);
+                       return ERROR_FAIL;
+               }
+
+               if (first_time_call && address != MIPS64_PRACC_TEXT) {
+                       LOG_ERROR("Error reading address " TARGET_ADDR_FMT " (0x%08llx expected)",
+                               address, MIPS64_PRACC_TEXT);
+                       return ERROR_JTAG_DEVICE_ERROR;
+               }
+
+               first_time_call = false;
+
+               /* Check for read or write */
+               if (ejtag_ctrl & EJTAG_CTRL_PRNW) {
+                       retval = mips64_pracc_exec_write(&ctx, address);
+                       if (retval != ERROR_OK) {
+                               printf("ERROR mips64_pracc_exec_write\n");
+                               return retval;
+                       }
+               } else {
+                       /* Check to see if its reading at the debug vector. The first pass through
+                        * the module is always read at the vector, so the first one we allow.  When
+                        * the second read from the vector occurs we are done and just exit. */
+                       if ((address == MIPS64_PRACC_TEXT) && (pass++)) {
+                               LOG_DEBUG("@MIPS64_PRACC_TEXT, address_prev=%" PRIx64, address_prev);
+                               break;
+                       }
+                       retval = mips64_pracc_exec_read(&ctx, address);
+                       if (retval != ERROR_OK) {
+                               printf("ERROR mips64_pracc_exec_read\n");
+                               return retval;
+                       }
+
+               }
+       }
+
+       /* stack sanity check */
+       if (ctx.stack_offset != 0)
+               LOG_ERROR("Pracc Stack not zero");
+
+       return ERROR_OK;
+}
+
+static int mips64_pracc_read_u64(struct mips_ejtag *ejtag_info, uint64_t addr,
+                                uint64_t *buf)
+{
+       const uint32_t code[] = {
+               /* move $15 to COP0 DeSave */
+               MIPS64_DMTC0(15, 31, 0),
+               /* $15 = MIPS64_PRACC_STACK */
+               MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)),
+               MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)),
+               /* sd $8, ($15) */
+               MIPS64_SD(8, 0, 15),
+               /* load R8 @ param_in[0] = address */
+               MIPS64_LD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN),  15),
+               /* ld $8, 0($8),  Load $8 with the word @mem[$8] */
+               MIPS64_LD(8, 0, 8),
+               /* sd $8, 0($15) */
+               MIPS64_SD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_OUT), 15),
+               /* ld $8, ($15) */
+               MIPS64_LD(8, 0, 15),
+               MIPS64_SYNC,
+               /* b start */
+               MIPS64_B(NEG16(10)),
+               /* move COP0 DeSave to $15 */
+               MIPS64_DMFC0(15, 31, 0),
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+       };
+
+       uint64_t param_in[1];
+       param_in[0] = addr;
+
+       LOG_DEBUG("enter mips64_pracc_exec");
+       return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
+               ARRAY_SIZE(param_in), param_in, 1, (uint64_t *) buf);
+}
+
+static int mips64_pracc_read_mem64(struct mips_ejtag *ejtag_info, uint64_t addr,
+                           unsigned count, uint64_t *buf)
+{
+       int retval = ERROR_OK;
+
+       for (unsigned i = 0; i < count; i++) {
+               retval = mips64_pracc_read_u64(ejtag_info, addr + 8*i, &buf[i]);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+       return retval;
+}
+
+static int mips64_pracc_read_u32(struct mips_ejtag *ejtag_info, uint64_t addr,
+                                uint32_t *buf)
+{
+       const uint32_t code[] = {
+               /* move $15 to COP0 DeSave */
+               MIPS64_DMTC0(15, 31, 0),
+               /* $15 = MIPS64_PRACC_STACK */
+               MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)),
+               MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)),
+               /* sd $8, ($15) */
+               MIPS64_SD(8, 0, 15),
+               /* load R8 @ param_in[0] = address */
+               MIPS64_LD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN),  15),
+               /* lw $8, 0($8),  Load $8 with the word @mem[$8] */
+               MIPS64_LW(8, 0, 8),
+               /* sd $8, 0($9) */
+               MIPS64_SD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_OUT), 15),
+               /* ld $8, ($15) */
+               MIPS64_LD(8, 0, 15),
+               MIPS64_SYNC,
+               /* b start */
+               MIPS64_B(NEG16(10)),
+               /* move COP0 DeSave to $15 */
+               MIPS64_DMFC0(15, 31, 0),
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+       };
+
+       int retval = ERROR_OK;
+       uint64_t param_in[1];
+       uint64_t param_out[1];
+
+       param_in[0] = addr;
+
+       LOG_DEBUG("enter mips64_pracc_exec");
+       retval = mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
+               1, param_in, 1, param_out);
+       buf[0] = (uint32_t) param_out[0];
+       return retval;
+}
+
+static int mips64_pracc_read_mem32(struct mips_ejtag *ejtag_info, uint64_t addr,
+                                  unsigned count, uint32_t *buf)
+{
+       int retval = ERROR_OK;
+
+       for (unsigned i = 0; i < count; i++) {
+               retval = mips64_pracc_read_u32(ejtag_info, addr + 4 * i, &buf[i]);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+       return retval;
+}
+
+static int mips64_pracc_read_u16(struct mips_ejtag *ejtag_info, uint64_t addr,
+                                uint16_t *buf)
+{
+       const uint32_t code[] = {
+               /* move $15 to COP0 DeSave */
+               MIPS64_DMTC0(15, 31, 0),
+               /* $15 = MIPS64_PRACC_STACK */
+               MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)),
+               MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)),
+               /* sd $8, ($15) */
+               MIPS64_SD(8, 0, 15),
+               /* load R8 @ param_in[0] = address */
+               MIPS64_LD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN),  15),
+               /* lw $8, 0($8),  Load $8 with the word @mem[$8] */
+               MIPS64_LHU(8, 0, 8),
+               /* sd $8, 0($9) */
+               MIPS64_SD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_OUT), 15),
+               /* ld $8, ($15) */
+               MIPS64_LD(8, 0, 15),
+               MIPS64_SYNC,
+               /* b start */
+               MIPS64_B(NEG16(10)),
+               /* move COP0 DeSave to $15 */
+               MIPS64_DMFC0(15, 31, 0),
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+       };
+
+       int retval;
+       uint64_t param_in[1];
+       uint64_t param_out[1];
+
+       param_in[0] = addr;
+
+       LOG_DEBUG("enter mips64_pracc_exec");
+       retval = mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
+               1, param_in, 1, param_out);
+       buf[0] = (uint16_t)param_out[0];
+       return retval;
+}
+
+static int mips64_pracc_read_mem16(struct mips_ejtag *ejtag_info, uint64_t addr,
+                           unsigned count, uint16_t *buf)
+{
+       int retval = ERROR_OK;
+
+       for (unsigned i = 0; i < count; i++) {
+               retval = mips64_pracc_read_u16(ejtag_info, addr + 2*i, &buf[i]);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+       return retval;
+}
+
+static int mips64_pracc_read_u8(struct mips_ejtag *ejtag_info, uint64_t addr,
+                               uint8_t *buf)
+{
+       const uint32_t code[] = {
+               /* move $15 to COP0 DeSave */
+               MIPS64_DMTC0(15, 31, 0),
+               /* $15 = MIPS64_PRACC_STACK */
+               MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)),
+               MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)),
+               /* sd $8, ($15) */
+               MIPS64_SD(8, 0, 15),
+               /* load R8 @ param_in[0] = address */
+               MIPS64_LD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN),  15),
+               /* lw $8, 0($8),  Load $8 with the word @mem[$8] */
+               MIPS64_LBU(8, 0, 8),
+               /* sd $8, 0($9) */
+               MIPS64_SD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_OUT), 15),
+               /* ld $8, ($15) */
+               MIPS64_LD(8, 0, 15),
+               MIPS64_SYNC,
+               /* b start */
+               MIPS64_B(NEG16(10)),
+               /* move COP0 DeSave to $15 */
+               MIPS64_DMFC0(15, 31, 0),
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+       };
+
+       int retval;
+       uint64_t param_in[1];
+       uint64_t param_out[1];
+
+       param_in[0] = addr;
+
+       LOG_DEBUG("enter mips64_pracc_exec");
+       retval = mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
+               1, param_in, 1, param_out);
+       buf[0] = (uint8_t)param_out[0];
+       return retval;
+}
+
+static int mips64_pracc_read_mem8(struct mips_ejtag *ejtag_info, uint64_t addr,
+                         unsigned count, uint8_t *buf)
+{
+       int retval = ERROR_OK;
+
+       for (unsigned i = 0; i < count; i++) {
+               retval = mips64_pracc_read_u8(ejtag_info, addr + i, &buf[i]);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+       return retval;
+}
+
+int mips64_pracc_read_mem(struct mips_ejtag *ejtag_info, uint64_t addr,
+                         unsigned size, unsigned count, void *buf)
+{
+       switch (size) {
+       case 1:
+               return mips64_pracc_read_mem8(ejtag_info, addr, count, buf);
+       case 2:
+               return mips64_pracc_read_mem16(ejtag_info, addr, count, buf);
+       case 4:
+               return mips64_pracc_read_mem32(ejtag_info, addr, count, buf);
+       case 8:
+               return mips64_pracc_read_mem64(ejtag_info, addr, count, buf);
+       }
+       return ERROR_FAIL;
+}
+
+static int mips64_pracc_write_u64(struct mips_ejtag *ejtag_info, uint64_t addr,
+                                 uint64_t *buf)
+{
+       const uint32_t code[] = {
+               /* move $15 to COP0 DeSave */
+               MIPS64_DMTC0(15, 31, 0),
+               /* $15 = MIPS64_PRACC_STACK */
+               MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)),
+               MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)),
+               /* sd $8, ($15) */
+               MIPS64_SD(8, 0, 15),
+               /* sd $9, ($15) */
+               MIPS64_SD(9, 0, 15),
+               /* load R8 @ param_in[1] = data */
+               MIPS64_LD(8, NEG16((MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN)-8), 15),
+               /* load R9 @ param_in[0] = address */
+               MIPS64_LD(9, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15),
+               /* sd $8, 0($9) */
+               MIPS64_SD(8, 0, 9),
+               MIPS64_SYNCI(9, 0),
+               /* ld $9, ($15) */
+               MIPS64_LD(9, 0, 15),
+               /* ld $8, ($15) */
+               MIPS64_LD(8, 0, 15),
+               MIPS64_SYNC,
+               /* b start */
+               MIPS64_B(NEG16(13)),
+               /* move COP0 DeSave to $15 */
+               MIPS64_DMFC0(15, 31, 0),
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+       };
+
+       /* TODO remove array */
+       uint64_t param_in[2];
+       param_in[0] = addr;
+       param_in[1] = *buf;
+
+       LOG_DEBUG("enter mips64_pracc_exec");
+       return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
+               ARRAY_SIZE(param_in), param_in, 0, NULL);
+}
+
+static int mips64_pracc_write_mem64(struct mips_ejtag *ejtag_info,
+                            uint64_t addr, unsigned count, uint64_t *buf)
+{
+       int retval = ERROR_OK;
+
+       for (unsigned i = 0; i < count; i++) {
+               retval = mips64_pracc_write_u64(ejtag_info, addr + 8 * i, &buf[i]);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+       return retval;
+}
+
+static int mips64_pracc_write_u32(struct mips_ejtag *ejtag_info, uint64_t addr,
+                                 uint32_t *buf)
+{
+       const uint32_t code[] = {
+               MIPS64_DMTC0(15, 31, 0),
+               /* move $15 to COP0 DeSave */
+               MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)),
+               /* $15 = MIPS64_PRACC_STACK */
+               MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)),
+               MIPS64_SD(8, 0, 15),
+               /* sd $8, ($15) */
+               MIPS64_SD(9, 0, 15),
+               /* sd $9, ($15) */
+               MIPS64_LD(8, NEG16((MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN) - 8), 15),
+               /* load R8 @ param_in[1] = data */
+               MIPS64_LD(9, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15),
+               /* load R9 @ param_in[0] = address */
+               MIPS64_SW(8, 0, 9),
+               /* sw $8, 0($9) */
+               MIPS64_SYNCI(9, 0),
+               MIPS64_LD(9, 0, 15),
+               /* ld $9, ($15) */
+               MIPS64_LD(8, 0, 15),
+               /* ld $8, ($15) */
+               MIPS64_SYNC,
+               MIPS64_B(NEG16(13)),
+               /* b start */
+               MIPS64_DMFC0(15, 31, 0),
+               /* move COP0 DeSave to $15 */
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+       };
+
+       /* TODO remove array */
+       uint64_t param_in[1 + 1];
+       param_in[0] = addr;
+       param_in[1] = *buf;
+
+       LOG_DEBUG("enter mips64_pracc_exec");
+       return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
+               ARRAY_SIZE(param_in), param_in, 0, NULL);
+}
+
+static int mips64_pracc_write_mem32(struct mips_ejtag *ejtag_info, uint64_t addr,
+                            unsigned count, uint32_t *buf)
+{
+       int retval = ERROR_OK;
+
+       for (unsigned i = 0; i < count; i++) {
+               retval = mips64_pracc_write_u32(ejtag_info, addr + 4 * i, &buf[i]);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+       return retval;
+}
+
+static int mips64_pracc_write_u16(struct mips_ejtag *ejtag_info, uint64_t addr,
+                                 uint16_t *buf)
+{
+       const uint32_t code[] = {
+               /* move $15 to COP0 DeSave */
+               MIPS64_DMTC0(15, 31, 0),
+               /* $15 = MIPS64_PRACC_STACK */
+               MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)),
+               MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)),
+               /* sd $8, ($15) */
+               MIPS64_SD(8, 0, 15),
+               /* sd $9, ($15) */
+               MIPS64_SD(9, 0, 15),
+               /* load R8 @ param_in[1] = data */
+               MIPS64_LD(8, NEG16((MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN) - 8), 15),
+               /* load R9 @ param_in[0] = address */
+               MIPS64_LD(9, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15),
+               /* sh $8, 0($9) */
+               MIPS64_SH(8, 0, 9),
+               /* ld $9, ($15) */
+               MIPS64_LD(9, 0, 15),
+               /* ld $8, ($15) */
+               MIPS64_LD(8, 0, 15),
+               MIPS64_SYNC,
+               /* b start */
+               MIPS64_B(NEG16(12)),
+               /* move COP0 DeSave to $15 */
+               MIPS64_DMFC0(15, 31, 0),
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+       };
+
+       uint64_t param_in[2];
+       param_in[0] = addr;
+       param_in[1] = *buf;
+
+       LOG_DEBUG("enter mips64_pracc_exec");
+       return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
+               ARRAY_SIZE(param_in), param_in, 0, NULL);
+}
+
+static int mips64_pracc_write_mem16(struct mips_ejtag *ejtag_info,
+                            uint64_t addr, unsigned count, uint16_t *buf)
+{
+       int retval = ERROR_OK;
+
+       for (unsigned i = 0; i < count; i++) {
+               retval = mips64_pracc_write_u16(ejtag_info, addr + 2 * i, &buf[i]);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+       return retval;
+}
+
+static int mips64_pracc_write_u8(struct mips_ejtag *ejtag_info, uint64_t addr,
+                                uint8_t *buf)
+{
+       const uint32_t code[] = {
+               /* move $15 to COP0 DeSave */
+               MIPS64_DMTC0(15, 31, 0),
+               /* $15 = MIPS64_PRACC_STACK */
+               MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)),
+               MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)),
+               /* sd $8, ($15) */
+               MIPS64_SD(8, 0, 15),
+               /* sd $9, ($15) */
+               MIPS64_SD(9, 0, 15),
+               /* load R8 @ param_in[1] = data */
+               MIPS64_LD(8, NEG16((MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN) - 8), 15),
+               /* load R9 @ param_in[0] = address */
+               MIPS64_LD(9, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15),
+               /* sh $8, 0($9) */
+               MIPS64_SB(8, 0, 9),
+               /* ld $9, ($15) */
+               MIPS64_LD(9, 0, 15),
+               /* ld $8, ($15) */
+               MIPS64_LD(8, 0, 15),
+               MIPS64_SYNC,
+               /* b start */
+               MIPS64_B(NEG16(12)),
+               /* move COP0 DeSave to $15 */
+               MIPS64_DMFC0(15, 31, 0),
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+       };
+
+       /* TODO remove array */
+       uint64_t param_in[2];
+       param_in[0] = addr;
+       param_in[1] = *buf;
+
+       LOG_DEBUG("enter mips64_pracc_exec");
+       return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
+               ARRAY_SIZE(param_in), param_in, 0, NULL);
+}
+
+static int mips64_pracc_write_mem8(struct mips_ejtag *ejtag_info,
+                           uint64_t addr, unsigned count, uint8_t *buf)
+{
+       int retval = ERROR_OK;
+
+       for (unsigned i = 0; i < count; i++) {
+               retval = mips64_pracc_write_u8(ejtag_info, addr + i, &buf[i]);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+       return retval;
+}
+
+int mips64_pracc_write_mem(struct mips_ejtag *ejtag_info,
+                          uint64_t addr, unsigned size,
+                          unsigned count, void *buf)
+{
+       switch (size) {
+       case 1:
+               return mips64_pracc_write_mem8(ejtag_info, addr, count, buf);
+       case 2:
+               return mips64_pracc_write_mem16(ejtag_info, addr, count, buf);
+       case 4:
+               return mips64_pracc_write_mem32(ejtag_info, addr, count, buf);
+       case 8:
+               return mips64_pracc_write_mem64(ejtag_info, addr, count, buf);
+       }
+       return ERROR_FAIL;
+}
+
+int mips64_pracc_write_regs(struct mips_ejtag *ejtag_info, uint64_t *regs)
+{
+       const uint32_t code[] = {
+               /* move $2 to COP0 DeSave */
+               MIPS64_DMTC0(2, 31, 0),
+               /* $15 = MIPS64_PRACC_STACK */
+               MIPS64_LUI(2, UPPER16(MIPS64_PRACC_PARAM_IN)),
+               MIPS64_ORI(2, 2, LOWER16(MIPS64_PRACC_PARAM_IN)),
+               /* sd $0, 0*8($2) */
+               MIPS64_LD(1, 1*8, 2),
+               /* sd $1, 1*8($2) */
+               MIPS64_LD(15, 15*8, 2),
+               /* sd $11, ($15) */
+               MIPS64_DMFC0(2, 31, 0),
+               MIPS64_DMTC0(15, 31, 0),
+               MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)),
+               MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)),
+               MIPS64_SD(1, 0, 15),
+               /* $11 = MIPS64_PRACC_PARAM_OUT */
+               MIPS64_LUI(1, UPPER16(MIPS64_PRACC_PARAM_IN)),
+               MIPS64_ORI(1, 1, LOWER16(MIPS64_PRACC_PARAM_IN)),
+               MIPS64_LD(3, 3*8, 1),
+               MIPS64_LD(4, 4*8, 1),
+               MIPS64_LD(5, 5*8, 1),
+               MIPS64_LD(6, 6*8, 1),
+               MIPS64_LD(7, 7*8, 1),
+               MIPS64_LD(8, 8*8, 1),
+               MIPS64_LD(9, 9*8, 1),
+               MIPS64_LD(10, 10*8, 1),
+               MIPS64_LD(11, 11*8, 1),
+               MIPS64_LD(12, 12*8, 1),
+               MIPS64_LD(13, 13*8, 1),
+               MIPS64_LD(14, 14*8, 1),
+               MIPS64_LD(16, 16*8, 1),
+               MIPS64_LD(17, 17*8, 1),
+               MIPS64_LD(18, 18*8, 1),
+               MIPS64_LD(19, 19*8, 1),
+               MIPS64_LD(20, 20*8, 1),
+               MIPS64_LD(21, 21*8, 1),
+               MIPS64_LD(22, 22*8, 1),
+               MIPS64_LD(23, 23*8, 1),
+               MIPS64_LD(24, 24*8, 1),
+               MIPS64_LD(25, 25*8, 1),
+               MIPS64_LD(26, 26*8, 1),
+               MIPS64_LD(27, 27*8, 1),
+               MIPS64_LD(28, 28*8, 1),
+               MIPS64_LD(29, 29*8, 1),
+               MIPS64_LD(30, 30*8, 1),
+               MIPS64_LD(31, 31*8, 1),
+               MIPS64_LD(2, 32*8, 1),
+               MIPS64_MTLO(2),
+               MIPS64_LD(2, 33*8, 1),
+               MIPS64_MTHI(2),
+               MIPS64_LD(2, MIPS64_NUM_CORE_REGS * 8, 1),
+               MIPS64_DMTC0(2, MIPS64_C0_DEPC, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 2) * 8, 1),
+               MIPS64_DMTC0(2, MIPS64_C0_ENTRYLO0, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 3) * 8, 1),
+               MIPS64_DMTC0(2, MIPS64_C0_ENTRYLO1, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 4) * 8, 1),
+               MIPS64_DMTC0(2, MIPS64_C0_CONTEXT, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 5) * 8, 1),
+               MIPS64_MTC0(2, MIPS64_C0_PAGEMASK, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 6) * 8, 1),
+               MIPS64_MTC0(2, MIPS64_C0_WIRED, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 8) * 8, 1),
+               MIPS64_MTC0(2, MIPS64_C0_COUNT, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 9) * 8, 1),
+               MIPS64_DMTC0(2, MIPS64_C0_ENTRYHI, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 10) * 8, 1),
+               MIPS64_MTC0(2, MIPS64_C0_COMPARE, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 11) * 8, 1),
+               MIPS64_MTC0(2, MIPS64_C0_STATUS, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 12) * 8, 1),
+               MIPS64_MTC0(2, MIPS64_C0_CAUSE, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 13) * 8, 1),
+               MIPS64_DMTC0(2, MIPS64_C0_EPC, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 15) * 8, 1),
+               MIPS64_MTC0(2, MIPS64_C0_CONFIG, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 16) * 8, 1),
+               MIPS64_MTC0(2, MIPS64_C0_LLA, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 21) * 8, 1),
+               MIPS64_DMTC0(2, MIPS64_C0_XCONTEXT, 1),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 22) * 8, 1),
+               MIPS64_MTC0(2, MIPS64_C0_MEMCTRL, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 24) * 8, 1),
+               MIPS64_MTC0(2, MIPS64_C0_PERFCOUNT, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 25) * 8, 1),
+               MIPS64_MTC0(2, MIPS64_C0_PERFCOUNT, 1),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 26) * 8, 1),
+               MIPS64_MTC0(2, MIPS64_C0_PERFCOUNT, 2),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 27) * 8, 1),
+               MIPS64_MTC0(2, MIPS64_C0_PERFCOUNT, 3),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 28) * 8, 1),
+               MIPS64_MTC0(2, MIPS64_C0_ECC, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 29) * 8, 1),
+               MIPS64_MTC0(2, MIPS64_C0_CACHERR, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 30) * 8, 1),
+               MIPS64_MTC0(2, MIPS64_C0_TAGLO, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 31) * 8, 1),
+               MIPS64_MTC0(2, MIPS64_C0_TAGHI, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 32) * 8, 1),
+               MIPS64_DMTC0(2, MIPS64_C0_DATAHI, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 33) * 8, 1),
+               MIPS64_DMTC0(2, MIPS64_C0_EEPC, 0),
+               /* check if FPU is enabled, */
+               MIPS64_MFC0(2, MIPS64_C0_STATUS, 0),
+               MIPS64_SRL(2, 2, 29),
+               MIPS64_ANDI(2, 2, 1),
+               /* skip FPU registers restoration if not */
+               MIPS64_BEQ(0, 2, 77),
+               MIPS64_NOP,
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 33) * 8, 1),
+               MIPS64_CTC1(2, MIPS64_C1_FIR, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 32) * 8, 1),
+               MIPS64_CTC1(2, MIPS64_C1_FCSR, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 34) * 8, 1),
+               MIPS64_CTC1(2, MIPS64_C1_FCONFIG, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 35) * 8, 1),
+               MIPS64_CTC1(2, MIPS64_C1_FCCR, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 36) * 8, 1),
+               MIPS64_CTC1(2, MIPS64_C1_FEXR, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 37) * 8, 1),
+               MIPS64_CTC1(2, MIPS64_C1_FENR, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 0) * 8, 1),
+               MIPS64_DMTC1(2, 0, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 1) * 8, 1),
+               MIPS64_DMTC1(2, 1, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 2) * 8, 1),
+               MIPS64_DMTC1(2, 2, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 3) * 8, 1),
+               MIPS64_DMTC1(2, 3, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 4) * 8, 1),
+               MIPS64_DMTC1(2, 4, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 5) * 8, 1),
+               MIPS64_DMTC1(2, 5, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 6) * 8, 1),
+               MIPS64_DMTC1(2, 6, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 7) * 8, 1),
+               MIPS64_DMTC1(2, 7, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 8) * 8, 1),
+               MIPS64_DMTC1(2, 8, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 9) * 8, 1),
+               MIPS64_DMTC1(2, 9, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 10) * 8, 1),
+               MIPS64_DMTC1(2, 10, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 11) * 8, 1),
+               MIPS64_DMTC1(2, 11, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 12) * 8, 1),
+               MIPS64_DMTC1(2, 12, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 13) * 8, 1),
+               MIPS64_DMTC1(2, 13, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 14) * 8, 1),
+               MIPS64_DMTC1(2, 14, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 15) * 8, 1),
+               MIPS64_DMTC1(2, 15, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 16) * 8, 1),
+               MIPS64_DMTC1(2, 16, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 17) * 8, 1),
+               MIPS64_DMTC1(2, 17, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 18) * 8, 1),
+               MIPS64_DMTC1(2, 18, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 19) * 8, 1),
+               MIPS64_DMTC1(2, 19, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 20) * 8, 1),
+               MIPS64_DMTC1(2, 20, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 21) * 8, 1),
+               MIPS64_DMTC1(2, 21, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 22) * 8, 1),
+               MIPS64_DMTC1(2, 22, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 23) * 8, 1),
+               MIPS64_DMTC1(2, 23, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 24) * 8, 1),
+               MIPS64_DMTC1(2, 24, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 25) * 8, 1),
+               MIPS64_DMTC1(2, 25, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 26) * 8, 1),
+               MIPS64_DMTC1(2, 26, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 27) * 8, 1),
+               MIPS64_DMTC1(2, 27, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 28) * 8, 1),
+               MIPS64_DMTC1(2, 28, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 29) * 8, 1),
+               MIPS64_DMTC1(2, 29, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 30) * 8, 1),
+               MIPS64_DMTC1(2, 30, 0),
+               MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 31) * 8, 1),
+               MIPS64_DMTC1(2, 31, 0),
+               MIPS64_LD(2, 2 * 8, 1),
+               MIPS64_LD(1, 0, 15),
+               MIPS64_SYNC,
+               /* b start */
+               MIPS64_B(NEG16(181)),
+               /* move COP0 DeSave to $15 */
+               MIPS64_DMFC0(15, 31, 0),
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+       };
+
+       LOG_DEBUG("enter mips64_pracc_exec");
+       return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
+               MIPS64_NUM_REGS, regs, 0, NULL);
+}
+
+int mips64_pracc_read_regs(struct mips_ejtag *ejtag_info, uint64_t *regs)
+{
+       const uint32_t code[] = {
+               /* move $2 to COP0 DeSave */
+               MIPS64_DMTC0(2, 31, 0),
+               /* $2 = MIPS64_PRACC_PARAM_OUT */
+               MIPS64_LUI(2, UPPER16(MIPS64_PRACC_PARAM_OUT)),
+               MIPS64_ORI(2, 2, LOWER16(MIPS64_PRACC_PARAM_OUT)),
+               /* sd $0, 0*8($2) */
+               MIPS64_SD(0, 0*8, 2),
+               /* sd $1, 1*8($2) */
+               MIPS64_SD(1, 1*8, 2),
+               /* sd $15, 15*8($2) */
+               MIPS64_SD(15, 15*8, 2),
+               /* move COP0 DeSave to $2 */
+               MIPS64_DMFC0(2, 31, 0),
+               /* move $15 to COP0 DeSave */
+               MIPS64_DMTC0(15, 31, 0),
+               /* $15 = MIPS64_PRACC_STACK */
+               MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)),
+               MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)),
+               /* sd $1, ($15) */
+               MIPS64_SD(1, 0, 15),
+               /* sd $2, ($15) */
+               MIPS64_SD(2, 0, 15),
+               /* $1 = MIPS64_PRACC_PARAM_OUT */
+               MIPS64_LUI(1, UPPER16(MIPS64_PRACC_PARAM_OUT)),
+               MIPS64_ORI(1, 1, LOWER16(MIPS64_PRACC_PARAM_OUT)),
+               MIPS64_SD(2, 2 * 8, 1),
+               MIPS64_SD(3, 3 * 8, 1),
+               MIPS64_SD(4, 4 * 8, 1),
+               MIPS64_SD(5, 5 * 8, 1),
+               MIPS64_SD(6, 6 * 8, 1),
+               MIPS64_SD(7, 7 * 8, 1),
+               MIPS64_SD(8, 8 * 8, 1),
+               MIPS64_SD(9, 9 * 8, 1),
+               MIPS64_SD(10, 10 * 8, 1),
+               MIPS64_SD(11, 11 * 8, 1),
+               MIPS64_SD(12, 12 * 8, 1),
+               MIPS64_SD(13, 13 * 8, 1),
+               MIPS64_SD(14, 14 * 8, 1),
+               MIPS64_SD(16, 16 * 8, 1),
+               MIPS64_SD(17, 17 * 8, 1),
+               MIPS64_SD(18, 18 * 8, 1),
+               MIPS64_SD(19, 19 * 8, 1),
+               MIPS64_SD(20, 20 * 8, 1),
+               MIPS64_SD(21, 21 * 8, 1),
+               MIPS64_SD(22, 22 * 8, 1),
+               MIPS64_SD(23, 23 * 8, 1),
+               MIPS64_SD(24, 24 * 8, 1),
+               MIPS64_SD(25, 25 * 8, 1),
+               MIPS64_SD(26, 26 * 8, 1),
+               MIPS64_SD(27, 27 * 8, 1),
+               MIPS64_SD(28, 28 * 8, 1),
+               MIPS64_SD(29, 29 * 8, 1),
+               MIPS64_SD(30, 30 * 8, 1),
+               MIPS64_SD(31, 31 * 8, 1),
+               MIPS64_MFLO(2),
+               MIPS64_SD(2, 32 * 8, 1),
+               MIPS64_MFHI(2),
+               MIPS64_SD(2, 33 * 8, 1),
+               MIPS64_DMFC0(2, MIPS64_C0_DEPC, 0),
+               MIPS64_SD(2, MIPS64_NUM_CORE_REGS * 8, 1),
+               MIPS64_DMFC0(2, MIPS64_C0_RANDOM, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 1) * 8, 1),
+               MIPS64_DMFC0(2, MIPS64_C0_ENTRYLO0, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 2) * 8, 1),
+               MIPS64_DMFC0(2, MIPS64_C0_ENTRYLO1, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 3) * 8, 1),
+               MIPS64_DMFC0(2, MIPS64_C0_CONTEXT, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 4) * 8, 1),
+               MIPS64_MFC0(2, MIPS64_C0_PAGEMASK, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 5) * 8, 1),
+               MIPS64_MFC0(2, MIPS64_C0_WIRED, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 6) * 8, 1),
+               MIPS64_DMFC0(2, MIPS64_C0_BADVADDR, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 7) * 8, 1),
+               MIPS64_MFC0(2, MIPS64_C0_COUNT, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 8) * 8, 1),
+               MIPS64_DMFC0(2, MIPS64_C0_ENTRYHI, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 9) * 8, 1),
+               MIPS64_MFC0(2, MIPS64_C0_COMPARE, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 10) * 8, 1),
+               MIPS64_MFC0(2, MIPS64_C0_STATUS, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 11) * 8, 1),
+               MIPS64_MFC0(2, MIPS64_C0_CAUSE, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 12) * 8, 1),
+               MIPS64_DMFC0(2, MIPS64_C0_EPC, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 13) * 8, 1),
+               MIPS64_MFC0(2, MIPS64_C0_PRID, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 14) * 8, 1),
+               MIPS64_MFC0(2, MIPS64_C0_CONFIG, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 15) * 8, 1),
+               MIPS64_MFC0(2, MIPS64_C0_LLA, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 16) * 8, 1),
+               MIPS64_DMFC0(2, MIPS64_C0_XCONTEXT, 1),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 21) * 8, 1),
+               MIPS64_MFC0(2, MIPS64_C0_MEMCTRL, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 22) * 8, 1),
+               MIPS64_MFC0(2, MIPS64_C0_DEBUG, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 23) * 8, 1),
+               MIPS64_MFC0(2, MIPS64_C0_PERFCOUNT, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 24) * 8, 1),
+               MIPS64_MFC0(2, MIPS64_C0_PERFCOUNT, 1),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 25) * 8, 1),
+               MIPS64_MFC0(2, MIPS64_C0_PERFCOUNT, 2),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 26) * 8, 1),
+               MIPS64_MFC0(2, MIPS64_C0_PERFCOUNT, 3),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 27) * 8, 1),
+               MIPS64_MFC0(2, MIPS64_C0_ECC, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 28) * 8, 1),
+               MIPS64_MFC0(2, MIPS64_C0_CACHERR, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 29) * 8, 1),
+               MIPS64_MFC0(2, MIPS64_C0_TAGLO, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 30) * 8, 1),
+               MIPS64_MFC0(2, MIPS64_C0_TAGHI, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 31) * 8, 1),
+               MIPS64_DMFC0(2, MIPS64_C0_DATAHI, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 32) * 8, 1),
+               MIPS64_DMFC0(2, MIPS64_C0_EEPC, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 33) * 8, 1),
+               /* check if FPU is enabled, */
+               MIPS64_MFC0(2, MIPS64_C0_STATUS, 0),
+               MIPS64_SRL(2, 2, 29),
+               MIPS64_ANDI(2, 2, 1),
+               /* skip FPU registers dump if not */
+               MIPS64_BEQ(0, 2, 77),
+               MIPS64_NOP,
+               MIPS64_CFC1(2, MIPS64_C1_FIR, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 33) * 8, 1),
+               MIPS64_CFC1(2, MIPS64_C1_FCSR, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 32) * 8, 1),
+               MIPS64_CFC1(2, MIPS64_C1_FCONFIG, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 34) * 8, 1),
+               MIPS64_CFC1(2, MIPS64_C1_FCCR, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 35) * 8, 1),
+               MIPS64_CFC1(2, MIPS64_C1_FEXR, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 36) * 8, 1),
+               MIPS64_CFC1(2, MIPS64_C1_FENR, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 37) * 8, 1),
+               MIPS64_DMFC1(2, 0, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 0) * 8, 1),
+               MIPS64_DMFC1(2, 1, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 1) * 8, 1),
+               MIPS64_DMFC1(2, 2, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 2) * 8, 1),
+               MIPS64_DMFC1(2, 3, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 3) * 8, 1),
+               MIPS64_DMFC1(2, 4, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 4) * 8, 1),
+               MIPS64_DMFC1(2, 5, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 5) * 8, 1),
+               MIPS64_DMFC1(2, 6, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 6) * 8, 1),
+               MIPS64_DMFC1(2, 7, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 7) * 8, 1),
+               MIPS64_DMFC1(2, 8, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 8) * 8, 1),
+               MIPS64_DMFC1(2, 9, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 9) * 8, 1),
+               MIPS64_DMFC1(2, 10, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 10) * 8, 1),
+               MIPS64_DMFC1(2, 11, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 11) * 8, 1),
+               MIPS64_DMFC1(2, 12, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 12) * 8, 1),
+               MIPS64_DMFC1(2, 13, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 13) * 8, 1),
+               MIPS64_DMFC1(2, 14, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 14) * 8, 1),
+               MIPS64_DMFC1(2, 15, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 15) * 8, 1),
+               MIPS64_DMFC1(2, 16, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 16) * 8, 1),
+               MIPS64_DMFC1(2, 17, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 17) * 8, 1),
+               MIPS64_DMFC1(2, 18, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 18) * 8, 1),
+               MIPS64_DMFC1(2, 19, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 19) * 8, 1),
+               MIPS64_DMFC1(2, 20, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 20) * 8, 1),
+               MIPS64_DMFC1(2, 21, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 21) * 8, 1),
+               MIPS64_DMFC1(2, 22, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 22) * 8, 1),
+               MIPS64_DMFC1(2, 23, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 23) * 8, 1),
+               MIPS64_DMFC1(2, 24, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 24) * 8, 1),
+               MIPS64_DMFC1(2, 25, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 25) * 8, 1),
+               MIPS64_DMFC1(2, 26, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 26) * 8, 1),
+               MIPS64_DMFC1(2, 27, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 27) * 8, 1),
+               MIPS64_DMFC1(2, 28, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 28) * 8, 1),
+               MIPS64_DMFC1(2, 29, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 29) * 8, 1),
+               MIPS64_DMFC1(2, 30, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 30) * 8, 1),
+               MIPS64_DMFC1(2, 31, 0),
+               MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 31) * 8, 1),
+               MIPS64_LD(2, 0, 15),
+               MIPS64_LD(1, 0, 15),
+               MIPS64_SYNC,
+               /* b start */
+               MIPS64_B(NEG16(192)),
+               /* move COP0 DeSave to $15 */
+               MIPS64_DMFC0(15, 31, 0),
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+       };
+
+       LOG_DEBUG("enter mips64_pracc_exec");
+       return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
+               0, NULL, MIPS64_NUM_REGS, regs);
+}
+
+/* fastdata upload/download requires an initialized working area
+ * to load the download code; it should not be called otherwise
+ * fetch order from the fastdata area
+ * 1. start addr
+ * 2. end addr
+ * 3. data ...
+ */
+int mips64_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info,
+                              struct working_area *source,
+                              bool write_t, uint64_t addr,
+                              unsigned count, uint64_t *buf)
+{
+       uint32_t handler_code[] = {
+               /* caution when editing, table is modified below */
+               /* r15 points to the start of this code */
+               MIPS64_SD(8, MIPS64_FASTDATA_HANDLER_SIZE - 8, 15),
+               MIPS64_SD(9, MIPS64_FASTDATA_HANDLER_SIZE - 8 * 2, 15),
+               MIPS64_SD(10, MIPS64_FASTDATA_HANDLER_SIZE - 8 * 3, 15),
+               MIPS64_SD(11, MIPS64_FASTDATA_HANDLER_SIZE - 8 * 4, 15),
+               /* start of fastdata area in t0 */
+               MIPS64_LUI(8, UPPER16(MIPS64_PRACC_FASTDATA_AREA)),
+               MIPS64_ORI(8, 8, LOWER16(MIPS64_PRACC_FASTDATA_AREA)),
+               /* start addr in t1 */
+               MIPS64_LD(9, 0, 8),
+               /* end addr to t2 */
+               MIPS64_LD(10, 0, 8),
+
+               /* loop: */
+               /* lw t3,[t8 | r9] */
+               /* 8 */ MIPS64_LD(11, 0, 0),
+               /* sw t3,[r9 | r8] */
+               /* 9 */ MIPS64_SD(11, 0, 0),
+               /* bne $t2,t1,loop */
+               MIPS64_BNE(10, 9, NEG16(3)),
+               /* addi t1,t1,4 */
+               MIPS64_DADDIU(9, 9, 8),
+
+               MIPS64_LD(8, MIPS64_FASTDATA_HANDLER_SIZE - 8, 15),
+               MIPS64_LD(9, MIPS64_FASTDATA_HANDLER_SIZE - 8 * 2, 15),
+               MIPS64_LD(10, MIPS64_FASTDATA_HANDLER_SIZE - 8 * 3, 15),
+               MIPS64_LD(11, MIPS64_FASTDATA_HANDLER_SIZE - 8 * 4, 15),
+
+               MIPS64_LUI(15, UPPER16(MIPS64_PRACC_TEXT)),
+               MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_TEXT)),
+               /* jr start */
+               MIPS64_JR(15),
+               /* move COP0 DeSave to $15 */
+               MIPS64_DMFC0(15, 31, 0),
+       };
+
+       uint32_t jmp_code[] = {
+               /* addr of working area added below */
+               /* 0 */ MIPS64_LUI(15, 0),
+               /* addr of working area added below */
+               /* 1 */ MIPS64_ORI(15, 15, 0),
+               /* jump to ram program */
+               MIPS64_JR(15),
+               MIPS64_NOP,
+       };
+
+       int retval;
+       unsigned i;
+       uint32_t ejtag_ctrl, address32;
+       uint64_t address, val;
+
+       if (source->size < MIPS64_FASTDATA_HANDLER_SIZE)
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+
+       if (write_t) {
+               /* load data from probe at fastdata area */
+               handler_code[8] = MIPS64_LD(11, 0, 8);
+               /* store data to RAM @ r9 */
+               handler_code[9] = MIPS64_SD(11, 0, 9);
+       } else {
+               /* load data from RAM @ r9 */
+               handler_code[8] = MIPS64_LD(11, 0, 9);
+               /* store data to probe at fastdata area */
+               handler_code[9] = MIPS64_SD(11, 0, 8);
+       }
+
+       /* write program into RAM */
+       if (write_t != ejtag_info->fast_access_save) {
+               mips64_pracc_write_mem(ejtag_info, source->address, 4,
+                                      ARRAY_SIZE(handler_code), handler_code);
+               /* save previous operation to speed to any consecutive read/writes */
+               ejtag_info->fast_access_save = write_t;
+       }
+
+       LOG_DEBUG("%s using " TARGET_ADDR_FMT " for write handler", __func__,
+                 source->address);
+       LOG_DEBUG("daddiu: %08x", handler_code[11]);
+
+       jmp_code[0] |= UPPER16(source->address);
+       jmp_code[1] |= LOWER16(source->address);
+       mips64_pracc_exec(ejtag_info,
+                         ARRAY_SIZE(jmp_code), jmp_code,
+                         0, NULL, 0, NULL);
+
+       /* next fetch to dmseg should be in FASTDATA_AREA, check */
+       address = 0;
+
+       mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
+       retval = mips_ejtag_drscan_32(ejtag_info, &address32);
+       if (retval != ERROR_OK)
+               return retval;
+       address = 0xffffffffff200000ull | address32;
+       if ((address & ~7ull) != MIPS64_PRACC_FASTDATA_AREA) {
+               LOG_ERROR("! @MIPS64_PRACC_FASTDATA_AREA (" TARGET_ADDR_FMT ")", address);
+               return ERROR_FAIL;
+       }
+       /* Send the load start address */
+       val = addr;
+       LOG_DEBUG("start: " TARGET_ADDR_FMT, val);
+       mips_ejtag_set_instr(ejtag_info, EJTAG_INST_FASTDATA);
+       mips64_ejtag_fastdata_scan(ejtag_info, 1, &val);
+
+       retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* Send the load end address */
+       val = addr + (count - 1) * 8;
+       LOG_DEBUG("stop: " TARGET_ADDR_FMT, val);
+       mips_ejtag_set_instr(ejtag_info, EJTAG_INST_FASTDATA);
+       mips64_ejtag_fastdata_scan(ejtag_info, 1, &val);
+
+       /* like in legacy code */
+       unsigned num_clocks = 0;
+       if (ejtag_info->mode != 0)
+               num_clocks = ((uint64_t)(ejtag_info->scan_delay) * jtag_get_speed_khz() + 500000) / 1000000;
+       LOG_DEBUG("num_clocks=%d", num_clocks);
+       for (i = 0; i < count; i++) {
+               jtag_add_clocks(num_clocks);
+               retval = mips64_ejtag_fastdata_scan(ejtag_info, write_t, buf++);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("mips64_ejtag_fastdata_scan failed");
+                       return retval;
+               }
+       }
+
+       retval = jtag_execute_queue();
+       if (retval != ERROR_OK) {
+               LOG_ERROR("jtag_execute_queue failed");
+               return retval;
+       }
+
+       retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("wait_for_pracc_rw failed");
+               return retval;
+       }
+
+       address = 0;
+       mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
+       retval = mips_ejtag_drscan_32(ejtag_info, &address32);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("mips_ejtag_drscan_32 failed");
+               return retval;
+       }
+
+       address = 0xffffffffff200000ull | address32;
+       if ((address & ~7ull) != MIPS64_PRACC_TEXT)
+               LOG_ERROR("mini program did not return to start");
+
+       return retval;
+}
+
+#endif /* BUILD_TARGET64 */
diff --git a/src/target/mips64_pracc.h b/src/target/mips64_pracc.h
new file mode 100644 (file)
index 0000000..65ff6e6
--- /dev/null
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Support for processors implementing MIPS64 instruction set
+ *
+ * Copyright (C) 2014 by Andrey Sidorov <anysidorov@gmail.com>
+ * Copyright (C) 2014 by Aleksey Kuleshov <rndfax@yandex.ru>
+ * Copyright (C) 2014-2019 by Peter Mamonov <pmamonov@gmail.com>
+ *
+ * Based on the work of:
+ *     Copyright (C) 2008 by Spencer Oliver
+ *     Copyright (C) 2008 by David T.L. Wong
+ *     Copyright (C) 2010 by Konstantin Kostyukhin, Nikolay Shmyrev
+ */
+
+#ifndef OPENOCD_TARGET_MIPS64_PRACC_H
+#define OPENOCD_TARGET_MIPS64_PRACC_H
+
+#include "mips_ejtag.h"
+
+#define MIPS64_PRACC_TEXT              0xffffffffFF200200ull
+
+#define MIPS64_PRACC_STACK             0xffffffffFF204000ull
+#define MIPS64_PRACC_PARAM_IN          0xffffffffFF201000ull
+#define MIPS64_PRACC_PARAM_IN_SIZE     0x1000
+#define MIPS64_PRACC_PARAM_OUT         (MIPS64_PRACC_PARAM_IN + MIPS64_PRACC_PARAM_IN_SIZE)
+#define MIPS64_PRACC_PARAM_OUT_SIZE    0x1000
+
+#undef UPPER16
+#undef LOWER16
+#define UPPER16(v) ((uint32_t)((v >> 16) & 0xFFFF))
+#define LOWER16(v) ((uint32_t)(v & 0xFFFF))
+#define MIPS64_PRACC_FASTDATA_AREA             0xffffffffFF200000
+#define MIPS64_PRACC_FASTDATA_SIZE             16
+#define MIPS64_FASTDATA_HANDLER_SIZE   0x80
+
+/* FIXME: 16-bit NEG */
+#undef NEG16
+#define NEG16(v) ((uint32_t)(((~(v)) + 1) & 0xFFFF))
+
+#define MIPS64_PRACC_ADDR_STEP 4
+#define MIPS64_PRACC_DATA_STEP 8
+
+int mips64_pracc_read_mem(struct mips_ejtag *ejtag_info, uint64_t addr, unsigned size, unsigned count, void *buf);
+int mips64_pracc_write_mem(struct mips_ejtag *ejtag_info, uint64_t addr, unsigned size, unsigned count, void *buf);
+
+int mips64_pracc_read_regs(struct mips_ejtag *ejtag_info, uint64_t *regs);
+int mips64_pracc_write_regs(struct mips_ejtag *ejtag_info, uint64_t *regs);
+
+int mips64_pracc_exec(struct mips_ejtag *ejtag_info,
+                     unsigned code_len, const uint32_t *code,
+                     unsigned num_param_in, uint64_t *param_in,
+                     unsigned num_param_out, uint64_t *param_out);
+
+int mips64_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info,
+                              struct working_area *source,
+                              bool write_t, uint64_t addr,
+                              unsigned count, uint64_t *buf);
+
+#endif /* OPENOCD_TARGET_MIPS64_PRACC_H */
index 03a0952..0b8122e 100644 (file)
 #include "mips_ejtag.h"
 #include "mips32_dmaacc.h"
 
+#if BUILD_TARGET64 == 1
+#include "mips64.h"
+#include "mips64_pracc.h"
+#endif
+
 void mips_ejtag_set_instr(struct mips_ejtag *ejtag_info, uint32_t new_instr)
 {
        assert(ejtag_info->tap != NULL);
@@ -87,6 +92,36 @@ void mips_ejtag_add_scan_96(struct mips_ejtag *ejtag_info, uint32_t ctrl, uint32
        keep_alive();
 }
 
+int mips_ejtag_drscan_64(struct mips_ejtag *ejtag_info, uint64_t *data)
+{
+       struct jtag_tap *tap;
+       tap  = ejtag_info->tap;
+
+       if (tap == NULL)
+               return ERROR_FAIL;
+       struct scan_field field;
+       uint8_t t[8], r[8];
+       int retval;
+
+       field.num_bits = 64;
+       field.out_value = t;
+       buf_set_u64(t, 0, field.num_bits, *data);
+       field.in_value = r;
+
+       jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+       retval = jtag_execute_queue();
+       if (retval != ERROR_OK) {
+               LOG_ERROR("register read failed");
+               return retval;
+       }
+
+       *data = buf_get_u64(field.in_value, 0, 64);
+
+       keep_alive();
+
+       return ERROR_OK;
+}
+
 void mips_ejtag_drscan_32_queued(struct mips_ejtag *ejtag_info, uint32_t data_out, uint8_t *data_in)
 {
        assert(ejtag_info->tap != NULL);
@@ -422,3 +457,112 @@ int mips_ejtag_fastdata_scan(struct mips_ejtag *ejtag_info, int write_t, uint32_
 
        return ERROR_OK;
 }
+
+#if BUILD_TARGET64 == 1
+
+int mips64_ejtag_config_step(struct mips_ejtag *ejtag_info, bool enable_step)
+{
+       const uint32_t code_enable[] = {
+               MIPS64_MTC0(1, 31, 0),              /* move $1 to COP0 DeSave */
+               MIPS64_MFC0(1, 23, 0),              /* move COP0 Debug to $1 */
+               MIPS64_ORI(1, 1, 0x0100),                /* set SSt bit in debug reg */
+               MIPS64_MTC0(1, 23, 0),              /* move $1 to COP0 Debug */
+               MIPS64_B(NEG16(5)),
+               MIPS64_MFC0(1, 31, 0),              /* move COP0 DeSave to $1 */
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+       };
+
+       const uint32_t code_disable[] = {
+               MIPS64_MTC0(15, 31, 0),                           /* move $15 to COP0 DeSave */
+               MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)),     /* $15 = MIPS64_PRACC_STACK */
+               MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)),
+               MIPS64_SD(1, 0, 15),                              /* sw $1,($15) */
+               MIPS64_SD(2, 0, 15),                              /* sw $2,($15) */
+               MIPS64_MFC0(1, 23, 0),                            /* move COP0 Debug to $1 */
+               MIPS64_LUI(2, 0xFFFF),                           /* $2 = 0xfffffeff */
+               MIPS64_ORI(2, 2, 0xFEFF),
+               MIPS64_AND(1, 1, 2),
+               MIPS64_MTC0(1, 23, 0),                            /* move $1 to COP0 Debug */
+               MIPS64_LD(2, 0, 15),
+               MIPS64_LD(1, 0, 15),
+               MIPS64_SYNC,
+               MIPS64_B(NEG16(14)),
+               MIPS64_MFC0(15, 31, 0),                           /* move COP0 DeSave to $15 */
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+       };
+       const uint32_t *code = enable_step ? code_enable : code_disable;
+       unsigned code_len = enable_step ? ARRAY_SIZE(code_enable) :
+                                         ARRAY_SIZE(code_disable);
+
+       return mips64_pracc_exec(ejtag_info,
+                                code_len, code, 0, NULL, 0, NULL);
+}
+
+int mips64_ejtag_exit_debug(struct mips_ejtag *ejtag_info)
+{
+       const uint32_t code[] = {
+               MIPS64_DRET,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+               MIPS64_NOP,
+       };
+       LOG_DEBUG("enter mips64_pracc_exec");
+       return mips64_pracc_exec(ejtag_info,
+                                ARRAY_SIZE(code), code, 0, NULL, 0, NULL);
+}
+
+int mips64_ejtag_fastdata_scan(struct mips_ejtag *ejtag_info, bool write_t, uint64_t *data)
+{
+       struct jtag_tap *tap;
+
+       tap = ejtag_info->tap;
+       assert(tap != NULL);
+
+       struct scan_field fields[2];
+       uint8_t spracc = 0;
+       uint8_t t[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+
+       /* fastdata 1-bit register */
+       fields[0].num_bits = 1;
+       fields[0].out_value = &spracc;
+       fields[0].in_value = NULL;
+
+       /* processor access data register 64 bit */
+       fields[1].num_bits = 64;
+       fields[1].out_value = t;
+
+       if (write_t) {
+               fields[1].in_value = NULL;
+               buf_set_u64(t, 0, 64, *data);
+       } else
+               fields[1].in_value = (uint8_t *) data;
+
+       jtag_add_dr_scan(tap, 2, fields, TAP_IDLE);
+
+       if (!write_t && data)
+               jtag_add_callback(mips_le_to_h_u64,
+                       (jtag_callback_data_t) data);
+       keep_alive();
+
+       return ERROR_OK;
+}
+
+#endif /* BUILD_TARGET64 */
index c64e858..cfba0ab 100644 (file)
 #define EJTAG_VERSION_41               4
 #define EJTAG_VERSION_51               5
 
+/*
+ * Additional defines for MIPS64 EJTAG
+ */
+#define EJTAG64_DCR                    0xFFFFFFFFFF300000ull
+#define EJTAG64_DCR_ENM                        (1llu << 29)
+#define EJTAG64_DCR_DB                 (1llu << 17)
+#define EJTAG64_DCR_IB                 (1llu << 16)
+#define EJTAG64_DCR_INTE               (1llu << 4)
+#define EJTAG64_DCR_MP                 (1llu << 2)
+#define EJTAG64_V25_DBA0               0xFFFFFFFFFF302100ull
+#define EJTAG64_V25_DBS                        0xFFFFFFFFFF302000ull
+#define EJTAG64_V25_IBA0               0xFFFFFFFFFF301100ull
+#define EJTAG64_V25_IBS                        0xFFFFFFFFFF301000ull
+
 struct mips_ejtag {
        struct jtag_tap *tap;
        uint32_t impcode;
@@ -224,17 +238,21 @@ struct mips_ejtag {
 void mips_ejtag_set_instr(struct mips_ejtag *ejtag_info, uint32_t new_instr);
 int mips_ejtag_enter_debug(struct mips_ejtag *ejtag_info);
 int mips_ejtag_exit_debug(struct mips_ejtag *ejtag_info);
+int mips64_ejtag_exit_debug(struct mips_ejtag *ejtag_info);
 int mips_ejtag_get_idcode(struct mips_ejtag *ejtag_info);
 void mips_ejtag_add_scan_96(struct mips_ejtag *ejtag_info,
                            uint32_t ctrl, uint32_t data, uint8_t *in_scan_buf);
+int mips_ejtag_drscan_64(struct mips_ejtag *ejtag_info, uint64_t *data);
 void mips_ejtag_drscan_32_out(struct mips_ejtag *ejtag_info, uint32_t data);
 int mips_ejtag_drscan_32(struct mips_ejtag *ejtag_info, uint32_t *data);
 void mips_ejtag_drscan_8_out(struct mips_ejtag *ejtag_info, uint8_t data);
 int mips_ejtag_drscan_8(struct mips_ejtag *ejtag_info, uint8_t *data);
 int mips_ejtag_fastdata_scan(struct mips_ejtag *ejtag_info, int write_t, uint32_t *data);
+int mips64_ejtag_fastdata_scan(struct mips_ejtag *ejtag_info, bool write_t, uint64_t *data);
 
 int mips_ejtag_init(struct mips_ejtag *ejtag_info);
 int mips_ejtag_config_step(struct mips_ejtag *ejtag_info, int enable_step);
+int mips64_ejtag_config_step(struct mips_ejtag *ejtag_info, bool enable_step);
 
 static inline void mips_le_to_h_u32(jtag_callback_data_t arg)
 {
@@ -242,4 +260,10 @@ static inline void mips_le_to_h_u32(jtag_callback_data_t arg)
        *((uint32_t *)arg) = le_to_h_u32(in);
 }
 
+static inline void mips_le_to_h_u64(jtag_callback_data_t arg)
+{
+       uint8_t *in = (uint8_t *)arg;
+       *((uint64_t *)arg) = le_to_h_u64(in);
+}
+
 #endif /* OPENOCD_TARGET_MIPS_EJTAG_H */