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 *)¤t_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 *)¤t_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 *)¤t_instr); + if (retval != ERROR_OK) + return retval; + current_instr = target_buffer_get_u16(target, (uint8_t *)¤t_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 */ --
