This is an automated email from Gerrit.

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

-- gerrit

commit 7e42271e3860c2c5f9b8e400f51bfff316329f15
Author: Angelo Dureghello <[email protected]>
Date:   Wed Feb 15 21:05:29 2017 +0100

    target: mcf5441x: add support for mcf5441x Coldfire family
    
    add support for mcf5441x family using BDM 26pin (bdm_cf26.c).
    
    Change-Id: I4042a75455024aefde9c22d64476bc0d07285ea1
    Signed-off-by: Angelo Dureghello <[email protected]>

diff --git a/src/target/Makefile.am b/src/target/Makefile.am
index 62c5fb5..7b456a8 100644
--- a/src/target/Makefile.am
+++ b/src/target/Makefile.am
@@ -106,7 +106,8 @@ AVR32_SRC = \
        %D%/avr32_regs.c
 
 BDM_CF26_SRC = \
-       %D%/bdm_cf26.c
+       %D%/bdm_cf26.c \
+       %D%/mcf5441x.c
 
 MIPS32_SRC = \
        %D%/mips32.c \
diff --git a/src/target/mcf5441x.c b/src/target/mcf5441x.c
new file mode 100644
index 0000000..115156c
--- /dev/null
+++ b/src/target/mcf5441x.c
@@ -0,0 +1,778 @@
+/***************************************************************************
+ *                                                                         *   
                                       *
+ *   Copyright (C) 2017 by Angelo Dureghello                               *
+ *   [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; see the file COPYING.  If not see            *
+ *   <http://www.gnu.org/licenses/>                                        *
+ *                                                                         *
+ ***************************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <jtag/jtag.h>
+#include <jtag/interface.h>
+#include <binarybuffer.h>
+
+#include "breakpoints.h"
+#include "target.h"
+#include "algorithm.h"
+#include "register.h"
+#include "target_type.h"
+#include "bdm_cf26.h"
+#include "mcf5441x.h"
+#include "log.h"
+
+static const struct {
+       unsigned id;
+       const char *name;
+       unsigned bits;
+       enum reg_type type;
+       const char *group;
+       const char *feature;
+} mcf5441x_registers_table[] = {
+       { CF_D0, "d0", 32, REG_TYPE_INT, "general", "org.gnu.gdb.coldfire.core" 
},
+       { CF_D1, "d1", 32, REG_TYPE_INT, "general", "org.gnu.gdb.coldfire.core" 
},
+       { CF_D2, "d2", 32, REG_TYPE_INT, "general", "org.gnu.gdb.coldfire.core" 
},
+       { CF_D3, "d3", 32, REG_TYPE_INT, "general", "org.gnu.gdb.coldfire.core" 
},
+       { CF_D4, "d4", 32, REG_TYPE_INT, "general", "org.gnu.gdb.coldfire.core" 
},
+       { CF_D5, "d5", 32, REG_TYPE_INT, "general", "org.gnu.gdb.coldfire.core" 
},
+       { CF_D6, "d6", 32, REG_TYPE_INT, "general", "org.gnu.gdb.coldfire.core" 
},
+       { CF_D7, "d7", 32, REG_TYPE_INT, "general", "org.gnu.gdb.coldfire.core" 
},
+       { CF_A0, "a0", 32, REG_TYPE_DATA_PTR, "data_ptr", 
"org.gnu.gdb.coldfire.core" },
+       { CF_A1, "a1", 32, REG_TYPE_DATA_PTR, "data_ptr", 
"org.gnu.gdb.coldfire.core" },
+       { CF_A2, "a2", 32, REG_TYPE_DATA_PTR, "data_ptr", 
"org.gnu.gdb.coldfire.core" },
+       { CF_A3, "a3", 32, REG_TYPE_DATA_PTR, "data_ptr", 
"org.gnu.gdb.coldfire.core" },
+       { CF_A4, "a4", 32, REG_TYPE_DATA_PTR, "data_ptr", 
"org.gnu.gdb.coldfire.core" },
+       { CF_A5, "a5", 32, REG_TYPE_DATA_PTR, "data_ptr", 
"org.gnu.gdb.coldfire.core" },
+       { CF_FP, "fp", 32, REG_TYPE_DATA_PTR, "data_ptr", 
"org.gnu.gdb.coldfire.core" },
+       { CF_SP, "sp", 32, REG_TYPE_DATA_PTR, "data_ptr", 
"org.gnu.gdb.coldfire.core" },
+       { CF_PS, "ps", 32, REG_TYPE_INT, "general", "org.gnu.gdb.coldfire.core" 
},
+       { CF_PC, "pc", 32, REG_TYPE_CODE_PTR, "code_ptr", 
"org.gnu.gdb.coldfire.core" },
+       { CF_VBR, "vbr", 32, REG_TYPE_DATA_PTR, "data_ptr", 
"org.gnu.gdb.coldfire.core" },
+};
+
+#define CF_NUM_REGS    ARRAY_SIZE(mcf5441x_registers_table)
+
+struct mcf5441x_reg {
+       struct target *target;
+};
+
+static int mcf5441x_poll(struct target *target)
+{
+       enum target_state prev_target_state = target->state;
+       uint32_t csr;
+
+       csr = bdm_cf26_read_dm_reg(target, BDM_REG_CSR);
+
+       if ((csr & CSR_BPKT) || (csr & CSR_HALT)) {
+
+               target->state = TARGET_HALTED;
+
+               if ((prev_target_state == TARGET_RUNNING) ||
+                       (prev_target_state == TARGET_RESET)) {
+
+                       target_call_event_callbacks(target, 
TARGET_EVENT_HALTED);
+
+                       if (mcf5441x_debug_entry(target) != ERROR_OK)
+                               LOG_WARNING("can't set debug entry");
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int mcf5441x_read_core_reg(struct mcf5441x *mcf5441x, struct reg *reg)
+{
+       int32_t ret;
+       struct target *target = mcf5441x->target;
+
+       assert(reg->number < mcf5441x->core_cache->num_regs);
+
+       if (target->state != TARGET_HALTED)
+               return ERROR_TARGET_NOT_HALTED;
+
+       /* special cases */
+       if (reg->number == CF_PC)
+               ret = bdm_cf26_read_pc(target);
+       else
+               ret = bdm_cf26_read_ad_reg(target, reg->number);
+
+       buf_set_u32(reg->value, 0, 32, ret);
+       reg->valid = 1;
+       reg->dirty = 0;
+
+       return ERROR_OK;
+}
+
+static int mcf5441x_write_core_reg(struct mcf5441x *mcf5441x,
+                                  struct reg *reg, uint8_t *value)
+{
+       int ret, regval;
+       struct target *target = mcf5441x->target;
+
+       if (target->state != TARGET_HALTED)
+               LOG_WARNING("target not halted");
+
+       regval = buf_get_u32(value, 0, 32);
+
+       assert(reg->number < mcf5441x->core_cache->num_regs);
+
+       /* special cases */
+       if (reg->number == CF_PC)
+               ret = bdm_cf26_write_pc(target, regval);
+       else
+               ret = bdm_cf26_write_ad_reg(target, reg->number, regval);
+
+       if (ret != ERROR_OK) {
+               LOG_ERROR("BDM failure");
+               reg->dirty = reg->valid;
+               return ERROR_JTAG_DEVICE_ERROR;
+       }
+
+       reg->valid = 1;
+       reg->dirty = 0;
+
+       return ERROR_OK;
+}
+
+static int mcf5441x_get_core_reg(struct reg *reg)
+{
+       struct mcf5441x_reg *mcfreg;
+       struct target *target;
+       struct mcf5441x *cpu;
+
+       mcfreg = reg->arch_info;
+       target = mcfreg->target;
+       cpu = target_to_mcf5441x(target);
+
+       if (target->state != TARGET_HALTED)
+               return ERROR_TARGET_NOT_HALTED;
+
+       return cpu->read_core_reg(cpu, reg);
+}
+
+static int mcf5441x_set_core_reg(struct reg *reg, uint8_t *buf)
+{
+       struct mcf5441x_reg *mcfreg;
+       struct target *target;
+       uint32_t value;
+
+       mcfreg = reg->arch_info;
+       target = mcfreg->target;
+
+       if (target->state != TARGET_HALTED)
+               return ERROR_TARGET_NOT_HALTED;
+
+       value = buf_get_u32(buf, 0, 32);
+       buf_set_u32(reg->value, 0, 32, value);
+
+       reg->dirty = 1;
+       reg->valid = 1;
+
+       return ERROR_OK;
+}
+
+static const struct reg_arch_type mcf5441x_reg_type = {
+       .get = mcf5441x_get_core_reg,
+       .set = mcf5441x_set_core_reg,
+};
+
+/**
+ * Restores target context using the cache of core registers set up
+ * by mcf5441x_build_reg_cache(), calling optional core-specific hooks.
+ */
+static int mcf5441x_restore_context(struct target *target)
+{
+       int i;
+       struct mcf5441x *cpu = target_to_mcf5441x(target);
+       struct reg_cache *cache = cpu->core_cache;
+
+       for (i = cache->num_regs - 1; i >= 0; i--) {
+               if (cache->reg_list[i].dirty) {
+                       cpu->write_core_reg(cpu,
+                               &cache->reg_list[i],
+                               (uint8_t *)cache->reg_list[i].value);
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int mcf5441x_disable_breakpoints(struct target *target)
+{
+       int ret;
+       struct breakpoint *breakpoint = target->breakpoints;
+
+       /* set any pending breakpoints */
+       while (breakpoint) {
+               if (breakpoint->set) {
+                       ret = mcf5441x_unset_breakpoint(target, breakpoint);
+                       if (ret != ERROR_OK) {
+                               LOG_ERROR("Failed to unset breakpoint");
+                               break;
+                       }
+               }
+               breakpoint = breakpoint->next;
+       }
+
+       return ERROR_OK;
+}
+
+static int mcf5441x_enable_breakpoints(struct target *target)
+{
+       int ret;
+       struct breakpoint *breakpoint = target->breakpoints;
+
+       /* set any pending breakpoints */
+       while (breakpoint) {
+               if (!breakpoint->set) {
+                       ret = mcf5441x_set_breakpoint(target, breakpoint);
+                       if (ret != ERROR_OK) {
+                               LOG_ERROR("Failed to set breakpoint");
+                               break;
+                       }
+               }
+               breakpoint = breakpoint->next;
+       }
+
+       return ERROR_OK;
+}
+
+static int mcf5441x_step(struct target *target, int current,
+                        target_addr_t address, int handle_breakpoints)
+{
+       struct mcf5441x *cpu = target_to_mcf5441x(target);
+       uint32_t value;
+       int ret;
+
+       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) {
+               LOG_INFO("mcf5441x_step() not current");
+               buf_set_u32(cpu->pc->value, 0, 32, address);
+               cpu->pc->dirty = 1;
+       }
+
+       target->debug_reason = DBG_REASON_SINGLESTEP;
+
+       /*
+        * restoring context now, before go
+        */
+       mcf5441x_restore_context(target);
+
+       target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
+
+       /*
+        * getting CRS and re-setting for step
+        */
+       value = bdm_cf26_read_dm_reg(target, BDM_REG_CSR);
+       /* setting in step, no interrupt */
+       value |= (CSR_SSM | CSR_IPI);
+       /* emulator mode */
+       value |= CSR_EMULATION;
+       bdm_cf26_write_dm_reg(target, BDM_REG_CSR, value);
+
+       /*
+        * ColdFire is magic, is magic, oh-oh-oh, the summer is magic
+        *
+        * With BDM in STEP + EMULATION mode, cpu caches somewhere a group
+        * of program instructions just after each go-step (go performs a step).
+        * We need to remove all the breakpoints so, or it will remember
+        * of them even if they are not there anymore.
+        */
+       mcf5441x_disable_breakpoints(target);
+
+       /* ok, go now acts as single step */
+       ret = bdm_cf26_go(target);
+       if (ret < 0) {
+               LOG_ERROR("Failed to resume execution");
+               return ret;
+       }
+
+       if (mcf5441x_debug_entry(target) != ERROR_OK)
+               LOG_WARNING("can't set debug entry");
+
+       /* now we should be halted with new reg read */
+       target_call_event_callbacks(target, TARGET_EVENT_HALTED);
+
+       return ERROR_OK;
+}
+
+static int mcf5441x_set_breakpoint(struct target *target,
+                                struct breakpoint *breakpoint)
+{
+       int retval;
+
+       if (breakpoint->set) {
+               LOG_WARNING("breakpoint (BPID: %" PRIu32 ") already set",
+                           breakpoint->unique_id);
+               return ERROR_OK;
+       }
+
+       if (breakpoint->type == BKPT_HARD) {
+               /* TODO: gdb / kdevelop actually asks for SW breakpoints
+                * only */
+       } else if (breakpoint->type == BKPT_SOFT) {
+
+               uint8_t code[2];
+
+               /*
+                * technique is to replace current memory location
+                * with an HALT.
+                */
+               retval = target_read_memory(target,
+                               breakpoint->address,
+                               breakpoint->length, 1,
+                               breakpoint->orig_instr);
+
+               if (retval != ERROR_OK)
+                       return retval;
+
+               /* swap to LE is done inside bdm_cf26_write_mem_word
+                */
+               h_u16_to_be(code, CF_OP_HALT);
+               retval = target_write_memory(target,
+                               breakpoint->address,
+                               breakpoint->length, 1,
+                               code);
+
+               if (retval != ERROR_OK)
+                       return retval;
+
+               breakpoint->set = true;
+       }
+
+       LOG_DEBUG("BPID: %" PRIu32 ", Type: %d, Address: 0x%08lx" PRIx32
+               " Length: %d (set=%d)",
+               breakpoint->unique_id,
+               (int)(breakpoint->type),
+               breakpoint->address,
+               breakpoint->length,
+               breakpoint->set);
+
+       return ERROR_OK;
+}
+
+static int mcf5441x_unset_breakpoint(struct target *target,
+                                struct breakpoint *breakpoint)
+{
+       int retval;
+
+       if (!breakpoint->set) {
+               LOG_WARNING("breakpoint not set");
+               return ERROR_OK;
+       }
+
+       LOG_DEBUG("BPID: %" PRIu32 ", Type: %d, Address: 0x%08lx" PRIx32
+               " Length: %d (set=%d)",
+               breakpoint->unique_id,
+               (int)(breakpoint->type),
+               breakpoint->address,
+               breakpoint->length,
+               breakpoint->set);
+
+       if (breakpoint->type == BKPT_HARD) {
+               /* TODO */
+       } else {
+               /* restore original instruction (kept in target endianness) */
+               retval = target_write_memory(target,
+                               breakpoint->address,
+                               breakpoint->length, 1,
+                               breakpoint->orig_instr);
+
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+       breakpoint->set = false;
+
+       return ERROR_OK;
+}
+
+static int mcf5441x_add_breakpoint(struct target *target,
+                                  struct breakpoint *breakpoint)
+{
+       return mcf5441x_set_breakpoint (target, breakpoint);
+}
+
+static int mcf5441x_remove_breakpoint(struct target *target,
+                                  struct breakpoint *breakpoint)
+{
+       if (breakpoint->set)
+               mcf5441x_unset_breakpoint(target, breakpoint);
+
+       return ERROR_OK;
+}
+
+static int mcf5441x_resume(struct target *target, int current,
+                       target_addr_t address,
+                       int handle_breakpoints, int debug_execution)
+{
+       struct mcf5441x *cpu = target_to_mcf5441x(target);
+       uint32_t value;
+       int ret;
+
+       if (target->state != TARGET_HALTED) {
+               LOG_WARNING("target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (!debug_execution)
+               mcf5441x_enable_breakpoints(target);
+
+       ret = mcf5441x_restore_context(target);
+       if (ret != ERROR_OK) {
+               LOG_ERROR("Failed to restore register context");
+               return ret;
+       }
+
+       /* the front-end may request us not to handle breakpoints */
+
+       /* removing any emulation mode from CSR */
+       value = bdm_cf26_read_dm_reg(target, BDM_REG_CSR);
+       /* setting in step, no interrupt */
+       value &= ~(CSR_SSM | CSR_IPI);
+       /* emulator mode */
+       value &= ~CSR_EMULATION;
+       bdm_cf26_write_dm_reg(target, BDM_REG_CSR, value);
+
+       /* Restart core */
+       ret = bdm_cf26_go(target);
+       if (ret < 0) {
+               LOG_ERROR("Failed to resume execution");
+               return ret;
+       }
+
+       target->debug_reason = DBG_REASON_NOTHALTED;
+
+       /* registers are now invalid */
+       register_cache_invalidate(cpu->core_cache);
+
+       if (!debug_execution) {
+               target->state = TARGET_RUNNING;
+               target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
+               LOG_DEBUG("target resumed");
+       } else {
+               target->state = TARGET_DEBUG_RUNNING;
+               target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED);
+               LOG_DEBUG("target debug resumed");
+       }
+
+       return ERROR_OK;
+}
+
+static int mcf5441x_assert_reset(struct target *target)
+{
+       bdm_cf26_assert_reset(target);
+
+       target->state = TARGET_RESET;
+
+       return ERROR_OK;
+}
+
+static int mcf5441x_deassert_reset(struct target *target)
+{
+       bdm_cf26_deassert_reset(target);
+
+       return ERROR_OK;
+}
+
+static int mcf5441x_setup_all_cpu_regs(struct target *target, uint8_t *reg_buf)
+{
+       int i;
+       uint32_t value;
+       struct mcf5441x *cpu = target_to_mcf5441x(target);
+       struct reg_cache *cache = cpu->core_cache;
+
+       for (i = CF_SP; i >= 0; i--) {
+               value = be_to_h_u32(reg_buf);
+               buf_set_u32(cache->reg_list[i].value, 0, 32, value);
+               cache->reg_list[i].valid = 1;
+               reg_buf += sizeof(uint32_t) + sizeof(uint16_t);
+       }
+
+       /* ok, misaligned rest now (different order in pemu buffer) */
+       value = be_to_h_u32(reg_buf);
+       buf_set_u32(cache->reg_list[CF_PC].value, 0, 32, value);
+       cache->reg_list[CF_PC].valid = 1;
+       reg_buf += sizeof(uint32_t) + sizeof(uint16_t);
+       value = be_to_h_u32(reg_buf);
+       buf_set_u32(cache->reg_list[CF_VBR].value, 0, 32, value);
+       cache->reg_list[CF_VBR].valid = 1;
+       reg_buf += sizeof(uint32_t) + sizeof(uint16_t);
+       value = be_to_h_u32(reg_buf);
+       buf_set_u32(cache->reg_list[CF_PS].value, 0, 32, value);
+       cache->reg_list[CF_PS].valid = 1;
+
+       return ERROR_OK;
+}
+
+static int mcf5441x_debug_entry(struct target *target)
+{
+       struct mcf5441x *cpu = target_to_mcf5441x(target);
+       struct reg_cache *cache = cpu->core_cache;
+       struct breakpoint *breakpoint;
+       uint8_t *reg_buf;
+
+       bdm_cf26_get_all_cpu_regs(target, &reg_buf);
+       mcf5441x_setup_all_cpu_regs(target, reg_buf);
+
+       uint32_t pc_value = buf_get_u32(cpu->pc->value, 0, 32);
+
+       breakpoint = breakpoint_find(target, pc_value - 2);
+       if (breakpoint) {
+               mcf5441x_unset_breakpoint(target, breakpoint);
+
+               buf_set_u32(cpu->pc->value, 0, 32, pc_value - 2);
+
+               cpu->write_core_reg(cpu,
+                               &cache->reg_list[CF_PC],
+                               (uint8_t *)cache->reg_list[CF_PC].value);
+       }
+
+       return ERROR_OK;
+}
+
+static int mcf5441x_halt(struct target *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");
+
+       /*
+        * need expert help here: seems that gdb, if not informed
+        * here immediately, cannot wait poll to reply and times-out
+        * closing conneciton.
+        * Sp gdb as default seems to have a quite short timeout, so,
+        * arranging to reply to halted asap here
+        */
+       if (target->state != TARGET_HALTED) {
+               int timeout = 0;
+               uint32_t csr;
+
+               target->state = TARGET_HALTED;
+               target_call_event_callbacks(target, TARGET_EVENT_HALTED);
+
+               bdm_cf26_halt(target);
+               alive_sleep(1);
+
+               while (timeout++ < 100) {
+                       csr = bdm_cf26_read_dm_reg(target, BDM_REG_CSR);
+
+                       if (csr & CSR_BPKT)
+                               break;
+
+                       alive_sleep(1);
+               }
+
+               if (mcf5441x_debug_entry(target) != ERROR_OK)
+                       LOG_WARNING("can't set debug entry");
+       }
+
+       return ERROR_OK;
+}
+
+static void mcf5441x_build_reg_cache(struct target *target)
+{
+       struct mcf5441x *mcf5441x = target_to_mcf5441x(target);
+       struct reg_feature *feature;
+       struct reg_cache **cache_p;
+       struct reg_cache *cache;
+       struct reg *reg_list;
+       struct mcf5441x_reg *arch_info;
+       int num_regs = CF_NUM_REGS;
+       int i;
+
+       arch_info = calloc(CF_NUM_REGS, sizeof(struct mcf5441x_reg));
+       reg_list = calloc(CF_NUM_REGS, sizeof(struct reg));
+       cache = malloc(sizeof(struct reg_cache));
+       cache_p = register_get_last_cache_p(&target->reg_cache);
+
+       cache->name = "coldfire registers";
+       cache->next = NULL;
+       cache->reg_list = reg_list;
+       cache->num_regs = num_regs;
+       (*cache_p) = cache;
+
+       for (i = 0; i < num_regs; i++) {
+               arch_info[i].target = target;
+               reg_list[i].name = mcf5441x_registers_table[i].name;
+               reg_list[i].size = mcf5441x_registers_table[i].bits;
+               reg_list[i].value = calloc(1, 4);
+               reg_list[i].dirty = 0;
+               reg_list[i].valid = 0;
+               reg_list[i].type = &mcf5441x_reg_type;
+               reg_list[i].arch_info = &arch_info[i];
+               reg_list[i].group = mcf5441x_registers_table[i].group;
+               reg_list[i].number = i;
+               reg_list[i].exist = true;
+               reg_list[i].caller_save = true; /* gdb defaults to true */
+
+               feature = calloc(1, sizeof(*feature));
+               if (feature) {
+                       feature->name = mcf5441x_registers_table[i].feature;
+                       reg_list[i].feature = feature;
+               }
+               reg_list[i].reg_data_type =
+                       calloc(1, sizeof(struct reg_data_type));
+               if (reg_list[i].reg_data_type)
+                       reg_list[i].reg_data_type->type =
+                               mcf5441x_registers_table[i].type;
+       }
+
+       mcf5441x->core_cache = cache;
+
+       mcf5441x->pc = &cache->reg_list[CF_PC];
+       mcf5441x->sp = &cache->reg_list[CF_SP];
+}
+
+static int mcf5441x_check_hw(uint32_t d0, uint32_t d1)
+{
+       if ((d0 & 0x0f) != 0xf)
+               return ERROR_FAIL;
+
+       if (((d0 & 0xf0) >> 4) != 0x02)
+               return ERROR_FAIL;
+
+       if (!(d0 & (1 << 11)))
+               return ERROR_FAIL;
+
+       if (((d0 & 0xf00000) >> 20) != 0x4)
+               return ERROR_FAIL;
+
+       LOG_INFO("mcf5441x detected, D+PSTB, MMU, ISA_C");
+
+       return ERROR_OK;
+}
+
+static int mcf5441x_examine(struct target *target)
+{
+       if (!target_was_examined(target)) {
+
+               target_set_examined(target);
+
+               const uint32_t csr =
+                       bdm_cf26_read_dm_reg(target, BDM_REG_CSR);
+
+               LOG_INFO("examining cpu ...");
+
+               if (csr == 0xffffffff) {
+                       LOG_ERROR("device not connected or not powered");
+                       return ERROR_FAIL;
+               } else {
+                       /*
+                        * ColdFire processors load hardware configuration
+                        * information into the D0 and D1
+                        */
+                       uint32_t d0, d1;
+
+                       d0 = bdm_cf26_read_ad_reg(target, CF_D0);
+                       d1 = bdm_cf26_read_ad_reg(target, CF_D1);
+
+                       if (d0 == 0xffffffff || d1 == 0xffffffff)
+                               return ERROR_FAIL;
+
+                       if (mcf5441x_check_hw(d0, d1) == ERROR_FAIL)
+                               return ERROR_FAIL;
+
+                       /*
+                        * set an initial known state
+                        */
+                       target->state = TARGET_RESET;
+
+                       mcf5441x_halt(target);
+                       mcf5441x_debug_entry(target);
+
+                       target->debug_reason = DBG_REASON_DBGRQ;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int mcf5441x_init_target(struct command_context *cmd_ctx,
+                               struct target *target)
+{
+       mcf5441x_build_reg_cache(target);
+
+       return ERROR_OK;
+}
+
+static int mcf5441x_target_create(struct target *target, Jim_Interp *interp)
+{
+       struct mcf5441x *mcf5441x;
+
+       mcf5441x = calloc(1, sizeof(*mcf5441x));
+       if (!mcf5441x)
+               return ERROR_FAIL;
+
+       mcf5441x->target = target;
+       mcf5441x->read_core_reg = mcf5441x_read_core_reg;
+       mcf5441x->write_core_reg = mcf5441x_write_core_reg;
+
+       target->arch_info = mcf5441x;
+
+       return ERROR_OK;
+}
+
+int mcf5441x_get_gdb_reg_list(struct target *target, struct reg **reg_list[],
+               int *reg_list_size, enum target_register_class reg_class)
+{
+       struct mcf5441x *cpu = target_to_mcf5441x(target);
+       int i;
+
+       if (reg_class == REG_CLASS_ALL)
+               *reg_list_size = cpu->core_cache->num_regs;
+       else
+               *reg_list_size = 8;
+
+       *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
+       if (*reg_list == NULL)
+               return ERROR_FAIL;
+
+       for (i = 0; i < *reg_list_size; i++)
+               (*reg_list)[i] = &cpu->core_cache->reg_list[i];
+
+       return ERROR_OK;
+}
+
+struct target_type mcf5441x_target = {
+       .name = "mcf5441x",
+       .target_create = mcf5441x_target_create,
+       .init_target = mcf5441x_init_target,
+       .examine = mcf5441x_examine,
+       .get_gdb_reg_list =  mcf5441x_get_gdb_reg_list,
+       .halt = mcf5441x_halt,
+       .resume = mcf5441x_resume,
+       .poll = mcf5441x_poll,
+       .step = mcf5441x_step,
+       .assert_reset = mcf5441x_assert_reset,
+       .deassert_reset = mcf5441x_deassert_reset,
+       .add_breakpoint = mcf5441x_add_breakpoint,
+       .remove_breakpoint = mcf5441x_remove_breakpoint,
+       .read_memory = bdm_cf26_read_memory,
+       .write_memory = bdm_cf26_write_memory,
+};
diff --git a/src/target/mcf5441x.h b/src/target/mcf5441x.h
new file mode 100644
index 0000000..92270fb
--- /dev/null
+++ b/src/target/mcf5441x.h
@@ -0,0 +1,97 @@
+/***************************************************************************
+ *                                                                         *
+ *   Copyright (C) 2017 by Angelo Dureghello                               *
+ *   [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; see the file COPYING.  If not see            *
+ *   <http://www.gnu.org/licenses/>                                        *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifndef OPENOCD_TARGET_MCF5441X_H
+#define OPENOCD_TARGET_MCF5441X_H
+
+/**
+ * Represents a coldfire v4 core
+ *
+ */
+struct mcf5441x {
+       struct reg_cache *core_cache;
+
+       struct reg *pc;
+       struct reg *sp;
+       struct reg *ccr;
+
+       /** Backpointer to the target. */
+       struct target *target;
+
+       /** Retrieve a single core register. */
+       int (*read_core_reg)(struct mcf5441x *mcf5441x, struct reg *reg);
+       int (*write_core_reg)(struct mcf5441x *mcf5441x, struct reg *reg,
+                             uint8_t *value);
+};
+
+enum {
+       CF_D0,
+       CF_D1,
+       CF_D2,
+       CF_D3,
+       CF_D4,
+       CF_D5,
+       CF_D6,
+       CF_D7,
+       CF_A0,
+       CF_A1,
+       CF_A2,
+       CF_A3,
+       CF_A4,
+       CF_A5,
+       CF_FP,
+       CF_SP,
+       CF_PS,
+       CF_PC,
+       CF_VBR,
+       CF_NUM_REGS,
+};
+
+enum {
+       CF_OP_HALT = 0x4ac8,
+       CF_OP_TRAP = 0x4e40,
+};
+
+
+#define XCSR_HALTED    (1 << 31)
+
+#define CSR_SSM                (1 << 4)
+#define CSR_IPI                (1 << 5)
+#define CSR_NPL                (1 << 6)
+#define CSR_EMULATION  (1 << 14)
+#define CSR_MAP                (1 << 15)
+#define CSR_BPKT       (1 << 24)
+#define CSR_HALT       (1 << 25)
+#define CSR_TRG                (1 << 26)
+
+static inline struct mcf5441x *target_to_mcf5441x(struct target *target)
+{
+       return target->arch_info;
+}
+
+static int mcf5441x_debug_entry(struct target *target);
+int32_t mcf5441x_ram_map_global_to_local(struct target *, uint32_t);
+static int mcf5441x_set_breakpoint(struct target *target,
+                                struct breakpoint *breakpoint);
+static int mcf5441x_unset_breakpoint(struct target *target,
+                                struct breakpoint *breakpoint);
+
+#endif /* OPENOCD_TARGET_MCF5441X_H */
diff --git a/src/target/target.c b/src/target/target.c
index ee302ee..4e4edac 100644
--- a/src/target/target.c
+++ b/src/target/target.c
@@ -105,6 +105,7 @@ extern struct target_type nds32_v3m_target;
 extern struct target_type or1k_target;
 extern struct target_type quark_x10xx_target;
 extern struct target_type quark_d20xx_target;
+extern struct target_type mcf5441x_target;
 
 static struct target_type *target_types[] = {
        &arm7tdmi_target,
@@ -136,6 +137,7 @@ static struct target_type *target_types[] = {
        &or1k_target,
        &quark_x10xx_target,
        &quark_d20xx_target,
+       &mcf5441x_target,
 #if BUILD_TARGET64
        &aarch64_target,
 #endif

-- 

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, SlashDot.org! http://sdm.link/slashdot
_______________________________________________
OpenOCD-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openocd-devel

Reply via email to