This is an automated email from Gerrit.

Jiri Kastner ([email protected]) just uploaded a new patch set to Gerrit, 
which you can find at http://openocd.zylin.com/6145

-- gerrit

commit 6128677b763992dc0b0335c2b3977cafe1a51381
Author: James Murray <[email protected]>
Date:   Tue Apr 6 19:59:42 2021 +0200

    target: add mpc57xx support
    
    this patch adds support for MPC57xx product line.
    
    Change-Id: I6089b412dbcdc85d4b12aa45e3760a0c0fc09094
    Signed-off-by: Jiri Kastner <[email protected]>

diff --git a/src/target/mpc57xx.c b/src/target/mpc57xx.c
new file mode 100644
index 0000000..f186bcd
--- /dev/null
+++ b/src/target/mpc57xx.c
@@ -0,0 +1,1137 @@
+/***************************************************************************
+ *   Copyright (C) 2017 by James Murray <[email protected]                   *
+ *   Based on code:                                                        *
+ *       Copyright (C) 2010 by Oleksandr Tymoshenko <[email protected]>   *
+ *   Based on mips_m4k code:                                               *
+ *       Copyright (C) 2008 by Spencer Oliver <[email protected]>       *
+ *       Copyright (C) 2008 by David T.L. Wong                             *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "jtag/jtag.h"
+#include "register.h"
+#include "algorithm.h"
+#include "target.h"
+#include "breakpoints.h"
+#include "target_type.h"
+#include "mpc5xxx_jtag.h"
+#include "mpc5xxx.h"
+#include "mpc56xx_regs.h"
+#include "mpc56xx.h"
+#include "mpc57xx_jtag.h"
+#include "mpc57xx_regs.h"
+#include "mpc57xx.h"
+#include "jtag/interface.h"
+
+
+static enum target_state cur_state; /* tmp */
+
+
+int mpc57xx_configure_break_unit(struct target *target)
+{
+       /* get pointers to arch-specific information */
+       struct mpc5xxx_common *mpc57xx = target_to_mpc5xxx(target);
+
+       if (mpc57xx->bp_scanned)
+               return ERROR_OK;
+
+       mpc57xx->num_inst_bpoints = MPC57XX_NUM_BPS; /* MPC5634M */
+       mpc57xx->num_inst_bpoints_avail = mpc57xx->num_inst_bpoints;
+       mpc57xx->inst_break_list = calloc(mpc57xx->num_inst_bpoints,
+               sizeof(struct mpc5xxx_comparator));
+
+       mpc57xx->num_data_bpoints = MPC57XX_NUM_WPS; /* MPC5634M */
+       mpc57xx->num_data_bpoints_avail = mpc57xx->num_data_bpoints;
+       mpc57xx->data_break_list = calloc(mpc57xx->num_data_bpoints,
+               sizeof(struct mpc5xxx_comparator));
+
+       mpc57xx->bp_scanned = 1;
+
+       return ERROR_OK;
+}
+
+
+/* enable (state=1) or disable (state=0) interrupts on halt and resume  */
+/* need to disable EE in MCR before single stepping, to guarantee execution */
+/* so may as well just leave it like this with no extra overhead .??   */
+static int mpc57xx_enable_interrupts(struct target *target, int state)
+{
+       uint32_t val ;
+       uint32_t opcode = state ? 0x7c008146 : 0x7c000146 ;
+       struct mpc5xxx_jtag *jtag_info = &target_to_mpc5xxx(target)->jtag ;
+       return  mpc57xx_exec_inst(jtag_info, opcode, 0, &val, 0);
+}
+
+
+static int mpc57xx_debug_entry(struct target *target, int async_flag)
+{
+       int retval;
+       struct mpc5xxx_common *mpc57xx = target_to_mpc5xxx(target);
+
+       /* Here we need to determine which OnCE we want to talk to.
+        * FIXME. Need to add support for SMP.
+        */
+       mpc57xx->jtag.once = MPC57XX_TAP_ONCE1; /* Default to CPU1 */
+       mpc57xx->jtag.current_tap = MPC5XXX_TAP_INVALID; /* Invalid to force 
TAP selection */
+       mpc57xx->jtag.jtag_irlen = 6;
+
+       printf("Debug entry !\n");
+       retval = mpc57xx_enter_debug(&mpc57xx->jtag, async_flag);
+       if (retval)
+               return retval;
+
+       register_cache_invalidate(mpc57xx->core_cache);
+       /*printf("About to save_context\n");*/
+       mpc57xx_save_context(target);
+       /* Force to say we are halted. Debug/halt appear to be synonymous? */
+       target->state = TARGET_HALTED;
+       mpc57xx->ctl_on_entry = mpc57xx->saved_ctl ;
+       mpc57xx->msr_on_entry = mpc57xx->saved_msr ;
+
+       printf("MSR on entry is 0x%08x\n", mpc57xx->msr_on_entry);
+       printf("CTL on entry is 0x%08x\n", mpc57xx->ctl_on_entry);
+
+       /* get all the debug registers! */
+       const struct {
+               int addr ;
+               char *name ;
+       } debug_regs[] = {
+                       {MPC57XX_ONCE_DBCR0, "DBCR0"},
+                       {MPC57XX_ONCE_DBCR1, "DBCR1"},
+                       {MPC57XX_ONCE_DBCR2, "DBCR2"},
+                       {MPC57XX_ONCE_DBCR4, "DBCR4"},
+                       {MPC57XX_ONCE_DBCR5, "DBCR5"},
+                       {MPC57XX_ONCE_DBCR6, "DBCR6"},
+                       {MPC57XX_ONCE_DBCR7, "DBCR7"},
+                       {MPC57XX_ONCE_DBCR8, "DBCR8"},
+                       {MPC57XX_ONCE_DBSR, "DBSR"},
+                       /*{574, "DSRR0"},
+                       {575, "DSRR1"}*/
+       };
+       const int num_db_regs = sizeof(debug_regs) / sizeof(debug_regs[0]) ;
+
+       for (int i = 0 ; i < num_db_regs ; i++) {
+               uint32_t val ;
+               uint32_t res = mpc5xxx_once_read(&mpc57xx->jtag, 
debug_regs[i].addr, &val, 32) ;
+               printf("%s (spr:%d) = 0x%08x\n", debug_regs[i].name, 
debug_regs[i].addr, res ? 0xdeadbeef : val);
+       }
+
+       retval = mpc5xxx_once_write(&mpc57xx->jtag, MPC57XX_ONCE_DBSR, 
0xffffffff, 32);
+       if (retval)
+               return retval;
+
+
+
+       /* make sure break unit configured */
+       mpc57xx_configure_break_unit(target);
+
+       target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT);
+
+       return ERROR_OK;
+}
+
+static int mpc57xx_poll(struct target *target)
+{
+       uint32_t osr, tmp;
+       int retval;
+       struct mpc5xxx_common *mpc57xx = target_to_mpc5xxx(target);
+
+       retval = mpc5xxx_once_read(&mpc57xx->jtag, MPC57XX_ONCE_DBSR, &tmp, 32);
+       if (retval)
+               return retval;
+       if (tmp) {
+               /*printf("DBSR = 0x%08x\n", tmp);*/
+               ;
+       }
+
+       retval = mpc5xxx_once_osr_read(&mpc57xx->jtag, &osr);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (cur_state != target->state) {
+               printf("Current target->state = %d : %s\n", target->state, 
target_state_name(target));
+               cur_state = target->state;
+       }
+
+       /* debug and halt appear to be synonymous */
+       if (osr & (MPC5XXX_OSR_HALT | MPC5XXX_OSR_DEBUG)) {
+               if ((target->state == TARGET_RUNNING) || (target->state == 
TARGET_RESET)) {
+                       target->state = TARGET_HALTED;
+
+                       printf("no.1\n");
+                       retval = mpc57xx_debug_entry(target, 0);
+                       if (retval != ERROR_OK)
+                               return retval;
+
+                       /*target_call_event_callbacks(target, 
TARGET_EVENT_HALTED);*/
+                       target_call_event_callbacks(target, 
TARGET_EVENT_DEBUG_HALTED);
+               } else if (target->state == TARGET_DEBUG_RUNNING) {
+                       target->state = TARGET_HALTED;
+
+                       printf("no.2\n");
+                       retval = mpc57xx_debug_entry(target, 1);
+                       if (retval != ERROR_OK)
+                               return retval;
+
+                       target_call_event_callbacks(target, 
TARGET_EVENT_DEBUG_HALTED);
+               }
+
+       } else if (target->state == TARGET_DEBUG_RUNNING) { /* JSM */
+
+               printf("no.3\n");
+               retval = mpc57xx_debug_entry(target, 1);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
+
+       } else {
+               if (target->state != TARGET_DEBUG_RUNNING)
+                       target->state = TARGET_RUNNING;
+       }
+
+
+       return ERROR_OK;
+}
+
+#define MPC57XX_BOOTADDR 0xf9c000
+/* Read the boot address from flash
+ * Simplified version that only reads from 0 address.
+ * Ought to read from the multiple possible addresses.
+ */
+static int mpc57xx_read_boot_vector(struct target *target, uint32_t *addr)
+{
+       int retval;
+       uint32_t ad;
+
+       *addr = 0;
+
+       retval = target_read_memory(target, MPC57XX_BOOTADDR, 4, 1, (uint8_t 
*)&ad);
+       if (retval != ERROR_OK)
+               return retval;
+       if (ad != 0x5a00) { /* 0x005a0000 BE */
+               printf("Didn't find a boot record at *0x%08x, found 0x%08x\n", 
MPC57XX_BOOTADDR, ad);
+               /*return ERROR_FAIL;*/
+               *addr = MPC57XX_BOOTADDR; /* At least it is readable flash */
+               return ERROR_OK;
+       }
+       printf("Check *0x%08x = 0x%08x\n", MPC57XX_BOOTADDR, ad);
+
+       retval = target_read_memory(target, MPC57XX_BOOTADDR + 4, 4, 1, 
(uint8_t *)&ad);
+       if (retval != ERROR_OK)
+               return retval;
+       *addr = ((ad & 0x000000ff) << 24)
+                               | ((ad & 0x0000ff00) << 8)
+                               | ((ad & 0x00ff0000) >> 8)
+                               | ((ad & 0xff000000) >> 24);
+       printf("Check *0x%08x = 0x%08x\n", MPC57XX_BOOTADDR + 4, *addr);
+
+       return ERROR_OK;
+}
+
+
+/* Initialise flash wait states. From AN4670 */
+static int mpc57xx_init_flash_ws(struct target *target)
+{
+       int retval;
+       uint32_t val;
+
+       printf("init_flash_ws ");
+       val = 0x00004554;
+       retval = mpc5xxx_write_memory(target, MPC57XX_FLASH_PFCR1,
+               4, 1, (uint8_t *)&val);
+       if (retval)
+               return retval;
+
+       val = 0x00000054;
+       retval = mpc5xxx_write_memory(target, MPC57XX_FLASH_PFCR2,
+               4, 1, (uint8_t *)&val);
+       if (retval)
+               return retval;
+
+       val = 0x00004555;
+       retval = mpc5xxx_write_memory(target, MPC57XX_FLASH_PFCR1,
+               4, 1, (uint8_t *)&val);
+       if (retval)
+               return retval;
+
+       val = 0x00000055;
+       retval = mpc5xxx_write_memory(target, MPC57XX_FLASH_PFCR2,
+               4, 1, (uint8_t *)&val);
+       if (retval)
+               return retval;
+
+       printf("done.\n");
+       return ERROR_OK;
+}
+
+#if 0
+/* Initialise Branch Target Buffer. From AN4670 */
+static int mpc57xx_init_btb(struct target *target)
+{
+       int retval;
+       uint32_t val, opcode;
+
+       /* This is the code we need to run.
+        *      70 60 02 01             e_li    r3,513
+        *      7c 75 fb a6             mtspr   1013,r3
+        *      00 01                   se_isync
+        */
+       opcode = 0x70600201;
+       retval = mpc57xx_exec_inst(&mpc57xx->jtag, opcode, 0, &val,
+               (mpc57xx->saved_ctl & 0xFFFF0000) | MPC57XX_EI_INC);
+       if (retval)
+               return retval;
+
+       opcode = 0x7c75fba6;
+       retval = mpc57xx_exec_inst(&mpc57xx->jtag, opcode, 0, &val,
+               (mpc57xx->saved_ctl & 0xFFFF0000) | MPC57XX_EI_INC);
+       if (retval)
+               return retval;
+
+       opcode = 0x0001; /* how to specify 16bit instruction */
+       retval = mpc57xx_exec_inst(&mpc57xx->jtag, opcode, 0, &val,
+               (mpc57xx->saved_ctl & 0xFFFF0000) | MPC57XX_EI_INC);
+       if (retval)
+               return retval;
+
+       return ERROR_OK;
+}
+#endif
+
+#if 0
+/* Supposed to performs 64bit writes to whole of SRAM to setup ECC
+ * Takes a very long time over JTAG, so instead setup just the first 256 bytes.
+ */
+static int mpc57xx_init_sram(struct target *target)
+{
+       int retval;
+       uint32_t val, addr;
+
+       printf("init_sram");
+       val = 0;
+       for (addr = 0; addr < 256 ; addr += 4) {
+               retval = mpc5xxx_write_memory(target, MPC57XX_START_OF_SRAM + 
addr,
+                       4, 1, (uint8_t *)&val);
+               if (retval)
+                       return retval;
+       }
+
+       printf("done.\n");
+       return ERROR_OK;
+}
+#endif
+
+static int mpc57xx_init_pll(struct target *target)
+{
+       int retval;
+       uint32_t val, retry;
+
+       retval = target_write_u32(target, MPC57XX_FMPLL_ESYNCR2, 0x00000002);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* Set 40MHz with 8MHz crystal */
+       retval = target_write_u32(target, MPC57XX_FMPLL_ESYNCR1, 0xF0000000 + 
40);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retry = 100; /* arbitrary limit */
+       val = 0;
+       while (retry && ((val & 8) == 0)) {
+               retval = target_read_memory(target, MPC57XX_FMPLL_SYNSR, 4, 1,
+                               (uint8_t *)&val);
+               val = be_to_h_u32((uint8_t *)&val); /* swap ends again */
+               if (retval != ERROR_OK)
+                       return retval;
+               retry--;
+       }
+       if (retry == 0) {
+               printf("1. Failed to get PLL lock in expected time.\n");
+               return ERROR_FAIL;
+       }
+
+       /* Set 64MHz with 8MHz crystal */
+       retval = target_write_u32(target, MPC57XX_FMPLL_ESYNCR1, 0xF0000000 + 
64);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return ERROR_OK;
+}
+
+static int mpc57xx_init_vectors(struct target *target)
+{
+       struct mpc5xxx_common *mpc57xx = target_to_mpc5xxx(target);
+       int retval;
+       uint32_t vec;
+/* From Freescale init
+ *     spr 63t $40000000
+ *     spr 400t $0
+ *     spr 401t $0
+ *     spr 402t $0
+ *     spr 403t $0
+ *     spr 404t $0
+ *     spr 405t $0
+ *     spr 406t $0
+ *     spr 407t $0
+ *     spr 408t $0
+ *     spr 409t $0
+ *     spr 410t $0
+ *     spr 411t $0
+ *     spr 412t $0
+ *     spr 413t $0    ; MMU data error vector points into valid memory
+ *     spr 414t $0    ; MMU instruction error vector points into valid memory
+ *     spr 415t $0
+ */
+       retval = mpc57xx_write_spr(&mpc57xx->jtag, 63, 0x40000000);
+       if (retval)
+               return retval;
+
+       for (vec = 400; vec <= 415; vec++) {
+               retval = mpc57xx_write_spr(&mpc57xx->jtag, vec, 0);
+               if (retval)
+                       return retval;
+               }
+
+       return ERROR_OK;
+}
+
+static int mpc57xx_halt(struct target *target)
+{
+       int retval;
+
+       printf("halt called\n");
+       LOG_DEBUG("target->state: %s",  target_state_name(target));
+
+       if (target->state == TARGET_HALTED) {
+               LOG_DEBUG("target was already halted");
+               return ERROR_OK;
+       }
+
+       if (target->state == TARGET_UNKNOWN)
+               LOG_WARNING("target was in unknown state when halt was 
requested");
+
+       if (target->state == TARGET_RESET) {
+               if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) && 
jtag_get_srst()) {
+                       LOG_ERROR("can't request a halt while in reset if nSRST 
pulls nTRST");
+                       return ERROR_TARGET_FAILURE;
+               } else {
+                       target->debug_reason = DBG_REASON_DBGRQ;
+
+                       return ERROR_OK;
+               }
+       }
+
+       printf("Supposed to halt, entering debug mode\n");
+       retval = mpc57xx_debug_entry(target, 1);
+       if (retval != ERROR_OK)
+               return retval;
+
+       target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT);
+
+       target->debug_reason = DBG_REASON_DBGRQ;
+       target->state = TARGET_HALTED;
+
+       return ERROR_OK;
+}
+
+static int mpc57xx_deassert_reset(struct target *target)
+{
+       struct mpc5xxx_common *mpc57xx = target_to_mpc5xxx(target);
+       int retval;
+
+       printf("mpc57xx_deassert_reset\n");
+       printf("reset_halt = %d\n", target->reset_halt);
+       if (target->reset_halt) {
+               retval = mpc57xx_enter_debug(&mpc57xx->jtag, 1);
+               if (retval)
+                       return retval;
+               LOG_DEBUG("Enabled debug after reset");
+       } else {
+               /* Ensure those bits are clear */
+               retval = mpc5xxx_once_write(&mpc57xx->jtag, MPC5XXX_ONCE_OCR, 
MPC5XXX_OCR_DEBUG_OFF, 32);
+               if (retval)
+                       return retval;
+               LOG_DEBUG("Disabled debug after reset");
+       }
+
+       printf("Disabling Interrupts\n") ;
+       mpc57xx_enable_interrupts(target, 0) ;
+
+       adapter_deassert_reset();
+
+       if (target->reset_halt) {
+
+               /* grab PC from boot vector */
+               uint32_t pc;
+               retval = mpc57xx_read_boot_vector(target, &pc);
+               if (retval)
+                       return retval;
+               printf("Boot PC = 0x%08x\n", pc);
+
+               
buf_set_u32(mpc57xx->core_cache->reg_list[MPC5XXX_REG_PC].value, 0, 32, pc);
+               mpc57xx->core_cache->reg_list[MPC5XXX_REG_PC].dirty = 1;
+               mpc57xx->core_cache->reg_list[MPC5XXX_REG_PC].valid = 1;
+               retval = mpc57xx_write_reg(&mpc57xx->jtag, MPC5XXX_REG_PC, pc);
+               if (retval)
+                       return retval;
+
+               printf("Initialise Flash wait states\n");
+               retval = mpc57xx_init_flash_ws(target);
+               if (retval)
+                       return retval;
+
+               /* Got as far as here, then found that S32 Design Studio 
includes a working OSBDM driver
+                * STOP...
+                */
+
+
+               printf("STOP!!! NOT READY YET...\n");
+               exit(1);
+
+#if 0
+               /* Initialise MMU */
+               printf("Initialise MMU in C-code\n");
+               retval = mpc57xx_init_mmu(target);
+               if (retval)
+                       return retval;
+
+               printf("Initialise SRAM in C-code\n");
+               retval = mpc57xx_init_sram(target);
+               if (retval)
+                       return retval;
+#endif
+
+
+               printf("Initialise PLL in C-code\n");
+               retval = mpc57xx_init_pll(target);
+               if (retval)
+                       return retval;
+               printf("Intialise interrupt vectors\n");
+               retval = mpc57xx_init_vectors(target);
+               if (retval)
+                       return retval;
+               retval = mpc57xx_debug_entry(target, 1);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               target->debug_reason = DBG_REASON_DBGRQ;
+               target->state = TARGET_HALTED;
+       }
+       return ERROR_OK;
+}
+
+static int mpc57xx_set_breakpoint(struct target *target,
+               struct breakpoint *breakpoint)
+{
+       struct mpc5xxx_common *mpc57xx = target_to_mpc5xxx(target);
+       struct mpc5xxx_comparator *comparator_list = mpc57xx->inst_break_list;
+       int retval;
+
+       if (breakpoint->set) {
+               LOG_WARNING("breakpoint already set");
+               return ERROR_OK;
+       }
+
+       if (breakpoint->type == BKPT_HARD) {
+               int bp_num = 0;
+
+               while (comparator_list[bp_num].used && (bp_num < 
mpc57xx->num_inst_bpoints))
+                       bp_num++;
+               if (bp_num >= mpc57xx->num_inst_bpoints) {
+                       LOG_ERROR("Can not find free FP Comparator(bpid: %" 
PRIu32 ")",
+                                       breakpoint->unique_id);
+                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               }
+               breakpoint->set = bp_num + 1;
+               comparator_list[bp_num].used = 1;
+               comparator_list[bp_num].bp_value = breakpoint->address;
+
+               printf("Setting breakpoint #%d at 0x%08x\n", bp_num, (unsigned 
int)breakpoint->address);
+               retval = mpc57xx_jtag_set_bp(&mpc57xx->jtag, bp_num, 
breakpoint->address);
+               if (retval)
+                       return retval;
+
+               LOG_DEBUG("bpid: %" PRIu32 ", bp_num %i bp_value 0x%" PRIx32 "",
+                                 breakpoint->unique_id,
+                                 bp_num, comparator_list[bp_num].bp_value);
+       } else if (breakpoint->type == BKPT_SOFT) {
+               LOG_DEBUG("bpid: %" PRIu32, breakpoint->unique_id);
+               if (breakpoint->length == 4) {
+                       uint32_t verify = 0xffffffff;
+
+                       retval = target_read_memory(target, 
breakpoint->address, breakpoint->length, 1,
+                                       breakpoint->orig_instr);
+                       if (retval != ERROR_OK)
+                               return retval;
+                       retval = target_write_u32(target, breakpoint->address, 
MPC57XX_SWBP);
+                       if (retval != ERROR_OK)
+                               return retval;
+
+                       retval = target_read_u32(target, breakpoint->address, 
&verify);
+                       if (retval != ERROR_OK)
+                               return retval;
+                       if (verify != MPC57XX_SWBP) {
+                               LOG_ERROR("Unable to set 32bit breakpoint at 
address %08" PRIx32
+                                               " - check that memory is 
read/writable", (unsigned int)breakpoint->address);
+                               return ERROR_OK;
+                       }
+               } else {
+                       uint16_t verify = 0xffff;
+
+                       retval = target_read_memory(target, 
breakpoint->address, breakpoint->length, 1,
+                                       breakpoint->orig_instr);
+                       if (retval != ERROR_OK)
+                               return retval;
+                       retval = target_write_u16(target, breakpoint->address, 
MPC57XX_SWBP);
+                       if (retval != ERROR_OK)
+                               return retval;
+
+                       retval = target_read_u16(target, breakpoint->address, 
&verify);
+                       if (retval != ERROR_OK)
+                               return retval;
+                       if (verify != MPC57XX_SWBP) {
+                               LOG_ERROR("Unable to set 16bit breakpoint at 
address %08" PRIx32
+                                               " - check that memory is 
read/writable", (unsigned int)breakpoint->address);
+                               return ERROR_OK;
+                       }
+               }
+
+               breakpoint->set = 20; /* Any nice value but 0 */
+       }
+
+       return ERROR_OK;
+}
+
+static int mpc57xx_enable_breakpoints(struct target *target)
+{
+       struct breakpoint *breakpoint = target->breakpoints;
+
+       /* set any pending breakpoints */
+       while (breakpoint) {
+               if (breakpoint->set == 0)
+                       mpc57xx_set_breakpoint(target, breakpoint);
+               breakpoint = breakpoint->next;
+       }
+       return ERROR_OK;
+}
+
+static int mpc57xx_unset_breakpoint(struct target *target,
+               struct breakpoint *breakpoint)
+{
+       /* get pointers to arch-specific information */
+       struct mpc5xxx_common *mpc57xx = target_to_mpc5xxx(target);
+       struct mpc5xxx_comparator *comparator_list = mpc57xx->inst_break_list;
+       int retval;
+
+       if (!breakpoint->set) {
+               LOG_WARNING("breakpoint not set");
+               return ERROR_OK;
+       }
+
+       if (breakpoint->type == BKPT_HARD) {
+               int bp_num = breakpoint->set - 1;
+               if ((bp_num < 0) || (bp_num >= mpc57xx->num_inst_bpoints)) {
+                       LOG_DEBUG("Invalid FP Comparator number in breakpoint 
(bpid: %" PRIu32 ")",
+                                         breakpoint->unique_id);
+                       return ERROR_OK;
+               }
+               LOG_DEBUG("bpid: %" PRIu32 " - releasing hw: %d",
+                               breakpoint->unique_id,
+                               bp_num);
+               comparator_list[bp_num].used = 0;
+               comparator_list[bp_num].bp_value = 0;
+               /*target_write_u32(target, comparator_list[bp_num].reg_address +
+                                ejtag_info->ejtag_ibc_offs, 0);*/
+
+       } else {
+               /* restore original instruction (kept in target endianness) */
+               LOG_DEBUG("bpid: %" PRIu32, breakpoint->unique_id);
+               if (breakpoint->length == 4) {
+                       uint32_t current_instr;
+
+                       /* check that user program has not modified breakpoint 
instruction */
+                       retval = target_read_memory(target, 
breakpoint->address, 4, 1,
+                                       (uint8_t *)&current_instr);
+                       if (retval != ERROR_OK)
+                               return retval;
+
+                       /**
+                        * target_read_memory() gets us data in _target_ 
endianess.
+                        * If we want to use this data on the host for 
comparisons with some macros
+                        * we must first transform it to _host_ endianess using 
target_buffer_get_u32().
+                        */
+                       current_instr = target_buffer_get_u32(target, (uint8_t 
*)&current_instr);
+
+               } else {
+                       uint16_t current_instr;
+                       /* Not checked to see if this makes any sense JSM */
+                       /* check that user program has not modified breakpoint 
instruction */
+                       retval = target_read_memory(target, 
breakpoint->address, 2, 1,
+                                       (uint8_t *)&current_instr);
+                       if (retval != ERROR_OK)
+                               return retval;
+                       current_instr = target_buffer_get_u16(target, (uint8_t 
*)&current_instr);
+
+               }
+       }
+       breakpoint->set = 0;
+
+       return ERROR_OK;
+}
+
+static int mpc57xx_add_breakpoint(struct target *target, struct breakpoint 
*breakpoint)
+{
+       struct mpc5xxx_common *mpc57xx = target_to_mpc5xxx(target);
+
+       printf("Adding a breakpoint @ 0x%08x, type = %d\n", (unsigned 
int)breakpoint->address, breakpoint->type);
+               if (breakpoint->type == BKPT_HARD) {
+                       if (mpc57xx->num_inst_bpoints_avail < 1) {
+                               LOG_INFO("no hardware breakpoint available");
+                               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+                       }
+
+                       mpc57xx->num_inst_bpoints_avail--;
+               }
+
+       return ERROR_OK;
+}
+
+static int mpc57xx_remove_breakpoint(struct target *target,
+               struct breakpoint *breakpoint)
+{
+       /* get pointers to arch-specific information */
+       struct mpc5xxx_common *mpc57xx = target_to_mpc5xxx(target);
+
+       if (target->state != TARGET_HALTED) {
+               LOG_WARNING("target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (breakpoint->set)
+               mpc57xx_unset_breakpoint(target, breakpoint);
+
+       if (breakpoint->type == BKPT_HARD)
+               mpc57xx->num_inst_bpoints_avail++;
+
+       return ERROR_OK;
+}
+
+static int mpc57xx_step(struct target *target, int current,
+       target_addr_t address, int handle_breakpoints)
+{
+       struct mpc5xxx_common *mpc57xx = target_to_mpc5xxx(target);
+       struct breakpoint *breakpoint = NULL;
+       int retval;
+       uint32_t addr, opcode, val;
+
+       if (target->state != TARGET_HALTED) {
+               LOG_WARNING("target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* current = 1: continue on current pc, otherwise continue at <address> 
*/
+       if (!current) {
+               
buf_set_u32(mpc57xx->core_cache->reg_list[MPC5XXX_REG_PC].value, 0, 32, 
address);
+               mpc57xx->core_cache->reg_list[MPC5XXX_REG_PC].dirty = true;
+               mpc57xx->core_cache->reg_list[MPC5XXX_REG_PC].valid = true;
+       }
+
+       /* the front-end may request us not to handle breakpoints */
+       if (handle_breakpoints) {
+               breakpoint = breakpoint_find(target,
+                               
buf_get_u32(mpc57xx->core_cache->reg_list[MPC5XXX_REG_PC].value, 0, 32));
+               if (breakpoint)
+                       mpc57xx_remove_breakpoint(target, breakpoint);
+       }
+
+       addr = buf_get_u32(mpc57xx->core_cache->reg_list[MPC5XXX_REG_PC].value, 
0, 32);
+
+       /* Fetch the instruction from that address */
+       mpc5xxx_jtag_read_memory32(&mpc57xx->jtag,
+               addr, 1, &val);
+
+       /* Opcode comes back endian swapped, fix it. */
+       opcode = ((val & 0x000000ff) << 24)
+                       | ((val & 0x0000ff00) << 8)
+                       | ((val & 0x00ff0000) >> 8)
+                       | ((val & 0xff000000) >> 24);
+
+       /* restore context incl. setting PC*/
+       mpc57xx_restore_context(target);
+
+
+       /* disable interrupts while stepping */
+       /*mpc57xx_enable_interrupts(target, 0);*/
+
+       target->debug_reason = DBG_REASON_SINGLESTEP;
+       target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
+       keep_alive();
+
+       retval = mpc57xx_exec_inst(&mpc57xx->jtag, opcode, 0, &val,
+                       (mpc57xx->saved_ctl & 0xFFFF0000) | MPC57XX_EI_INC);
+
+       if (retval)
+               return retval;
+
+       /* Fetch updated PC - may not be necessary ? */
+       retval = mpc57xx_read_reg(&mpc57xx->jtag, MPC5XXX_REG_PC, &val);
+       if (retval)
+               return retval;
+
+       /* registers are now invalid */
+       register_cache_invalidate(mpc57xx->core_cache);
+
+       mpc57xx_save_context(target);
+
+       /* Save PC - not sure this is strictly necessary */
+       buf_set_u32(mpc57xx->core_cache->reg_list[MPC5XXX_REG_PC].value, 0, 32, 
mpc57xx->core_regs[MPC5XXX_REG_PC]);
+
+       /* Seems like these aren't handled correctly? GDB isn't getting new 
value. */
+       mpc57xx->core_cache->reg_list[MPC5XXX_REG_PC].valid = true;
+
+       if (breakpoint)
+               mpc57xx_add_breakpoint(target, breakpoint);
+
+       target_call_event_callbacks(target, TARGET_EVENT_HALTED);
+
+       return ERROR_OK;
+}
+
+static int mpc57xx_set_watchpoint(struct target *target,
+               struct watchpoint *watchpoint)
+{
+       struct mpc5xxx_common *mpc57xx = target_to_mpc5xxx(target);
+       struct mpc5xxx_comparator *comparator_list = mpc57xx->data_break_list;
+       int retval;
+
+       if (watchpoint->set) {
+               LOG_WARNING("watchpoint already set");
+               return ERROR_OK;
+       }
+
+       int wp_num = 0;
+
+       while (comparator_list[wp_num].used && (wp_num < 
mpc57xx->num_data_bpoints))
+               wp_num++;
+       if (wp_num >= mpc57xx->num_data_bpoints) {
+               LOG_ERROR("Can not find free FP Comparator(wpid: %" PRIu32 ")",
+                               watchpoint->unique_id);
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       }
+       watchpoint->set = wp_num + 1;
+       comparator_list[wp_num].used = 1;
+       comparator_list[wp_num].bp_value = watchpoint->address;
+
+       printf("Actually need to set watchpoint #%d at 0x%08x\n", wp_num, 
(unsigned int)watchpoint->address);
+       retval = mpc57xx_jtag_set_wp(&mpc57xx->jtag, wp_num, 
watchpoint->address);
+       if (retval)
+               return retval;
+
+       LOG_DEBUG("wpid: %" PRIu32 ", wp_num %i bp_value 0x%" PRIx32 "",
+                         watchpoint->unique_id,
+                         wp_num, comparator_list[wp_num].bp_value);
+
+       watchpoint->set = 20; /* Any nice value but 0 */
+
+       return ERROR_OK;
+}
+
+static int mpc57xx_enable_watchpoints(struct target *target)
+{
+       struct watchpoint *watchpoint = target->watchpoints;
+
+       /* set any pending breakpoints */
+       while (watchpoint) {
+               if (watchpoint->set == 0)
+                       mpc57xx_set_watchpoint(target, watchpoint);
+               watchpoint = watchpoint->next;
+       }
+       return ERROR_OK;
+}
+
+static int mpc57xx_unset_watchpoint(struct target *target,
+               struct watchpoint *watchpoint)
+{
+       /* get pointers to arch-specific information */
+       struct mpc5xxx_common *mpc57xx = target_to_mpc5xxx(target);
+       struct mpc5xxx_comparator *comparator_list = mpc57xx->data_break_list;
+
+       if (!watchpoint->set) {
+               LOG_WARNING("breakpoint not set");
+               return ERROR_OK;
+       }
+
+       int wp_num = watchpoint->set - 1;
+       if ((wp_num < 0) || (wp_num >= mpc57xx->num_data_bpoints)) {
+               LOG_DEBUG("Invalid FP Comparator number in breakpoint (wpid: %" 
PRIu32 ")",
+                                 watchpoint->unique_id);
+               return ERROR_OK;
+       }
+       LOG_DEBUG("wpid: %" PRIu32 " - releasing hw: %d",
+                       watchpoint->unique_id,
+                       wp_num);
+       comparator_list[wp_num].used = 0;
+       comparator_list[wp_num].bp_value = 0;
+               /*target_write_u32(target, comparator_list[bp_num].reg_address +
+                                ejtag_info->ejtag_ibc_offs, 0);*/
+
+       watchpoint->set = 0;
+
+       return ERROR_OK;
+}
+
+
+static int mpc57xx_add_watchpoint(struct target *target, struct watchpoint 
*watchpoint)
+{
+       struct mpc5xxx_common *mpc57xx = target_to_mpc5xxx(target);
+
+       if (mpc57xx->num_inst_bpoints_avail < 1) {
+               LOG_INFO("no hardware watchpoints available");
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       }
+
+       mpc57xx->num_inst_bpoints_avail--;
+
+       return ERROR_OK;
+}
+
+static int mpc57xx_remove_watchpoint(struct target *target,
+       struct watchpoint *watchpoint)
+{
+       /* get pointers to arch-specific information */
+       struct mpc5xxx_common *mpc57xx = target_to_mpc5xxx(target);
+
+       if (target->state != TARGET_HALTED) {
+               LOG_WARNING("target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (watchpoint->set)
+               mpc57xx_unset_watchpoint(target, watchpoint);
+
+       mpc57xx->num_inst_bpoints_avail++;
+
+       return ERROR_OK;
+}
+
+
+static int mpc57xx_resume(struct target *target, int current,
+       target_addr_t address, int handle_breakpoints, int debug_execution)
+{
+       struct mpc5xxx_common *mpc57xx = target_to_mpc5xxx(target);
+       struct breakpoint *breakpoint = NULL;
+       uint32_t resume_pc;
+       int retval;
+
+       if (target->state != TARGET_HALTED) {
+               LOG_WARNING("1. target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (!debug_execution) {
+               target_free_all_working_areas(target);
+
+               retval = mpc57xx_jtag_clr_bps_wps(&mpc57xx->jtag);
+               if (retval)
+                       return retval;
+
+               retval = mpc57xx_enable_breakpoints(target);
+               if (retval)
+                       return retval;
+
+               retval = mpc57xx_enable_watchpoints(target);
+               if (retval)
+                       return retval;
+       }
+
+       /* current = 1: continue on current pc, otherwise continue at <address> 
*/
+       if (!current) {
+               
buf_set_u32(mpc57xx->core_cache->reg_list[MPC5XXX_REG_PC].value, 0, 32, 
address);
+               mpc57xx->core_cache->reg_list[MPC5XXX_REG_PC].dirty = 1;
+               mpc57xx->core_cache->reg_list[MPC5XXX_REG_PC].valid = 1;
+               resume_pc = address;
+       } else {
+               resume_pc = 
buf_get_u32(mpc57xx->core_cache->reg_list[MPC5XXX_REG_PC].value, 0, 32);
+       }
+
+       retval = mpc57xx_restore_context(target);
+       if (retval)
+               return retval;
+
+       /* the front-end may request us not to handle breakpoints */
+       if (handle_breakpoints) {
+               /* Single step past breakpoint at current address */
+               breakpoint = breakpoint_find(target, resume_pc);
+               if (breakpoint) {
+                       printf("Not yet handling resuming on breakpoint\n");
+#if 0
+                       LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 "", 
breakpoint->address);
+                       mpc57xx_unset_breakpoint(target, breakpoint);
+                       mpc57xx_single_step_core(target);
+                       mpc57xx_set_breakpoint(target, breakpoint);
+#endif
+               }
+       }
+#if 0
+
+       /* enable interrupts if we are running */
+       mpc57xx_enable_interrupts(target, !debug_execution);
+#endif
+       /* exit debug mode */
+       if (mpc57xx->msr_on_entry & MPC5XXX_MSR_EE) {
+               printf("Re-enabling interrupts ? debug_execution = %d\n", 
debug_execution) ;
+               mpc57xx_enable_interrupts(target, debug_execution ? 0 : 1) ;
+       } else {
+               printf("Not Re-enabling interrupts ? debug_execution = %d\n", 
debug_execution) ;
+
+       }
+       /* 1 was handle_breakpoints */
+       retval = mpc57xx_exit_debug(&mpc57xx->jtag, resume_pc, 1, 
mpc57xx->ctl_on_entry);
+
+       if (retval)
+               return retval;
+
+       target->debug_reason = DBG_REASON_NOTHALTED;
+
+       /* registers are now invalid */
+       register_cache_invalidate(mpc57xx->core_cache);
+
+       if (!debug_execution) {
+               target->state = TARGET_RUNNING;
+               target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
+               LOG_DEBUG("target resumed at 0x%" PRIx32 "", resume_pc);
+       } else {
+               target->state = TARGET_DEBUG_RUNNING;
+               target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED);
+               LOG_DEBUG("target debug resumed at 0x%" PRIx32 "", resume_pc);
+       }
+
+       return ERROR_OK;
+}
+
+static int mpc57xx_target_create(struct target *target, Jim_Interp *interp)
+{
+       struct mpc5xxx_common *mpc57xx = calloc(1, sizeof(struct
+                       mpc5xxx_common));
+       printf("target_create\n");
+       mpc57xx->common_magic = MPC57XX_COMMON_MAGIC;
+       target->arch_info = mpc57xx;
+
+       mpc57xx->jtag.once = MPC57XX_TAP_ONCE1; /* Default to CPU1 */
+       mpc57xx->jtag.current_tap = MPC5XXX_TAP_INVALID; /* Invalid to force 
TAP selection */
+       mpc57xx->jtag.jtag_irlen = 6;
+
+       return ERROR_OK;
+}
+
+/* read registers from the MCU and copy them to core_regs etc. */
+/* this function disables interrupts if they are enabled ... */
+/* result will however be reported correctly */
+int mpc57xx_save_context(struct target *target)
+{
+       int retval, i;
+       struct mpc5xxx_common *mpc56xx = target_to_mpc5xxx(target);
+
+       /*printf("save_context\n");*/
+       keep_alive();
+       retval = mpc57xx_jtag_read_regs(&mpc56xx->jtag, mpc56xx->core_regs, 
&mpc56xx->saved_ctl);
+       if (retval != ERROR_OK)
+               return retval;
+
+       mpc56xx->saved_msr = mpc56xx->core_regs[MPC5XXX_REG_MSR] ;
+
+       /* now we saved the sate of the msr before we disabled interrupts,
+        * we can stop lying about disabled interrupts - otherwise
+        * restore_context will re-enable them
+        */
+
+       mpc56xx->core_regs[MPC5XXX_REG_MSR] &= ~MPC5XXX_MSR_EE ;
+
+       for (i = 0; i < MPC5XXX_NUMCOREREGS; i++) {
+               if (!mpc56xx->core_cache->reg_list[i].valid)
+                       mpc5xxx_read_core_reg(target, i);
+       }
+
+       keep_alive();
+
+       /*printf("end save context\n");*/
+       keep_alive();
+       return ERROR_OK;
+}
+
+/* restore registers and state to the MCU */
+int mpc57xx_restore_context(struct target *target)
+{
+       int i, retval;
+       struct mpc5xxx_cpuscr scr;
+
+       /*printf("restore_context\n");*/
+
+       /* get pointers to arch-specific information */
+       struct mpc5xxx_common *mpc56xx = target_to_mpc5xxx(target);
+
+       for (i = 0; i < MPC5XXX_NUMCOREREGS; i++) {
+               if (mpc56xx->core_cache->reg_list[i].dirty)
+                       mpc5xxx_write_core_reg(target, i);
+       }
+
+       /* write core regs */
+       mpc57xx_jtag_write_regs(&mpc56xx->jtag, mpc56xx->core_regs);
+
+       /* Restore CTL */
+       retval = mpc5xxx_once_cpuscr_read(&mpc56xx->jtag, &scr);
+       if (retval)
+               return retval;
+       scr.ctl = mpc56xx->saved_ctl;
+       return mpc5xxx_once_cpuscr_write(&mpc56xx->jtag, &scr);
+}
+
+
+struct target_type mpc57xx_target = {
+       .name = "mpc57xx",
+
+       .poll = mpc57xx_poll,
+       .arch_state = mpc5xxx_arch_state,
+
+       .halt = mpc57xx_halt,
+       .resume = mpc57xx_resume,
+       .step = mpc57xx_step,
+
+       .assert_reset = mpc5xxx_assert_reset,
+       .deassert_reset = mpc57xx_deassert_reset,
+
+       .get_gdb_reg_list = mpc5xxx_get_gdb_reg_list,
+
+       .read_memory = mpc5xxx_read_memory,
+       .write_memory = mpc5xxx_write_memory,
+       /* .checksum_memory = mpc57xx_checksum_memory, */
+       /* .blank_check_memory = mpc57xx_blank_check_memory, */
+
+       /* .run_algorithm = mpc57xx_run_algorithm, */
+
+       .add_breakpoint = mpc57xx_add_breakpoint,
+       .remove_breakpoint = mpc57xx_remove_breakpoint,
+       .add_watchpoint = mpc57xx_add_watchpoint,
+       .remove_watchpoint = mpc57xx_remove_watchpoint,
+
+       .target_create = mpc57xx_target_create,
+       .init_target = mpc5xxx_init_target,
+       .examine = mpc5xxx_examine,
+};
diff --git a/src/target/mpc57xx.h b/src/target/mpc57xx.h
new file mode 100644
index 0000000..c0d48ac
--- /dev/null
+++ b/src/target/mpc57xx.h
@@ -0,0 +1,43 @@
+/***************************************************************************
+ *   Copyright (C) 2017 by James Murray <[email protected]                   *
+ *   Based on code:                                                        *
+ *       Copyright (C) 2010 by Oleksandr Tymoshenko <[email protected]>   *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifndef MPC57XX
+#define MPC57XX
+
+struct target;
+
+#define MPC57XX_COMMON_MAGIC   0x1834601d /* Set as MPC5746R JTAG ID - is this 
acceptable? */
+
+#define MPC57XX_START_OF_SRAM  0x40008000 /* This needs to come from a config 
var */
+#define MPC57XX_SIZE_OF_SRAM   0x00038000 /* 224k This needs to come from a 
config var */
+
+#define MPC57XX_FLASH_PFCR1    0xfc030000
+#define MPC57XX_FLASH_PFCR2    0xfc030004
+
+#define MPC57XX_FMPLL  0xc3f80000
+#define MPC57XX_FMPLL_SYNCR    (MPC57XX_FMPLL+0)
+#define MPC57XX_FMPLL_SYNSR    (MPC57XX_FMPLL+4)
+#define MPC57XX_FMPLL_ESYNCR1  (MPC57XX_FMPLL+8)
+#define MPC57XX_FMPLL_ESYNCR2  (MPC57XX_FMPLL+0xc)
+#define MPC57XX_FMPLL_SYNFMRR  (MPC57XX_FMPLL+0x18)
+
+int mpc57xx_save_context(struct target *target);
+int mpc57xx_restore_context(struct target *target);
+
+#endif /*MPC5634*/
diff --git a/src/target/mpc57xx_jtag.c b/src/target/mpc57xx_jtag.c
new file mode 100644
index 0000000..c65d7f5
--- /dev/null
+++ b/src/target/mpc57xx_jtag.c
@@ -0,0 +1,447 @@
+/***************************************************************************
+ *   Copyright (C) 2017 by James Murray <[email protected]                   *
+ *   Based on code:                                                        *
+ *       Copyright (C) 2010 by Oleksandr Tymoshenko <[email protected]>   *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "target.h"
+#include "jtag/jtag.h"
+#include "mpc56xx_jtag.h"
+#include "mpc57xx_jtag.h"
+#include "jtag/interface.h"
+
+#define READ_MAXLOOPS 500
+
+int mpc57xx_enter_debug(struct mpc5xxx_jtag *jtag_info, int async_flag)
+{
+       int res;
+       printf("got call to enter_debug\n");
+
+       res = mpc56xx_enable_once(jtag_info);
+       if (res)
+               return res;
+
+       if (async_flag) {
+               /* WKUP, DR */
+               res = mpc5xxx_once_write(jtag_info, MPC5XXX_ONCE_OCR, 
MPC5XXX_OCR_DEBUG1, 32);
+               if (res)
+                       return res;
+       }
+
+       /* was WKUP, FDB only */
+       res = mpc5xxx_once_write(jtag_info, MPC5XXX_ONCE_OCR, 
MPC5XXX_OCR_DEBUG2 | 1, 32);
+       if (res)
+               return res;
+
+       /* Clear internal debug status register */
+       res = mpc5xxx_once_write(jtag_info, MPC57XX_ONCE_EDBSR0, 0xffffffff, 
32);
+       if (res)
+               return res;
+       res = mpc5xxx_once_write(jtag_info, MPC57XX_ONCE_DBCR0, 
MPC5XXX_ONCE_DBCR0_EDM, 32);
+       if (res)
+               return res;
+       /* Clear external debug status register */
+       res = mpc5xxx_once_write(jtag_info, MPC57XX_ONCE_EDBSR0, 0xffffffff, 
32);
+       if (res)
+               return res;
+       /* Take control of all debug resources */
+       res = mpc5xxx_once_write(jtag_info, MPC57XX_ONCE_EDBRAC0, 
MPC57XX_ONCE_EDBRAC0_DEFAULT, 32);
+       if (res)
+               return res;
+
+       return ERROR_OK;
+}
+
+/* In debug mode only, loads an instruction to CPUSCR and executes
+ * it. Optionally using alternate data if flag set.
+ */
+int mpc57xx_exec_inst_nowait(struct mpc5xxx_jtag *jtag_info, uint32_t inst, 
uint32_t in,
+               uint32_t *out, uint32_t flag)
+{
+       int retval;
+
+       uint32_t osr;
+       struct mpc5xxx_cpuscr scr;
+       uint32_t val;
+
+       retval = mpc5xxx_once_cpuscr_read(jtag_info, &scr);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /*
+        * write the appropriate information into the CPU scan chain
+        * register (CPUSCR), followed by writing to OCMD to set the OCMD[GO] 
bit and clear the OCMD[EX]
+        * bit with the OCMD[RS] field indicating either the CPUSCR or No 
Register Selected.
+        */
+       scr.wbbrl = in;
+       scr.wbbrh = 0; /* only for 64 bit */
+       /* leave scr.msr unchanged */
+       scr.ir = inst;
+
+       /*
+        * FILTHY HACK:
+        * If we a are single stepping as part of normal execution flow, we 
need to ensure the
+        * top sixteen bits of ctl are the same as when we entered debug mode.
+        * If this is the case, the upper sixteen bits of flag should contain 
this ...
+        */
+
+       scr.ctl = flag & 0xFFFF0000 ;
+
+
+       if ((flag & MPC57XX_EI_VAL))
+               scr.ctl |= MPC57XX_CPUSCR_CTL_FFRA;
+
+       /* May point to invalid instruction? */
+       if ((flag & MPC57XX_EI_INC) == 0)
+               scr.pc -= 4; /* post-decrement by one instruction */
+
+       retval = mpc5xxx_once_cpuscr_write(jtag_info, &scr);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = mpc5xxx_jtag_set_instr(jtag_info, MPC5XXX_ONCE_GO | 
MPC57XX_ONCE_NOREG); /* was MPC57XX_ONCE_CPUSCR */
+       if (retval)
+               return retval;
+
+       /* Freescale e200z3 RM has this CRITICAL tidbit:
+        * "In addition, the Update-DR state must also be transitioned through
+        * in order for the single-step and/or exit functionality to be 
performed"
+        */
+       retval = mpc5xxx_jtag_read_data(jtag_info, &val, 1); /* dummy read of 
one bit to force update-DR */
+       if (retval)
+               return retval;
+
+       /* After single-step, "the external tool
+        * should read the OnCE Status Register (OSR) to verify that the CPU 
has returned to debug mode with no
+        * error by verifying that the OSR[DEBUG] bit is set and OSR[ERR] bit 
is cleared."
+        */
+
+       retval = mpc5xxx_once_osr_read(jtag_info, &osr);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (((osr & MPC5XXX_OSR_DEBUG) == 0) || (osr & MPC5XXX_OSR_ERR)) {
+               printf("2. OSR indicates failure of some kind. OSR = 0x%08x\n", 
osr);
+               printf("The inst =0x%08x, PC=0x%08x\n", inst, scr.pc);
+
+               if ((osr & MPC5XXX_OSR_ERR))
+                       return ERROR_WAIT ;
+               else
+                       return ERROR_FAIL;
+       }
+
+       retval = mpc5xxx_once_cpuscr_read(jtag_info, &scr);
+       if (retval != ERROR_OK)
+               return retval;
+
+       *out = scr.wbbrl;
+
+       return ERROR_OK;
+}
+
+int mpc57xx_exec_inst(struct mpc5xxx_jtag *jtag_info, uint32_t inst, uint32_t 
in,
+               uint32_t *out, uint32_t flag){
+       int retval ;
+       int retries = 100 ;
+
+       do {
+               retval = mpc57xx_exec_inst_nowait(jtag_info, inst, in, out, 
flag);
+       } while (retval == ERROR_WAIT && --retries) ;
+
+       if (retval) {
+               if (!retries)
+                       printf("Failed to execute single step.\n");
+               return retval;
+       }
+       return retval ;
+}
+
+
+/* In debug mode only, exits debug mode.
+ * Single-steps over NOP and sets EX bit to exit debug.
+ * ctl_on_entry unused here
+ */
+int mpc57xx_exit_debug(struct mpc5xxx_jtag *jtag_info, uint32_t addr, int 
sw_bp, uint32_t ctl_on_entry)
+{
+       int retval;
+
+       uint32_t osr;
+       struct mpc5xxx_cpuscr scr;
+       uint32_t val;
+
+       if (sw_bp)
+               retval = mpc5xxx_once_write(jtag_info, MPC5XXX_ONCE_OCR, 
MPC5XXX_OCR_DEBUG2, 32); /* leave SW BPs on */
+       else
+               retval = mpc5xxx_once_write(jtag_info, MPC5XXX_ONCE_OCR, 
MPC5XXX_OCR_DEBUG_OFF, 32);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* debug */
+               /* see what's in IACs */
+               retval = mpc5xxx_once_read(jtag_info, MPC57XX_ONCE_IAC1, &val, 
32);
+               if (retval != ERROR_OK)
+                       return retval;
+               printf("IAC1=0x%08x, ", val);
+               retval = mpc5xxx_once_read(jtag_info, MPC57XX_ONCE_IAC2, &val, 
32);
+               if (retval != ERROR_OK)
+                       return retval;
+               printf("IAC2=0x%08x, ", val);
+               retval = mpc5xxx_once_read(jtag_info, MPC57XX_ONCE_IAC3, &val, 
32);
+               if (retval != ERROR_OK)
+                       return retval;
+               printf("IAC3=0x%08x, ", val);
+               retval = mpc5xxx_once_read(jtag_info, MPC57XX_ONCE_IAC4, &val, 
32);
+               if (retval != ERROR_OK)
+                       return retval;
+               printf("IAC4=0x%08x\n", val);
+               /* end IACs */
+
+               retval = mpc5xxx_once_read(jtag_info, MPC5XXX_ONCE_OCR, &val, 
32);
+               if (retval != ERROR_OK)
+                       return retval;
+               printf("OCR=0x%08x\n", val);
+       /* end debug */
+
+       retval = mpc5xxx_once_cpuscr_read(jtag_info, &scr);
+       if (retval != ERROR_OK)
+               return retval;
+
+       scr.wbbrl = 0;
+       scr.wbbrh = 0;
+       scr.ir = MPC57XX_NOP ;
+       scr.pc = addr - 4 ;
+
+       retval = mpc5xxx_once_cpuscr_write(jtag_info, &scr);
+       if (retval != ERROR_OK)
+               return retval;
+
+       printf("Continuing @ 0x%08x...\n", addr);
+       retval = mpc5xxx_jtag_set_instr(jtag_info, MPC5XXX_ONCE_GO | 
MPC5XXX_ONCE_EX | MPC57XX_ONCE_NOREG);
+       if (retval)
+               return retval;
+
+       /* Freescale e200z3 RM has this CRITICAL tidbit:
+        * "In addition, the Update-DR state must also be transitioned through
+        * in order for the single-step and/or exit functionality to be 
performed"
+        */
+       retval = mpc5xxx_jtag_read_data(jtag_info, &val, 1); /* dummy read of 
one bit to force update-DR */
+       if (retval)
+               return retval;
+
+       if (sw_bp)
+               retval = mpc5xxx_once_write(jtag_info, MPC5XXX_ONCE_OCR, 
MPC5XXX_OCR_FDB, 32); /* leave SW BPs on */
+       else
+               retval = mpc5xxx_once_write(jtag_info, MPC5XXX_ONCE_OCR, 
MPC5XXX_OCR_DEBUG_OFF, 32);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = mpc5xxx_once_osr_read(jtag_info, &osr);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* Check no error */
+       if (osr & MPC5XXX_OSR_ERR) {
+               printf("1. OSR indicates failure of some kind. OSR = 0x%08x\n", 
osr);
+               return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static uint32_t bp_reg[MPC57XX_NUM_BPS] = {MPC57XX_ONCE_IAC1, 
MPC57XX_ONCE_IAC2,
+                                                                               
        MPC57XX_ONCE_IAC3, MPC57XX_ONCE_IAC4,
+                                                                               
        MPC57XX_ONCE_IAC5, MPC57XX_ONCE_IAC6,
+                                                                               
        MPC57XX_ONCE_IAC7, MPC57XX_ONCE_IAC8};
+static uint32_t bp_mask[MPC57XX_NUM_BPS] = {MPC57XX_DBCR0_IAC1, 
MPC57XX_DBCR0_IAC2,
+                                                                               
        MPC57XX_DBCR0_IAC3, MPC57XX_DBCR0_IAC4,
+                                                                               
        MPC57XX_DBCR0_IAC5, MPC57XX_DBCR0_IAC6,
+                                                                               
        MPC57XX_DBCR0_IAC7, MPC57XX_DBCR0_IAC8};
+
+int mpc57xx_jtag_set_bp(struct mpc5xxx_jtag *jtag_info, int bp_num, uint32_t 
bp_addr)
+{
+       int retval;
+       uint32_t dbcr0;
+
+       if ((bp_num < 0) || (bp_num >= MPC57XX_NUM_BPS))
+               return ERROR_FAIL;
+       retval = mpc5xxx_once_read(jtag_info, MPC57XX_ONCE_DBCR0, &dbcr0, 32);
+       if (retval)
+               return retval;
+
+       /* Write address to IAC register */
+       retval = mpc5xxx_once_write(jtag_info, bp_reg[bp_num], bp_addr, 32);
+       if (retval)
+               return retval;
+
+       /* clear status register for IAC (write a 1 to that bit) */
+       retval = mpc5xxx_once_write(jtag_info, MPC57XX_ONCE_EDBSR0, 
MPC57XX_DBSR_IAC, 32);
+       if (retval)
+               return retval;
+
+       /* Enable that breakpoint channel */
+       dbcr0 |= MPC5XXX_ONCE_DBCR0_EDM | bp_mask[bp_num];
+
+       retval = mpc5xxx_once_write(jtag_info, MPC57XX_ONCE_DBCR0, dbcr0, 32);
+       if (retval)
+               return retval;
+
+       /* Exact matches. No exclusions based on MSR. */
+       retval = mpc5xxx_once_write(jtag_info, MPC57XX_ONCE_DBCR1, 0, 32);
+       if (retval)
+               return retval;
+       /* Set reg to zero. */
+       retval = mpc5xxx_once_write(jtag_info, MPC57XX_ONCE_DBCR5, 0, 32);
+       if (retval)
+               return retval;
+       /* Set reg to zero. */
+       retval = mpc5xxx_once_write(jtag_info, MPC57XX_ONCE_DBCR6, 0, 32);
+       if (retval)
+               return retval;
+
+       return ERROR_OK;
+}
+
+/* Clear breakpoint and watchpoint enable bits.
+ * Use this before enabling to ensure only active BP/WP get used.
+ */
+int mpc57xx_jtag_clr_bps_wps(struct mpc5xxx_jtag *jtag_info)
+{
+       int retval;
+       uint32_t dbcr0, mask0;
+
+       mask0 = MPC57XX_DBCR0_IAC1 | MPC57XX_DBCR0_IAC2 | MPC57XX_DBCR0_IAC3 | 
MPC57XX_DBCR0_IAC4
+                       | MPC57XX_DBCR0_DAC1R | MPC57XX_DBCR0_DAC1W | 
MPC57XX_DBCR0_DAC2R | MPC57XX_DBCR0_DAC2W
+                       | MPC57XX_DBCR0_IAC5 | MPC57XX_DBCR0_IAC6 | 
MPC57XX_DBCR0_IAC7 | MPC57XX_DBCR0_IAC8;
+       /* Disable that breakpoint channel */
+       retval = mpc5xxx_once_read(jtag_info, MPC57XX_ONCE_DBCR0, &dbcr0, 32);
+       if (retval)
+               return retval;
+       dbcr0 &= ~mask0;
+       retval = mpc5xxx_once_write(jtag_info, MPC57XX_ONCE_DBCR0, dbcr0, 32);
+       if (retval)
+               return retval;
+
+       /* Clear all of those bits */
+       retval = mpc5xxx_once_write(jtag_info, MPC57XX_ONCE_EDBSR0, mask0, 32);
+       if (retval)
+               return retval;
+       exit(1); /* needs extending to other IACs and DACs */
+
+       return ERROR_OK;
+}
+
+int mpc57xx_jtag_clr_bp(struct mpc5xxx_jtag *jtag_info, int bp_num, uint32_t 
addr)
+{
+       int retval;
+       uint32_t dbcr0;
+
+       if ((bp_num < 0) || (bp_num >= MPC57XX_NUM_BPS))
+               return ERROR_FAIL;
+
+       /* Disable that breakpoint channel */
+       retval = mpc5xxx_once_read(jtag_info, MPC57XX_ONCE_DBCR0, &dbcr0, 32);
+       if (retval)
+               return retval;
+       dbcr0 &= ~bp_mask[bp_num];
+       retval = mpc5xxx_once_write(jtag_info, MPC57XX_ONCE_DBCR0, dbcr0, 32);
+       if (retval)
+               return retval;
+
+       /* Write a 1 to that bit to clear it */
+       retval = mpc5xxx_once_write(jtag_info, MPC57XX_ONCE_EDBSR0, 
bp_mask[bp_num], 32);
+       if (retval)
+               return retval;
+
+       return ERROR_OK;
+}
+
+static uint32_t wp_reg[MPC57XX_NUM_WPS] = {MPC57XX_ONCE_DAC1, 
MPC57XX_ONCE_DAC2};
+static uint32_t wp_mask[MPC57XX_NUM_WPS] = {MPC57XX_DBCR0_DAC1R | 
MPC57XX_DBCR0_DAC1W,
+                                                                               
        MPC57XX_DBCR0_DAC2R | MPC57XX_DBCR0_DAC2W};
+/* FIXME - only supporting DAC1,2 - need to add support for DAC3,4 */
+int mpc57xx_jtag_set_wp(struct mpc5xxx_jtag *jtag_info, int wp_num, uint32_t 
wp_addr)
+{
+       int retval;
+       uint32_t dbcr0;
+
+       if ((wp_num < 0) || (wp_num >= MPC57XX_NUM_WPS))
+               return ERROR_FAIL;
+       retval = mpc5xxx_once_read(jtag_info, MPC57XX_ONCE_DBCR0, &dbcr0, 32);
+       if (retval)
+               return retval;
+
+       /* Write address to DAC register */
+       retval = mpc5xxx_once_write(jtag_info, wp_reg[wp_num], wp_addr, 32);
+       if (retval)
+               return retval;
+
+       /* clear status register for that channel (write a 1 to that bit) */
+       retval = mpc5xxx_once_write(jtag_info, MPC57XX_ONCE_EDBSR0, 
wp_mask[wp_num], 32);
+       if (retval)
+               return retval;
+
+       /* Enable that breakpoint channel */
+       dbcr0 |= MPC5XXX_ONCE_DBCR0_EDM | wp_mask[wp_num];
+
+       retval = mpc5xxx_once_write(jtag_info, MPC57XX_ONCE_DBCR0, dbcr0, 32);
+       if (retval)
+               return retval;
+
+       /* Set for simple operation */
+       retval = mpc5xxx_once_write(jtag_info, MPC57XX_ONCE_DBCR2, 0, 32);
+       if (retval)
+               return retval;
+       retval = mpc5xxx_once_write(jtag_info, MPC57XX_ONCE_DBCR4, 0, 32);
+       if (retval)
+               return retval;
+
+       return ERROR_OK;
+}
+
+int mpc57xx_jtag_clr_wp(struct mpc5xxx_jtag *jtag_info, int wp_num, uint32_t 
addr)
+{
+       int retval;
+       uint32_t dbsr0;
+
+       if ((wp_num < 0) || (wp_num >= MPC57XX_NUM_WPS))
+               return ERROR_FAIL;
+
+       /* Disable that watchpoint channel */
+       retval = mpc5xxx_once_read(jtag_info, MPC57XX_ONCE_DBCR0, &dbsr0, 32);
+       if (retval)
+               return retval;
+       dbsr0 &= ~wp_mask[wp_num];
+       retval = mpc5xxx_once_write(jtag_info, MPC57XX_ONCE_DBCR0, dbsr0, 32);
+       if (retval)
+               return retval;
+
+       /* Write a 1 to that bit to clear it */
+       retval = mpc5xxx_once_write(jtag_info, MPC57XX_ONCE_EDBSR0, 
wp_mask[wp_num], 32);
+       if (retval)
+               return retval;
+
+       return ERROR_OK;
+}
+
+
+
+
+
+
diff --git a/src/target/mpc57xx_jtag.h b/src/target/mpc57xx_jtag.h
new file mode 100644
index 0000000..9118f64
--- /dev/null
+++ b/src/target/mpc57xx_jtag.h
@@ -0,0 +1,135 @@
+/***************************************************************************
+ *   Copyright (C) 2017 by James Murray <[email protected]                   *
+ *   Based on code:                                                        *
+ *       Copyright (C) 2010 by Oleksandr Tymoshenko <[email protected]>   *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifndef MPC57XX_JTAG
+#define MPC57XX_JTAG
+
+#include "mpc5xxx_jtag.h"
+
+/* TAP instructions from MPC5746RRM */
+
+#define MPC57XX_TAP_NAR                0x21
+#define MPC57XX_TAP_JDC                0x26
+#define MPC57XX_TAP_ONCE0      0x28
+#define MPC57XX_TAP_ONCE1      0x29
+#define MPC57XX_TAP_ETPU       0x30
+#define MPC57XX_TAP_NXMC_0     0x34
+#define MPC57XX_TAP_NXMC_1     0x35
+#define MPC57XX_TAP_SPU                0x3a
+#define MPC57XX_TAP_JTAGC_PD   0x3e /* only applies when Buddy Die in use */
+
+/*
+ * Registers
+ */
+/* Registers are lower 7 bits of 10 bit commands */
+#define MPC57XX_ONCE_DID               0b0000010
+#define MPC57XX_ONCE_CPUSCR            0b0010000
+#define MPC57XX_ONCE_NOREG             0b0010001
+/* See MPC5XXX_ONCE_OCR */
+#define MPC57XX_ONCE_DAC3              0b0011000
+#define MPC57XX_ONCE_DAC4              0b0011001
+#define MPC57XX_ONCE_IAC1              0b0100000
+#define MPC57XX_ONCE_IAC2              0b0100001
+#define MPC57XX_ONCE_IAC3              0b0100010
+#define MPC57XX_ONCE_IAC4              0b0100011
+#define MPC57XX_ONCE_DAC1              0b0100100
+#define MPC57XX_ONCE_DAC2              0b0100101
+#define MPC57XX_ONCE_DVC1              0b0100110
+#define MPC57XX_ONCE_DVC2              0b0100111
+#define MPC57XX_ONCE_IAC5              0b0101000
+#define MPC57XX_ONCE_IAC6              0b0101001
+#define MPC57XX_ONCE_IAC7              0b0101010
+#define MPC57XX_ONCE_IAC8              0b0101011
+#define MPC57XX_ONCE_DDEAR             0b0101100
+#define MPC57XX_ONCE_EDDEAR            0b0101101
+#define MPC57XX_ONCE_EDBCR0            0b0101110
+#define MPC57XX_ONCE_EDBSR0            0b0101111
+#define MPC57XX_ONCE_DBSR              0b0110000
+#define MPC57XX_ONCE_DBCR0             0b0110001
+#define MPC57XX_ONCE_DBCR1             0b0110010
+#define MPC57XX_ONCE_DBCR2             0b0110011
+/* There is no DBCR3 */
+#define MPC57XX_ONCE_DBCR4             0b0110101
+#define MPC57XX_ONCE_DBCR5             0b0110110
+#define MPC57XX_ONCE_DBCR6             0b0110111
+#define MPC57XX_ONCE_DBCR7             0b0111000
+#define MPC57XX_ONCE_DBCR8             0b0111001
+#define MPC57XX_ONCE_EDBSRMSK0 0b0111100
+#define MPC57XX_ONCE_DDAM              0b0111101
+#define MPC57XX_ONCE_DEVENT            0b0111110
+#define MPC57XX_ONCE_EDBRAC0   0b0111111
+
+#define MPC57XX_ONCE_MPU0CSR0  0b1101101
+#define MPC57XX_ONCE_PERFMON   0b1101110
+/* GPR selects [0:9] */
+#define MPC57XX_ONCE_CDACTL            0b1111010
+#define MPC57XX_ONCE_CDADATA   0b1111011
+/*  MPC56XX_ONCE_NEXUS use MPC5XXX_ONCE_NEXUS */
+#define MPC57XX_ONCE_LSRL              0b1111101
+#define MPC57XX_ONCE_ENABLE            0b1111110 /* Datasheet rather 
mysterious on this */
+#define MPC57XX_ONCE_BYPASS            0b1111111
+
+#define MPC57XX_ONCE_EDBRAC0_DEFAULT 0x00000180
+
+/* Many registers the same as 56xx.
+ * Nexus via OnCE the same.
+ */
+
+#define MPC57XX_NOP    0x60000000 /* need VLE equivalent */
+#define MPC57XX_SWBP   0x00000000 /* need VLE equivalent */
+#define MPC57XX_CPUSCR_CTL_FFRA        0x00000400
+#define MPC57XX_CPUSCR_CTL_PCOFST4     0x00001000
+
+#define MPC57XX_DBCR0_IAC1     0x00800000 /* masks apply to DBCR0 */
+#define MPC57XX_DBCR0_IAC2     0x00400000
+#define MPC57XX_DBCR0_IAC3     0x00200000
+#define MPC57XX_DBCR0_IAC4     0x00100000
+#define MPC57XX_DBCR0_IAC5     0x00004000
+#define MPC57XX_DBCR0_IAC6     0x00002000
+#define MPC57XX_DBCR0_IAC7     0x00001000
+#define MPC57XX_DBCR0_IAC8     0x00000800
+#define MPC57XX_DBCR0_DAC1R    0x00080000
+#define MPC57XX_DBCR0_DAC1W    0x00040000
+#define MPC57XX_DBCR0_DAC2R    0x00020000
+#define MPC57XX_DBCR0_DAC2W    0x00010000
+#define MPC57XX_DBSR_DACW      0x00040000
+#define MPC57XX_DBSR_DACR      0x00080000
+#define MPC57XX_DBSR_IAC       0x00800000
+#define MPC57XX_DBSR_VLES      0x00000010
+
+#define MPC57XX_NUM_BPS        8
+#define MPC57XX_NUM_WPS        2 /* actually 4, but 3,4 not yet implemented */
+
+#define MPC57XX_EI_VAL         0x01 /* ? */
+#define MPC57XX_EI_INC         0x02 /* ? */
+#define MPC57XX_EI_MASKINT     0x04 /* ? */
+
+int mpc57xx_enter_debug(struct mpc5xxx_jtag *jtag_info, int async_flag);
+int mpc57xx_leave_debug(struct mpc5xxx_jtag *jtag_info);
+int mpc57xx_enable_once(struct mpc5xxx_jtag *jtag_info);
+int mpc57xx_exec_inst(struct mpc5xxx_jtag *jtag_info, uint32_t inst, uint32_t 
in,
+               uint32_t *out, uint32_t flag);
+int mpc57xx_exit_debug(struct mpc5xxx_jtag *jtag_info, uint32_t addr, int 
sw_bp, uint32_t ctl_on_entry);
+int mpc57xx_jtag_set_bp(struct mpc5xxx_jtag *jtag_info, int bp_num, uint32_t 
addr);
+int mpc57xx_jtag_clr_bps_wps(struct mpc5xxx_jtag *jtag_info);
+int mpc57xx_jtag_clr_bp(struct mpc5xxx_jtag *jtag_info, int bp_num, uint32_t 
addr);
+int mpc57xx_jtag_set_wp(struct mpc5xxx_jtag *jtag_info, int bp_num, uint32_t 
addr);
+int mpc57xx_jtag_clr_wp(struct mpc5xxx_jtag *jtag_info, int bp_num, uint32_t 
addr);
+
+#endif /* MPC57XX_JTAG */
diff --git a/src/target/mpc57xx_regs.c b/src/target/mpc57xx_regs.c
new file mode 100644
index 0000000..95d5fb3
--- /dev/null
+++ b/src/target/mpc57xx_regs.c
@@ -0,0 +1,318 @@
+/***************************************************************************
+ *   Copyright (C) 2017 by James Murray <[email protected]                   *
+ *   Based on code:                                                        *
+ *       Copyright (C) 2010 by Oleksandr Tymoshenko <[email protected]>   *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "target.h"
+#include "jtag/jtag.h"
+#include "mpc5xxx_jtag.h"
+#include "mpc5xxx.h"
+#include "mpc57xx_jtag.h"
+#include "mpc57xx_regs.h"
+
+static int mpc57xx_read_gpr(struct mpc5xxx_jtag *jtag_info, int reg,
+               uint32_t *val)
+{
+       uint32_t opcode;
+
+       if ((reg < 0) || (reg > 31)) {
+               LOG_ERROR("Invalid GP register %d requested!", reg);
+               printf("Invalid GP register %d requested!\n", reg);
+               *val = 0;
+               return ERROR_FAIL;
+       }
+       opcode = 0x60000000 | (reg << 16) | (reg << 21); /* ori Rx, Rx, 0 */
+       return mpc57xx_exec_inst(jtag_info, opcode, 0, val, 0);
+}
+
+static int mpc57xx_write_gpr(struct mpc5xxx_jtag *jtag_info, int reg,
+               uint32_t val)
+{
+       uint32_t val2, opcode;
+
+       if ((reg < 0) || (reg > 31)) {
+               LOG_ERROR("Invalid GP register %d requested!", reg);
+               printf("Invalid GP register %d requested!\n", reg);
+               return ERROR_FAIL;
+       }
+
+       opcode = 0x60000000 | (reg << 16) | (reg << 21); /* ori Rx, Rx, 0 */
+       return mpc57xx_exec_inst(jtag_info, opcode, val, &val2, MPC57XX_EI_VAL);
+}
+
+int mpc57xx_read_spr(struct mpc5xxx_jtag *jtag_info, int reg,
+               uint32_t *val)
+{
+       int retval;
+       uint32_t opcode, r31;
+
+       if ((reg < 0) || (reg > 1023)) {
+               LOG_ERROR("Invalid SP register %d requested!", reg);
+               printf("Invalid SP register %d requested!\n", reg);
+               *val = 0;
+               return ERROR_FAIL;
+       }
+       /* Preserve R31 */
+       retval = mpc57xx_read_gpr(jtag_info, MPC5XXX_REG_R31, &r31);
+       if (retval)
+               return retval;
+
+       /* Transfer special purpose register to R31 */
+       opcode = 0x7fe002a6 | ((reg & 0x1f) << 16) | ((reg & 0x3e0) << 6); /* 
mpspr r31, reg */
+       retval = mpc57xx_exec_inst(jtag_info, opcode, 0, val, 0);
+
+       /* Restore R31 */
+       return mpc57xx_write_gpr(jtag_info, MPC5XXX_REG_R31, r31);
+}
+
+int mpc57xx_write_spr(struct mpc5xxx_jtag *jtag_info, int reg,
+               uint32_t val)
+{
+       uint32_t opcode;
+
+       if ((reg < 0) || (reg > 1023)) {
+               LOG_ERROR("Invalid SP register %d requested!", reg);
+               printf("Invalid SP register %d requested!\n", reg);
+               return ERROR_FAIL;
+       }
+
+       /* Transfer value to special purpose register */
+       opcode = 0x7fe003a6 | ((reg & 0x1f) << 16) | ((reg & 0x3e0) << 6); /* 
mtspr reg, r31 */
+       return mpc57xx_exec_inst(jtag_info, opcode, val, &val, MPC57XX_EI_VAL);
+}
+
+static int mpc57xx_read_cr(struct mpc5xxx_jtag *jtag_info, uint32_t *val)
+{
+       int retval;
+       uint32_t opcode, r31;
+
+       /* Preserve R31 */
+       retval = mpc57xx_read_gpr(jtag_info, MPC5XXX_REG_R31, &r31);
+       if (retval)
+               return retval;
+
+       /* Transfer condition register to R31 */
+       opcode = 0x7fe00026; /* mfcr r31 */
+       retval = mpc57xx_exec_inst(jtag_info, opcode, 0, val, 0);
+
+       /* Restore R31 */
+       return mpc57xx_write_gpr(jtag_info, MPC5XXX_REG_R31, r31);
+}
+
+static int mpc57xx_write_cr(struct mpc5xxx_jtag *jtag_info, uint32_t val)
+{
+       uint32_t opcode;
+
+       /* Transfer value to condition register */
+       opcode = 0x7feff120; /* mtcr r31 */
+       return mpc57xx_exec_inst(jtag_info, opcode, val, &val, MPC57XX_EI_VAL);
+}
+
+static int mpc57xx_read_ctr(struct mpc5xxx_jtag *jtag_info, uint32_t *val)
+{
+       int retval;
+       uint32_t opcode, r31;
+
+       /* Preserve R31 - may not be necessary ? */
+       retval = mpc57xx_read_gpr(jtag_info, MPC5XXX_REG_R31, &r31);
+       if (retval)
+               return retval;
+
+       /* Transfer condition register to R31 */
+       opcode = 0x7fe902a6; /* mfctr r31 */
+       retval = mpc57xx_exec_inst(jtag_info, opcode, 0, val, 0);
+
+       /* Restore R31 */
+       return mpc57xx_write_gpr(jtag_info, MPC5XXX_REG_R31, r31);
+}
+
+static int mpc57xx_write_ctr(struct mpc5xxx_jtag *jtag_info, uint32_t val)
+{
+       uint32_t opcode;
+
+       /* Transfer value to condition register */
+       opcode = 0x7fe903a6; /* mtctr r31 */
+       return mpc57xx_exec_inst(jtag_info, opcode, val, &val, MPC57XX_EI_VAL);
+}
+
+static int mpc57xx_read_lr(struct mpc5xxx_jtag *jtag_info, uint32_t *val)
+{
+       int retval;
+       uint32_t opcode, r31;
+
+       /* Preserve R31 - may not be necessary ? */
+       retval = mpc57xx_read_gpr(jtag_info, MPC5XXX_REG_R31, &r31);
+       if (retval)
+               return retval;
+
+       /* Transfer condition register to R31 */
+       opcode = 0x7fe802a6; /* mflr r31 */
+       retval = mpc57xx_exec_inst(jtag_info, opcode, 0, val, 0);
+
+       /* Restore R31 */
+       return mpc57xx_write_gpr(jtag_info, MPC5XXX_REG_R31, r31);
+}
+
+static int mpc57xx_write_lr(struct mpc5xxx_jtag *jtag_info, uint32_t val)
+{
+       uint32_t opcode;
+
+       /* Transfer value to condition register */
+       opcode = 0x7fe803a6; /* mtlr r31 */
+       return mpc57xx_exec_inst(jtag_info, opcode, val, &val, MPC57XX_EI_VAL);
+}
+
+int mpc57xx_read_reg(struct mpc5xxx_jtag *jtag_info, int reg,
+               uint32_t *val)
+{
+       int retval;
+       struct mpc5xxx_cpuscr scr;
+
+       if (reg < 0) {
+               LOG_ERROR("Invalid negative register %d requested", reg);
+               printf("Invalid GP register %d requested!\n", reg);
+               *val = 0;
+               return ERROR_OK;
+       } else if (reg < 32) {
+               retval = mpc57xx_read_gpr(jtag_info, reg, val);
+       } else if (reg == MPC5XXX_REG_PC) {
+               retval = mpc5xxx_once_cpuscr_read(jtag_info, &scr);
+               *val = scr.pc;
+               printf("Read of PC = 0x%08x\n", *val);
+       } else if (reg == MPC5XXX_REG_MSR) {
+               retval = mpc5xxx_once_cpuscr_read(jtag_info, &scr);
+               *val = scr.msr;
+       } else if (reg == MPC5XXX_REG_CND) {
+               retval = mpc57xx_read_cr(jtag_info, val);
+       } else if (reg == MPC5XXX_REG_LR) {
+               retval = mpc57xx_read_lr(jtag_info, val);
+       } else if (reg == MPC5XXX_REG_CNT) { /* This is CTR ? */
+               retval = mpc57xx_read_ctr(jtag_info, val);
+       } else if (reg == MPC5XXX_REG_XER) {
+               retval = mpc57xx_read_spr(jtag_info, 1, val);
+       } else if (reg == MPC5XXX_REG_MQ) {
+               /* Ignore MQ */
+               *val = 0;
+               retval = ERROR_OK;
+       } else {
+               /* Faking read of register */
+               *val = 0;
+               retval = ERROR_OK;
+       }
+
+       return retval;
+}
+
+int mpc57xx_write_reg(struct mpc5xxx_jtag *jtag_info, int reg,
+               uint32_t val)
+{
+       int retval;
+       struct mpc5xxx_cpuscr scr;
+
+       if (reg < 0) {
+               LOG_ERROR("Invalid negative register %d requested", reg);
+               printf("Invalid GP register %d requested!\n", reg);
+               return ERROR_OK;
+       } else if (reg < 32) {
+               retval = mpc57xx_write_gpr(jtag_info, reg, val);
+       } else if (reg == MPC5XXX_REG_PC) {
+               retval = mpc5xxx_once_cpuscr_read(jtag_info, &scr);
+               if (retval)
+                       return retval;
+               printf("Writing PC = 0x%08x\n", val);
+               scr.pc = val;
+               retval = mpc5xxx_once_cpuscr_write(jtag_info, &scr);
+       } else if (reg == MPC5XXX_REG_MSR) {
+               retval = mpc5xxx_once_cpuscr_read(jtag_info, &scr);
+               if (retval)
+                       return retval;
+               scr.msr = val;
+               retval = mpc5xxx_once_cpuscr_write(jtag_info, &scr);
+       } else if (reg == MPC5XXX_REG_CND) {
+               retval = mpc57xx_write_cr(jtag_info, val);
+       } else if (reg == MPC5XXX_REG_LR) {
+               retval = mpc57xx_write_lr(jtag_info, val);
+       } else if (reg == MPC5XXX_REG_CNT) { /* This is CTR ? */
+               retval = mpc57xx_write_ctr(jtag_info, val);
+       } else if (reg == MPC5XXX_REG_XER) {
+               retval = mpc57xx_write_spr(jtag_info, 1, val);
+       } else if (reg == MPC5XXX_REG_MQ) {
+               /* Ignore MQ */
+               retval = ERROR_OK;
+       } else {
+               /*printf("Faking write_reg %d\n", reg);*/
+               retval = ERROR_OK;
+       }
+
+       return retval;
+}
+
+int mpc57xx_jtag_read_regs(struct mpc5xxx_jtag *jtag_info, uint32_t *regs, 
uint32_t * saved_ctl)
+{
+       int i, retval;
+
+       /* read core registers */
+       /* read in PC and MSR first, as they get wiped out and affected by 
later ops */
+       struct mpc5xxx_cpuscr scr;
+
+       retval = mpc5xxx_once_cpuscr_read(jtag_info, &scr);
+       if (retval)
+                       return retval;
+
+       regs[MPC5XXX_REG_PC]  = scr.pc ;
+       regs[MPC5XXX_REG_MSR] = scr.msr ;
+       if (saved_ctl)
+               *saved_ctl = scr.ctl ;
+
+
+       /* turn off interrupts and lie about it in regs[msr] */
+
+       scr.msr &= ~MPC5XXX_MSR_EE ;
+       mpc5xxx_once_cpuscr_write(jtag_info, &scr) ;
+
+       for (i = 0; i < MPC5XXX_NUMCOREREGS - 1; i++) {
+               if (!(i == MPC5XXX_REG_PC || i == MPC5XXX_REG_MSR)) {
+                       retval = mpc57xx_read_reg(jtag_info, i, regs + i);
+                       if (retval)
+                               return retval;
+                       if (i == (MPC5XXX_NUMCOREREGS >> 1))
+                               keep_alive();
+               }
+       }
+
+       return ERROR_OK;
+}
+
+int mpc57xx_jtag_write_regs(struct mpc5xxx_jtag *jtag_info, uint32_t *regs)
+{
+       int i, retval;
+
+       /*
+        * And now the rest of registers
+        */
+       for (i = 0; i < MPC5XXX_NUMCOREREGS - 1; i++) {
+               retval = mpc57xx_write_reg(jtag_info, i, regs[i]);
+               if (retval)
+                       return retval;
+       }
+
+       return ERROR_OK;
+}
diff --git a/src/target/mpc57xx_regs.h b/src/target/mpc57xx_regs.h
new file mode 100644
index 0000000..98600d1
--- /dev/null
+++ b/src/target/mpc57xx_regs.h
@@ -0,0 +1,32 @@
+/***************************************************************************
+ *   Copyright (C) 2017 by James Murray <[email protected]                   *
+ *   Based on code:                                                        *
+ *       Copyright (C) 2010 by Oleksandr Tymoshenko <[email protected]>   *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifndef MPC57XX_REGS
+#define MPC57XX_REGS
+
+#include "mpc56xx_regs.h"
+
+int mpc57xx_jtag_read_regs(struct mpc5xxx_jtag *jtag_info, uint32_t *regs, 
uint32_t *saved_ctl);
+int mpc57xx_jtag_write_regs(struct mpc5xxx_jtag *jtag_info, uint32_t *regs);
+int mpc57xx_read_reg(struct mpc5xxx_jtag *jtag_info, int reg, uint32_t *val);
+int mpc57xx_write_reg(struct mpc5xxx_jtag *jtag_info, int reg, uint32_t val);
+int mpc57xx_write_spr(struct mpc5xxx_jtag *jtag_info, int reg, uint32_t val);
+int mpc57xx_read_spr(struct mpc5xxx_jtag *jtag_info, int reg, uint32_t *val) ;
+
+#endif /* MPC57XX_REGS */

-- 

Reply via email to