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 afa5f49b6b91edfb105d0c52ac82698f85444140..2a7cc4b3b335e78beb5237ce6659c894f05f9aa3 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 03a09529ce37a2f3486b79789d4470238fbc42ab..0b8122e1cf3374470e541bcfef7da20cfd2e8e12 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 c64e858a3dc5579750dc5dcc634c13fa0d63a6b6..cfba0ab561c7a80775a54cb8c37f9ed185e6a2e6 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 */

Linking to existing account procedure

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

SSH host keys fingerprints

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