diff options
author | Oleksandr Tymoshenko <gonzo@bluezbox.com> | 2010-08-15 21:51:34 +0200 |
---|---|---|
committer | Øyvind Harboe <oyvind.harboe@zylin.com> | 2010-08-15 21:51:34 +0200 |
commit | c3d51bf0da7333de303adf86011913a4bca96e4d (patch) | |
tree | bc1afa41a5722ee45bd023943bef9401d4d90af0 /src/target | |
parent | bb88f3f470b7e3805636983c533756e84806bd2f (diff) | |
download | openocd_libswd-c3d51bf0da7333de303adf86011913a4bca96e4d.tar.gz openocd_libswd-c3d51bf0da7333de303adf86011913a4bca96e4d.tar.bz2 openocd_libswd-c3d51bf0da7333de303adf86011913a4bca96e4d.tar.xz openocd_libswd-c3d51bf0da7333de303adf86011913a4bca96e4d.zip |
avr32: work-in-progress
committed so as to ease cooperation and to let it be improved
over time.
So far it supports:
- halt/resume
- registers inspection
- memory inspection/modification
I'm still getting up to speed with OpenOCD internals and AVR32 so code is a little
bit messy and I'd appreciate any feedback.
Diffstat (limited to 'src/target')
-rw-r--r-- | src/target/Makefile.am | 7 | ||||
-rw-r--r-- | src/target/avr32_ap7k.c | 684 | ||||
-rw-r--r-- | src/target/avr32_ap7k.h | 49 | ||||
-rw-r--r-- | src/target/avr32_jtag.c | 392 | ||||
-rw-r--r-- | src/target/avr32_jtag.h | 107 | ||||
-rw-r--r-- | src/target/avr32_mem.c | 333 | ||||
-rw-r--r-- | src/target/avr32_mem.h | 37 | ||||
-rw-r--r-- | src/target/avr32_regs.c | 112 | ||||
-rw-r--r-- | src/target/avr32_regs.h | 46 | ||||
-rw-r--r-- | src/target/target.c | 2 |
10 files changed, 1769 insertions, 0 deletions
diff --git a/src/target/Makefile.am b/src/target/Makefile.am index ea6d88fc..e01e0774 100644 --- a/src/target/Makefile.am +++ b/src/target/Makefile.am @@ -32,6 +32,7 @@ libtarget_la_SOURCES = \ $(ARMV6_SRC) \ $(ARMV7_SRC) \ $(ARM_MISC_SRC) \ + $(AVR32_SRC) \ $(MIPS32_SRC) \ avrt.c \ dsp563xx.c \ @@ -92,6 +93,12 @@ ARM_DEBUG_SRC = \ $(OOCD_TRACE_FILES) \ etm_dummy.c +AVR32_SRC = \ + avr32_ap7k.c \ + avr32_jtag.c \ + avr32_mem.c \ + avr32_regs.c + MIPS32_SRC = \ mips32.c \ mips_m4k.c \ diff --git a/src/target/avr32_ap7k.c b/src/target/avr32_ap7k.c new file mode 100644 index 00000000..a5cdbe47 --- /dev/null +++ b/src/target/avr32_ap7k.c @@ -0,0 +1,684 @@ +/*************************************************************************** + * Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.com> * + * Based on mips_m4k code: * + * Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> * + * 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, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#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 "avr32_jtag.h" +#include "avr32_mem.h" +#include "avr32_regs.h" +#include "avr32_ap7k.h" + +static char* avr32_core_reg_list[] = +{ + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", + "r9", "r10", "r11", "r12", "sp", "lr", "pc", "sr" +}; + +static struct avr32_core_reg + avr32_core_reg_list_arch_info[AVR32NUMCOREREGS] = +{ + {0, NULL, NULL}, + {1, NULL, NULL}, + {2, NULL, NULL}, + {3, NULL, NULL}, + {4, NULL, NULL}, + {5, NULL, NULL}, + {6, NULL, NULL}, + {7, NULL, NULL}, + {8, NULL, NULL}, + {9, NULL, NULL}, + {10, NULL, NULL}, + {11, NULL, NULL}, + {12, NULL, NULL}, + {13, NULL, NULL}, + {14, NULL, NULL}, + {15, NULL, NULL}, + {16, NULL, NULL}, +}; + + +static int avr32_read_core_reg(struct target *target, int num); +static int avr32_write_core_reg(struct target *target, int num); + +int avr32_ap7k_save_context(struct target *target) +{ + int retval, i; + struct avr32_ap7k_common *ap7k = target_to_ap7k(target); + + retval = avr32_jtag_read_regs(&ap7k->jtag, ap7k->core_regs); + if (retval != ERROR_OK) + return retval; + + for (i = 0; i < AVR32NUMCOREREGS; i++) + { + if (!ap7k->core_cache->reg_list[i].valid) + { + avr32_read_core_reg(target, i); + } + } + + return ERROR_OK; +} + +int avr32_ap7k_restore_context(struct target *target) +{ + int i; + + /* get pointers to arch-specific information */ + struct avr32_ap7k_common *ap7k = target_to_ap7k(target); + + for (i = 0; i < AVR32NUMCOREREGS; i++) + { + if (ap7k->core_cache->reg_list[i].dirty) + { + avr32_write_core_reg(target, i); + } + } + + /* write core regs */ + avr32_jtag_write_regs(&ap7k->jtag, ap7k->core_regs); + + return ERROR_OK; +} + +static int avr32_read_core_reg(struct target *target, int num) +{ + uint32_t reg_value; + struct avr32_core_reg *mips_core_reg; + + /* get pointers to arch-specific information */ + struct avr32_ap7k_common *ap7k = target_to_ap7k(target); + + if ((num < 0) || (num >= AVR32NUMCOREREGS)) + return ERROR_INVALID_ARGUMENTS; + + mips_core_reg = ap7k->core_cache->reg_list[num].arch_info; + reg_value = ap7k->core_regs[num]; + buf_set_u32(ap7k->core_cache->reg_list[num].value, 0, 32, reg_value); + ap7k->core_cache->reg_list[num].valid = 1; + ap7k->core_cache->reg_list[num].dirty = 0; + + return ERROR_OK; +} + +static int avr32_write_core_reg(struct target *target, int num) +{ + uint32_t reg_value; + struct avr32_core_reg *mips_core_reg; + + /* get pointers to arch-specific information */ + struct avr32_ap7k_common *ap7k = target_to_ap7k(target); + + if ((num < 0) || (num >= AVR32NUMCOREREGS)) + return ERROR_INVALID_ARGUMENTS; + + reg_value = buf_get_u32(ap7k->core_cache->reg_list[num].value, 0, 32); + mips_core_reg = ap7k->core_cache->reg_list[num].arch_info; + ap7k->core_regs[num] = reg_value; + LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num , reg_value); + ap7k->core_cache->reg_list[num].valid = 1; + ap7k->core_cache->reg_list[num].dirty = 0; + + return ERROR_OK; +} + +static int avr32_get_core_reg(struct reg *reg) +{ + int retval; + struct avr32_core_reg *avr32_reg = reg->arch_info; + struct target *target = avr32_reg->target; + + if (target->state != TARGET_HALTED) + { + return ERROR_TARGET_NOT_HALTED; + } + + retval = avr32_read_core_reg(target, avr32_reg->num); + + return retval; +} + +static int avr32_set_core_reg(struct reg *reg, uint8_t *buf) +{ + struct avr32_core_reg *avr32_reg = reg->arch_info; + struct target *target = avr32_reg->target; + uint32_t value = buf_get_u32(buf, 0, 32); + + if (target->state != TARGET_HALTED) + { + return ERROR_TARGET_NOT_HALTED; + } + + buf_set_u32(reg->value, 0, 32, value); + reg->dirty = 1; + reg->valid = 1; + + return ERROR_OK; +} + +static const struct reg_arch_type avr32_reg_type = { + .get = avr32_get_core_reg, + .set = avr32_set_core_reg, +}; + +static struct reg_cache *avr32_build_reg_cache(struct target *target) +{ + int num_regs = AVR32NUMCOREREGS; + struct avr32_ap7k_common *ap7k = target_to_ap7k(target); + struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); + struct reg_cache *cache = malloc(sizeof(struct reg_cache)); + struct reg *reg_list = malloc(sizeof(struct reg) * num_regs); + struct avr32_core_reg *arch_info = + malloc(sizeof(struct avr32_core_reg) * num_regs); + int i; + + /* Build the process context cache */ + cache->name = "avr32 registers"; + cache->next = NULL; + cache->reg_list = reg_list; + cache->num_regs = num_regs; + (*cache_p) = cache; + ap7k->core_cache = cache; + + for (i = 0; i < num_regs; i++) + { + arch_info[i] = avr32_core_reg_list_arch_info[i]; + arch_info[i].target = target; + arch_info[i].avr32_common = ap7k; + reg_list[i].name = avr32_core_reg_list[i]; + reg_list[i].size = 32; + reg_list[i].value = calloc(1, 4); + reg_list[i].dirty = 0; + reg_list[i].valid = 0; + reg_list[i].type = &avr32_reg_type; + reg_list[i].arch_info = &arch_info[i]; + } + + return cache; +} + +static int avr32_ap7k_debug_entry(struct target *target) +{ + + uint32_t dpc, dinst; + int retval; + struct avr32_ap7k_common *ap7k = target_to_ap7k(target); + + retval = avr32_jtag_nexus_read(&ap7k->jtag, AVR32_OCDREG_DPC, &dpc); + if (retval != ERROR_OK) + return retval; + + retval = avr32_jtag_nexus_read(&ap7k->jtag, AVR32_OCDREG_DINST, &dinst); + if (retval != ERROR_OK) + return retval; + + ap7k->jtag.dpc = dpc; + + avr32_ap7k_save_context(target); + + return ERROR_OK; +} + + +static int avr32_ap7k_poll(struct target *target) +{ + uint32_t ds; + int retval; + struct avr32_ap7k_common *ap7k = target_to_ap7k(target); + + retval = avr32_jtag_nexus_read(&ap7k->jtag, AVR32_OCDREG_DS, &ds); + if (retval != ERROR_OK) + return retval; + + /* check for processor halted */ + if (ds & OCDREG_DS_DBA) + { + if ((target->state == TARGET_RUNNING) || (target->state == TARGET_RESET)) + { + target->state = TARGET_HALTED; + + if ((retval = avr32_ap7k_debug_entry(target)) != ERROR_OK) + return retval; + + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + } + else if (target->state == TARGET_DEBUG_RUNNING) + { + target->state = TARGET_HALTED; + + if ((retval = avr32_ap7k_debug_entry(target)) != ERROR_OK) + return retval; + + target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); + } + } + else + { + target->state = TARGET_RUNNING; + } + + + return ERROR_OK; +} + +static int avr32_ap7k_halt(struct target *target) +{ + struct avr32_ap7k_common *ap7k = target_to_ap7k(target); + + 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; + } + } + + + avr32_ocd_setbits(&ap7k->jtag, AVR32_OCDREG_DC, OCDREG_DC_DBR); + target->debug_reason = DBG_REASON_DBGRQ; + + return ERROR_OK; +} + +static int avr32_ap7k_assert_reset(struct target *target) +{ + LOG_ERROR("%s: implement me", __func__); + + return ERROR_OK; +} + +static int avr32_ap7k_deassert_reset(struct target *target) +{ + LOG_ERROR("%s: implement me", __func__); + + return ERROR_OK; +} + +static int avr32_ap7k_soft_reset_halt(struct target *target) +{ + LOG_ERROR("%s: implement me", __func__); + + return ERROR_OK; +} + +static int avr32_ap7k_resume(struct target *target, int current, + uint32_t address, int handle_breakpoints, int debug_execution) +{ + struct avr32_ap7k_common *ap7k = target_to_ap7k(target); + struct breakpoint *breakpoint = NULL; + uint32_t resume_pc; + int retval; + + if (target->state != TARGET_HALTED) + { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!debug_execution) + { + target_free_all_working_areas(target); + /* + avr32_ap7k_enable_breakpoints(target); + avr32_ap7k_enable_watchpoints(target); + */ + } + + /* current = 1: continue on current pc, otherwise continue at <address> */ + if (!current) + { +#if 0 + if (retval != ERROR_OK) + return retval; +#endif + } + + resume_pc = + buf_get_u32(ap7k->core_cache->reg_list[AVR32_REG_PC].value, 0, 32); + avr32_ap7k_restore_context(target); + + /* the front-end may request us not to handle breakpoints */ + if (handle_breakpoints) + { + /* Single step past breakpoint at current address */ + if ((breakpoint = breakpoint_find(target, resume_pc))) + { + LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 "", breakpoint->address); +#if 0 + avr32_ap7k_unset_breakpoint(target, breakpoint); + avr32_ap7k_single_step_core(target); + avr32_ap7k_set_breakpoint(target, breakpoint); +#endif + } + } + +#if 0 + /* enable interrupts if we are running */ + avr32_ap7k_enable_interrupts(target, !debug_execution); + + /* exit debug mode */ + mips_ejtag_exit_debug(ejtag_info); +#endif + + + retval = avr32_ocd_clearbits(&ap7k->jtag, AVR32_OCDREG_DC, + OCDREG_DC_DBR); + if (retval != ERROR_OK) + return retval; + + retval = avr32_jtag_exec(&ap7k->jtag, RETD); + if (retval != ERROR_OK) + return retval; + + target->debug_reason = DBG_REASON_NOTHALTED; + + /* registers are now invalid */ + register_cache_invalidate(ap7k->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 avr32_ap7k_step(struct target *target, int current, + uint32_t address, int handle_breakpoints) +{ + LOG_ERROR("%s: implement me", __func__); + + return ERROR_OK; +} + +static int avr32_ap7k_add_breakpoint(struct target *target, struct breakpoint *breakpoint) +{ + LOG_ERROR("%s: implement me", __func__); + + return ERROR_OK; +} + +static int avr32_ap7k_remove_breakpoint(struct target *target, + struct breakpoint *breakpoint) +{ + LOG_ERROR("%s: implement me", __func__); + + return ERROR_OK; +} + +static int avr32_ap7k_add_watchpoint(struct target *target, struct watchpoint *watchpoint) +{ + LOG_ERROR("%s: implement me", __func__); + + return ERROR_OK; +} + +static int avr32_ap7k_remove_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + LOG_ERROR("%s: implement me", __func__); + + return ERROR_OK; +} + +static int avr32_ap7k_read_memory(struct target *target, uint32_t address, + uint32_t size, uint32_t count, uint8_t *buffer) +{ + struct avr32_ap7k_common *ap7k = target_to_ap7k(target); + + LOG_DEBUG("address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", address, size, count); + + if (target->state != TARGET_HALTED) + { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* sanitize arguments */ + if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) + return ERROR_INVALID_ARGUMENTS; + + if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) + return ERROR_TARGET_UNALIGNED_ACCESS; + + switch (size) + { + case 4: + return avr32_jtag_read_memory32(&ap7k->jtag, address, count, (uint32_t*)buffer); + break; + case 2: + return avr32_jtag_read_memory16(&ap7k->jtag, address, count, (uint16_t*)buffer); + break; + case 1: + return avr32_jtag_read_memory8(&ap7k->jtag, address, count, buffer); + break; + default: + break; + } + + return ERROR_OK; +} + +static int avr32_ap7k_write_memory(struct target *target, uint32_t address, + uint32_t size, uint32_t count, uint8_t *buffer) +{ + struct avr32_ap7k_common *ap7k = target_to_ap7k(target); + + LOG_DEBUG("address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", address, size, count); + + if (target->state != TARGET_HALTED) + { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* sanitize arguments */ + if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) + return ERROR_INVALID_ARGUMENTS; + + if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) + return ERROR_TARGET_UNALIGNED_ACCESS; + + switch (size) + { + case 4: + return avr32_jtag_write_memory32(&ap7k->jtag, address, count, (uint32_t*)buffer); + break; + case 2: + return avr32_jtag_write_memory16(&ap7k->jtag, address, count, (uint16_t*)buffer); + break; + case 1: + return avr32_jtag_write_memory8(&ap7k->jtag, address, count, buffer); + break; + default: + break; + } + + return ERROR_OK; +} + +static int avr32_ap7k_init_target(struct command_context *cmd_ctx, + struct target *target) +{ + struct avr32_ap7k_common *ap7k = target_to_ap7k(target); + + ap7k->jtag.tap = target->tap; + avr32_build_reg_cache(target); + return ERROR_OK; +} + +static int avr32_ap7k_target_create(struct target *target, Jim_Interp *interp) +{ + struct avr32_ap7k_common *ap7k = calloc(1, sizeof(struct + avr32_ap7k_common)); + + ap7k->common_magic = AP7k_COMMON_MAGIC; + target->arch_info = ap7k; + + return ERROR_OK; +} + +static int avr32_ap7k_examine(struct target *target) +{ + uint32_t devid, ds; + struct avr32_ap7k_common *ap7k = target_to_ap7k(target); + + if (!target_was_examined(target)) + { + target_set_examined(target); + avr32_jtag_nexus_read(&ap7k->jtag, AVR32_OCDREG_DID, &devid); + LOG_INFO("device id: %08x", devid); + avr32_ocd_setbits(&ap7k->jtag, AVR32_OCDREG_DC,OCDREG_DC_DBE); + avr32_jtag_nexus_read(&ap7k->jtag, AVR32_OCDREG_DS, &ds); + + /* check for processor halted */ + if (ds & OCDREG_DS_DBA) + { + LOG_INFO("target is halted"); + target->state = TARGET_HALTED; + } + else + target->state = TARGET_RUNNING; + } + + return ERROR_OK; +} + +static int avr32_ap7k_bulk_write_memory(struct target *target, uint32_t address, + uint32_t count, uint8_t *buffer) +{ + LOG_ERROR("%s: implement me", __func__); + + return ERROR_OK; +} + + +int avr32_ap7k_arch_state(struct target *target) +{ + struct avr32_ap7k_common *ap7k = target_to_ap7k(target); + + LOG_USER("target halted due to %s, pc: 0x%8.8" PRIx32 "", + debug_reason_name(target), ap7k->jtag.dpc); + + return ERROR_OK; +} + +int avr32_ap7k_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size) +{ +#if 0 + /* get pointers to arch-specific information */ + int i; + + /* include floating point registers */ + *reg_list_size = AVR32NUMCOREREGS + AVR32NUMFPREGS; + *reg_list = malloc(sizeof(struct reg*) * (*reg_list_size)); + + for (i = 0; i < AVR32NUMCOREREGS; i++) + { + (*reg_list)[i] = &mips32->core_cache->reg_list[i]; + } + + /* add dummy floating points regs */ + for (i = AVR32NUMCOREREGS; i < (AVR32NUMCOREREGS + AVR32NUMFPREGS); i++) + { + (*reg_list)[i] = &avr32_ap7k_gdb_dummy_fp_reg; + } +#endif + + LOG_ERROR("%s: implement me", __func__); + return ERROR_FAIL; +} + + + +struct target_type avr32_ap7k_target = +{ + .name = "avr32_ap7k", + + .poll = avr32_ap7k_poll, + .arch_state = avr32_ap7k_arch_state, + + .target_request_data = NULL, + + .halt = avr32_ap7k_halt, + .resume = avr32_ap7k_resume, + .step = avr32_ap7k_step, + + .assert_reset = avr32_ap7k_assert_reset, + .deassert_reset = avr32_ap7k_deassert_reset, + .soft_reset_halt = avr32_ap7k_soft_reset_halt, + + .get_gdb_reg_list = avr32_ap7k_get_gdb_reg_list, + + .read_memory = avr32_ap7k_read_memory, + .write_memory = avr32_ap7k_write_memory, + .bulk_write_memory = avr32_ap7k_bulk_write_memory, + // .checksum_memory = avr32_ap7k_checksum_memory, + // .blank_check_memory = avr32_ap7k_blank_check_memory, + + // .run_algorithm = avr32_ap7k_run_algorithm, + + .add_breakpoint = avr32_ap7k_add_breakpoint, + .remove_breakpoint = avr32_ap7k_remove_breakpoint, + .add_watchpoint = avr32_ap7k_add_watchpoint, + .remove_watchpoint = avr32_ap7k_remove_watchpoint, + + .target_create = avr32_ap7k_target_create, + .init_target = avr32_ap7k_init_target, + .examine = avr32_ap7k_examine, +}; diff --git a/src/target/avr32_ap7k.h b/src/target/avr32_ap7k.h new file mode 100644 index 00000000..d08254b1 --- /dev/null +++ b/src/target/avr32_ap7k.h @@ -0,0 +1,49 @@ +/*************************************************************************** + * Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.com> * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef AVR32_AP7K +#define AVR32_AP7K + +#include <helper/types.h> + +struct target; + +#define AP7k_COMMON_MAGIC 0x4150374b +struct avr32_ap7k_common +{ + int common_magic; + struct avr32_jtag jtag; + struct reg_cache *core_cache; + uint32_t core_regs[AVR32NUMCOREREGS]; +}; + +static inline struct avr32_ap7k_common * +target_to_ap7k(struct target *target) +{ + return (struct avr32_ap7k_common*)target->arch_info; +} + +struct avr32_core_reg +{ + uint32_t num; + struct target *target; + struct avr32_ap7k_common *avr32_common; +}; + +#endif /*AVR32_AP7K*/ diff --git a/src/target/avr32_jtag.c b/src/target/avr32_jtag.c new file mode 100644 index 00000000..b6b5e37b --- /dev/null +++ b/src/target/avr32_jtag.c @@ -0,0 +1,392 @@ +/*************************************************************************** + * Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.com> * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "target.h" +#include "helper/types.h" +#include "jtag/jtag.h" +#include "avr32_jtag.h" + +static int avr32_jtag_set_instr(struct avr32_jtag *jtag_info, int new_instr) +{ + struct jtag_tap *tap; + int busy = 0; + + tap = jtag_info->tap; + if (tap == NULL) + return ERROR_FAIL; + + if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != (uint32_t)new_instr) + { + do { + struct scan_field field; + uint8_t t[4]; + uint8_t ret[4]; + + field.num_bits = tap->ir_length; + field.out_value = t; + buf_set_u32(t, 0, field.num_bits, new_instr); + field.in_value = ret; + + jtag_add_ir_scan(tap, &field, TAP_IDLE); + if (jtag_execute_queue() != ERROR_OK) + { + LOG_ERROR("%s: setting address failed", __func__); + return ERROR_FAIL; + } + busy = buf_get_u32(ret, 2, 1); + } while (busy); /* check for busy bit */ + } + + return ERROR_OK; +} + +int avr32_jtag_nexus_set_address(struct avr32_jtag *jtag_info, + uint32_t addr, int mode) +{ + struct scan_field fields[2]; + uint8_t addr_buf[4]; + uint8_t busy_buf[4]; + int busy; + + memset(fields, 0, sizeof(fields)); + + do { + memset(addr_buf, 0, sizeof(addr_buf)); + memset(busy_buf, 0, sizeof(busy_buf)); + + buf_set_u32(addr_buf, 0, 1, mode); + buf_set_u32(addr_buf, 1, 7, addr); + + fields[0].num_bits = 26; + fields[0].in_value = NULL; + fields[0].out_value = NULL; + + fields[1].num_bits = 8; + fields[1].in_value = busy_buf; + fields[1].out_value = addr_buf; + + jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_IDLE); + if (jtag_execute_queue() != ERROR_OK) + { + LOG_ERROR("%s: setting address failed", __func__); + return ERROR_FAIL; + } + busy = buf_get_u32(busy_buf, 6, 1); + } while(busy); + + return ERROR_OK; +} + + +int avr32_jtag_nexus_read_data(struct avr32_jtag *jtag_info, + uint32_t *pdata) +{ + + struct scan_field fields[2]; + uint8_t data_buf[4]; + uint8_t busy_buf[4]; + int busy; + + do { + memset(data_buf, 0, sizeof(data_buf)); + memset(busy_buf, 0, sizeof(busy_buf)); + + fields[0].num_bits = 32; + fields[0].out_value = NULL; + fields[0].in_value = data_buf; + + + fields[1].num_bits = 2; + fields[1].in_value = busy_buf; + fields[1].out_value = NULL; + + jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_IDLE); + + if (jtag_execute_queue() != ERROR_OK) + { + LOG_ERROR("%s: reading data failed", __func__); + return ERROR_FAIL; + } + + busy = buf_get_u32(busy_buf, 0, 1); + } while (busy); + + *pdata = buf_get_u32(data_buf, 0, 32); + + return ERROR_OK; +} + + +int avr32_jtag_nexus_write_data(struct avr32_jtag *jtag_info, + uint32_t data) +{ + + struct scan_field fields[2]; + uint8_t data_buf[4]; + uint8_t busy_buf[4]; + uint8_t dummy_buf[4]; + int busy; + + do { + memset(data_buf, 0, sizeof(data_buf)); + memset(busy_buf, 0, sizeof(busy_buf)); + memset(dummy_buf, 0, sizeof(dummy_buf)); + + fields[0].num_bits = 2; + fields[0].in_value = busy_buf; + fields[0].out_value = dummy_buf; + + + buf_set_u32(data_buf, 0, 32, data); + fields[1].num_bits = 32; + fields[1].in_value = NULL; + fields[1].out_value = data_buf; + + jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_IDLE); + + if (jtag_execute_queue() != ERROR_OK) + { + LOG_ERROR("%s: reading data failed", __func__); + return ERROR_FAIL; + } + + busy = buf_get_u32(busy_buf, 0, 0); + } while (busy); + + + return ERROR_OK; +} + + + + +int avr32_jtag_nexus_read(struct avr32_jtag *jtag_info, + uint32_t addr, uint32_t *value) +{ + avr32_jtag_set_instr(jtag_info, AVR32_INST_NEXUS_ACCESS); + avr32_jtag_nexus_set_address(jtag_info, addr, MODE_READ); + avr32_jtag_nexus_read_data(jtag_info, value); + + return ERROR_OK; + +} +int avr32_jtag_nexus_write(struct avr32_jtag *jtag_info, + uint32_t addr, uint32_t value) +{ + avr32_jtag_set_instr(jtag_info, AVR32_INST_NEXUS_ACCESS); + avr32_jtag_nexus_set_address(jtag_info, addr, MODE_WRITE); + avr32_jtag_nexus_write_data(jtag_info, value); + + return ERROR_OK; +} + +int avr32_jtag_mwa_set_address(struct avr32_jtag *jtag_info, int slave, + uint32_t addr, int mode) +{ + struct scan_field fields[2]; + uint8_t addr_buf[4]; + uint8_t slave_buf[4]; + uint8_t busy_buf[4]; + int busy; + + memset(fields, 0, sizeof(fields)); + + do { + memset(addr_buf, 0, sizeof(addr_buf)); + memset(busy_buf, 0, sizeof(busy_buf)); + memset(slave_buf, 0, sizeof(slave_buf)); + + buf_set_u32(slave_buf, 0, 4, slave); + buf_set_u32(addr_buf, 0, 1, mode); + buf_set_u32(addr_buf, 1, 30, addr >> 2); + + fields[0].num_bits = 31; + fields[0].in_value = NULL; + fields[0].out_value = addr_buf; + + fields[1].num_bits = 4; + fields[1].in_value = busy_buf; + fields[1].out_value = slave_buf; + + jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_IDLE); + if (jtag_execute_queue() != ERROR_OK) + { + LOG_ERROR("%s: setting address failed", __func__); + return ERROR_FAIL; + } + busy = buf_get_u32(busy_buf, 1, 1); + } while(busy); + + return ERROR_OK; +} + +int avr32_jtag_mwa_read_data(struct avr32_jtag *jtag_info, + uint32_t *pdata) +{ + + struct scan_field fields[2]; + uint8_t data_buf[4]; + uint8_t busy_buf[4]; + int busy; + + do { + memset(data_buf, 0, sizeof(data_buf)); + memset(busy_buf, 0, sizeof(busy_buf)); + + fields[0].num_bits = 32; + fields[0].out_value = NULL; + fields[0].in_value = data_buf; + + + fields[1].num_bits = 3; + fields[1].in_value = busy_buf; + fields[1].out_value = NULL; + + jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_IDLE); + + if (jtag_execute_queue() != ERROR_OK) + { + LOG_ERROR("%s: reading data failed", __func__); + return ERROR_FAIL; + } + + busy = buf_get_u32(busy_buf, 0, 1); + } while (busy); + + *pdata = buf_get_u32(data_buf, 0, 32); + + return ERROR_OK; +} + +int avr32_jtag_mwa_write_data(struct avr32_jtag *jtag_info, + uint32_t data) +{ + + struct scan_field fields[2]; + uint8_t data_buf[4]; + uint8_t busy_buf[4]; + uint8_t zero_buf[4]; + int busy; + + do { + memset(data_buf, 0, sizeof(data_buf)); + memset(busy_buf, 0, sizeof(busy_buf)); + memset(zero_buf, 0, sizeof(zero_buf)); + + buf_set_u32(data_buf, 0, 32, data); + fields[0].num_bits = 3; + fields[0].in_value = busy_buf; + fields[0].out_value = zero_buf; + + fields[1].num_bits = 32; + fields[1].out_value = data_buf; + fields[1].in_value = NULL; + + + jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_IDLE); + + if (jtag_execute_queue() != ERROR_OK) + { + LOG_ERROR("%s: reading data failed", __func__); + return ERROR_FAIL; + } + + busy = buf_get_u32(busy_buf, 0, 1); + } while (busy); + + return ERROR_OK; +} + + + +int avr32_jtag_mwa_read(struct avr32_jtag *jtag_info, int slave, + uint32_t addr, uint32_t *value) +{ + avr32_jtag_set_instr(jtag_info, AVR32_INST_MW_ACCESS); + avr32_jtag_mwa_set_address(jtag_info, slave, addr, MODE_READ); + avr32_jtag_mwa_read_data(jtag_info, value); + + return ERROR_OK; +} + +int avr32_jtag_mwa_write(struct avr32_jtag *jtag_info, int slave, + uint32_t addr, uint32_t value) +{ + avr32_jtag_set_instr(jtag_info, AVR32_INST_MW_ACCESS); + avr32_jtag_mwa_set_address(jtag_info, slave, addr, MODE_WRITE); + avr32_jtag_mwa_write_data(jtag_info, value); + + return ERROR_OK; +} + +int avr32_jtag_exec(struct avr32_jtag *jtag_info, uint32_t inst) +{ + int retval; + uint32_t ds; + + retval = avr32_jtag_nexus_write(jtag_info, AVR32_OCDREG_DINST, inst); + if (retval != ERROR_OK) + return retval; + + do { + retval = avr32_jtag_nexus_read(jtag_info, AVR32_OCDREG_DS, &ds); + if (retval != ERROR_OK) + return retval; + } while ((ds & OCDREG_DS_DBA) && !(ds & OCDREG_DS_INC)); + + return ERROR_OK; +} + +int avr32_ocd_setbits(struct avr32_jtag *jtag, int reg, uint32_t bits) +{ + uint32_t value; + int res; + + res = avr32_jtag_nexus_read(jtag, reg, &value); + if (res) + return res; + + value |= bits; + res = avr32_jtag_nexus_write(jtag, reg, value); + if (res) + return res; + + return ERROR_OK; +} + +int avr32_ocd_clearbits(struct avr32_jtag *jtag, int reg, uint32_t bits) +{ + uint32_t value; + int res; + + res = avr32_jtag_nexus_read(jtag, reg, &value); + if (res) + return res; + + value &= ~bits; + res = avr32_jtag_nexus_write(jtag, reg, value); + if (res) + return res; + + return ERROR_OK; +} + diff --git a/src/target/avr32_jtag.h b/src/target/avr32_jtag.h new file mode 100644 index 00000000..00f8330e --- /dev/null +++ b/src/target/avr32_jtag.h @@ -0,0 +1,107 @@ +/*************************************************************************** + * Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.com> * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef AVR32_JTAG +#define AVR32_JTAG + +#define AVR32NUMCOREREGS 17 + +/* tap instructions */ +#define AVR32_INST_IDCODE 0x01 +#define AVR32_INST_NEXUS_ACCESS 0x10 +#define AVR32_INST_MW_ACCESS 0x11 +#define AVR32_INST_MB_ACCESS 0x12 + +#define SLAVE_OCD 0x01 +#define SLAVE_HSB_CACHED 0x04 +#define SLAVE_HSB_UNCACHED 0x05 + +/* + * Registers + */ + +#define AVR32_OCDREG_DID 0x00 +#define AVR32_OCDREG_DC 0x02 +#define OCDREG_DC_SS (1 << 8) +#define OCDREG_DC_DBR (1 << 12) +#define OCDREG_DC_DBE (1 << 13) +#define OCDREG_DC_SQA (1 << 22) +#define OCDREG_DC_RES (1 << 30) +#define OCDREG_DC_ABORT (1 << 31) +#define AVR32_OCDREG_DS 0x04 +#define OCDREG_DS_SSS (1 << 0) +#define OCDREG_DS_SWB (1 << 1) +#define OCDREG_DS_HWB (1 << 2) +#define OCDREG_DS_STP (1 << 4) +#define OCDREG_DS_DBS (1 << 5) +#define OCDREG_DS_BP_SHIFT 8 +#define OCDREG_DS_BP_MASK 0xff +#define OCDREG_DS_INC (1 << 24) +#define OCDREG_DS_BOZ (1 << 25) +#define OCDREG_DS_DBA (1 << 26) +#define OCDREG_DS_EXB (1 << 27) +#define OCDREG_DS_NTBF (1 << 28) + +#define AVR32_OCDREG_DINST 0x41 +#define AVR32_OCDREG_DPC 0x42 +#define AVR32_OCDREG_DCCPU 0x44 +#define AVR32_OCDREG_DCEMU 0x45 +#define AVR32_OCDREG_DCSR 0x46 +#define OCDREG_DCSR_CPUD (1 << 0) +#define OCDREG_DCSR_EMUD (1 << 1) + +/* + * Direction bit + */ +#define MODE_WRITE 0x00 +#define MODE_READ 0x01 + +/* + * Some instructions + */ + +#define RETD 0xd703d623 +#define MTDR(dreg, reg) (0xe7b00044 | ((reg) << 16) | dreg) +#define MFDR(reg, dreg) (0xe5b00044 | ((reg) << 16) | dreg) +#define MTSR(sysreg, reg) (0xe3b00002 | ((reg) << 16) | sysreg) +#define MFSR(reg, sysreg) (0xe1b00002 | ((reg) << 16) | sysreg) + +struct avr32_jtag +{ + struct jtag_tap *tap; + uint32_t dpc; /* Debug PC value */ +}; + +int avr32_jtag_nexus_read(struct avr32_jtag *jtag_info, + uint32_t addr, uint32_t *value); +int avr32_jtag_nexus_write(struct avr32_jtag *jtag_info, + uint32_t addr, uint32_t value); + +int avr32_jtag_mwa_read(struct avr32_jtag *jtag_info, int slave, + uint32_t addr, uint32_t *value); +int avr32_jtag_mwa_write(struct avr32_jtag *jtag_info, int slave, + uint32_t addr, uint32_t value); + + +int avr32_ocd_setbits(struct avr32_jtag *jtag, int reg, uint32_t bits); +int avr32_ocd_clearbits(struct avr32_jtag *jtag, int reg, uint32_t bits); + +int avr32_jtag_exec(struct avr32_jtag *jtag_info, uint32_t inst); + +#endif /* AVR32_JTAG */ + diff --git a/src/target/avr32_mem.c b/src/target/avr32_mem.c new file mode 100644 index 00000000..0767c55c --- /dev/null +++ b/src/target/avr32_mem.c @@ -0,0 +1,333 @@ +/*************************************************************************** + * Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.com> * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "target.h" +#include "jtag/jtag.h" +#include "avr32_jtag.h" +#include "avr32_mem.h" + +int avr32_jtag_read_memory32(struct avr32_jtag *jtag_info, + uint32_t addr, int count, uint32_t *buffer) +{ + int i, retval; + uint32_t data; + + for (i = 0; i < count; i++) + { + retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, + addr + i*4, &data); + + if (retval != ERROR_OK) + return retval; + + /* XXX: Assume AVR32 is BE */ + buffer[i] = be_to_h_u32((uint8_t*)&data); + } + + return ERROR_OK; +} + +int avr32_jtag_read_memory16(struct avr32_jtag *jtag_info, + uint32_t addr, int count, uint16_t *buffer) +{ + int i, retval; + uint32_t data; + + i = 0; + + /* any unaligned half-words? */ + if (addr & 3) + { + retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, + addr + i*2, &data); + + if (retval != ERROR_OK) + return retval; + + /* XXX: Assume AVR32 is BE */ + data = be_to_h_u32((uint8_t*)&data); + buffer[i] = (data >> 16) & 0xffff; + i++; + } + + /* read all complete words */ + for (; i < (count & ~1); i+=2) + { + retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, + addr + i*2, &data); + + if (retval != ERROR_OK) + return retval; + + /* XXX: Assume AVR32 is BE */ + data = be_to_h_u32((uint8_t*)&data); + buffer[i] = data & 0xffff; + buffer[i+1] = (data >> 16) & 0xffff; + } + + /* last halfword */ + if (i < count) + { + retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, + addr + i*2, &data); + + if (retval != ERROR_OK) + return retval; + + /* XXX: Assume AVR32 is BE */ + data = be_to_h_u32((uint8_t*)&data); + buffer[i] = data & 0xffff; + } + + return ERROR_OK; +} + +int avr32_jtag_read_memory8(struct avr32_jtag *jtag_info, + uint32_t addr, int count, uint8_t *buffer) +{ + int i, j, retval; + uint8_t data[4]; + i = 0; + + /* Do we have non-aligned bytes? */ + if (addr & 3) + { + retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, + addr + i, (uint32_t*)data); + + if (retval != ERROR_OK) + return retval; + + for (j = addr & 3; (j < 4) && (i < count); j++, i++) + buffer[i] = data[3-j]; + } + + + /* read all complete words */ + for (; i < (count & ~3); i+=4) + { + retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, + addr + i, (uint32_t*)data); + + if (retval != ERROR_OK) + return retval; + + for (j = 0; j < 4; j++) + buffer[i+j] = data[3-j]; + } + + /* remaining bytes */ + if (i < count) + { + retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, + addr + i, (uint32_t*)data); + + if (retval != ERROR_OK) + return retval; + + for (j = 0; i + j < count; j++) + buffer[i+j] = data[3-j]; + } + + return ERROR_OK; +} + +int avr32_jtag_write_memory32(struct avr32_jtag *jtag_info, + uint32_t addr, int count, uint32_t *buffer) +{ + int i, retval; + uint32_t data; + + for (i = 0; i < count; i++) + { + /* XXX: Assume AVR32 is BE */ + h_u32_to_be((uint8_t*)&data, buffer[i]); + retval = avr32_jtag_mwa_write(jtag_info, SLAVE_HSB_UNCACHED, + addr + i*4, data); + + if (retval != ERROR_OK) + return retval; + + } + + return ERROR_OK; +} + +int avr32_jtag_write_memory16(struct avr32_jtag *jtag_info, + uint32_t addr, int count, uint16_t *buffer) +{ + int i, retval; + uint32_t data; + uint32_t data_out; + + i = 0; + + /* + * Do we have any non-aligned half-words? + */ + if (addr & 3) { + /* + * mwa_read will read whole world, no nead to fiddle + * with address. It will be truncated in set_addr + */ + retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, + addr, &data); + + if (retval != ERROR_OK) + return retval; + + data = be_to_h_u32((uint8_t*)&data); + data = (buffer[i] << 16) | (data & 0xffff); + h_u32_to_be((uint8_t*)&data_out, data); + + retval = avr32_jtag_mwa_write(jtag_info, SLAVE_HSB_UNCACHED, + addr, data_out); + + if (retval != ERROR_OK) + return retval; + + i++; + } + + + /* write all complete words */ + for (; i < (count & ~1); i+=2) + { + /* XXX: Assume AVR32 is BE */ + data = (buffer[i+1] << 16) | buffer[i]; + h_u32_to_be((uint8_t*)&data_out, data); + + retval = avr32_jtag_mwa_write(jtag_info, SLAVE_HSB_UNCACHED, + addr + i*2, data_out); + + if (retval != ERROR_OK) + return retval; + } + + /* last halfword */ + if (i < count) + { + retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, + addr + i*2, &data); + + if (retval != ERROR_OK) + return retval; + + data = be_to_h_u32((uint8_t*)&data); + data &= ~0xffff; + data |= buffer[i]; + h_u32_to_be((uint8_t*)&data_out, data); + + retval = avr32_jtag_mwa_write(jtag_info, SLAVE_HSB_UNCACHED, + addr + i*2, data_out); + + if (retval != ERROR_OK) + return retval; + } + + return ERROR_OK; +} + +int avr32_jtag_write_memory8(struct avr32_jtag *jtag_info, + uint32_t addr, int count, uint8_t *buffer) +{ + int i, j, retval; + uint32_t data; + uint32_t data_out; + + i = 0; + + /* + * Do we have any non-aligned bytes? + */ + if (addr & 3) { + /* + * mwa_read will read whole world, no nead to fiddle + * with address. It will be truncated in set_addr + */ + retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, + addr, &data); + + if (retval != ERROR_OK) + return retval; + + data = be_to_h_u32((uint8_t*)&data); + for (j = addr & 3; (j < 4) && (i < count); j++, i++) + { + data &= ~(0xff << j*8); + data |= (buffer[i] << j*8); + } + + h_u32_to_be((uint8_t*)&data_out, data); + retval = avr32_jtag_mwa_write(jtag_info, SLAVE_HSB_UNCACHED, + addr, data_out); + + if (retval != ERROR_OK) + return retval; + } + + + /* write all complete words */ + for (; i < (count & ~3); i+=4) + { + data = 0; + + for (j = 0; j < 4; j++) + data |= (buffer[j+i] << j*8); + + h_u32_to_be((uint8_t*)&data_out, data); + + retval = avr32_jtag_mwa_write(jtag_info, SLAVE_HSB_UNCACHED, + addr + i, data_out); + + if (retval != ERROR_OK) + return retval; + } + + /* + * Write trailing bytes + */ + if (i < count) { + retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, + addr + i, &data); + + if (retval != ERROR_OK) + return retval; + + data = be_to_h_u32((uint8_t*)&data); + for (j = 0; i < count; j++, i++) + { + data &= ~(0xff << j*8); + data |= (buffer[j+i] << j*8); + } + + h_u32_to_be((uint8_t*)&data_out, data); + + retval = avr32_jtag_mwa_write(jtag_info, SLAVE_HSB_UNCACHED, + addr+i, data_out); + + if (retval != ERROR_OK) + return retval; + } + + return ERROR_OK; +} diff --git a/src/target/avr32_mem.h b/src/target/avr32_mem.h new file mode 100644 index 00000000..2a6f606a --- /dev/null +++ b/src/target/avr32_mem.h @@ -0,0 +1,37 @@ +/*************************************************************************** + * Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.com> * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef AVR32_MEM +#define AVR32_MEM + +int avr32_jtag_read_memory32(struct avr32_jtag *jtag_info, + uint32_t addr, int count, uint32_t *buffer); +int avr32_jtag_read_memory16(struct avr32_jtag *jtag_info, + uint32_t addr, int count, uint16_t *buffer); +int avr32_jtag_read_memory8(struct avr32_jtag *jtag_info, + uint32_t addr, int count, uint8_t *buffer); + +int avr32_jtag_write_memory32(struct avr32_jtag *jtag_info, + uint32_t addr, int count, uint32_t *buffer); +int avr32_jtag_write_memory16(struct avr32_jtag *jtag_info, + uint32_t addr, int count, uint16_t *buffer); +int avr32_jtag_write_memory8(struct avr32_jtag *jtag_info, + uint32_t addr, int count, uint8_t *buffer); + +#endif /* AVR32_MEM */ + diff --git a/src/target/avr32_regs.c b/src/target/avr32_regs.c new file mode 100644 index 00000000..eb283fc3 --- /dev/null +++ b/src/target/avr32_regs.c @@ -0,0 +1,112 @@ +/*************************************************************************** + * Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.com> * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "target.h" +#include "jtag/jtag.h" +#include "avr32_jtag.h" +#include "avr32_regs.h" + +static int avr32_jtag_read_reg(struct avr32_jtag *jtag_info, int reg, + uint32_t *val) +{ + int retval; + uint32_t dcsr; + + retval = avr32_jtag_exec(jtag_info, MTDR(AVR32_OCDREG_DCCPU, reg)); + if (retval != ERROR_OK) + return retval; + + do { + retval = avr32_jtag_nexus_read(jtag_info, + AVR32_OCDREG_DCSR, &dcsr); + + if (retval != ERROR_OK) + return retval; + } while (!(dcsr & OCDREG_DCSR_CPUD)); + + retval = avr32_jtag_nexus_read(jtag_info, + AVR32_OCDREG_DCCPU, val); + + return retval; +} + +static int avr32_jtag_write_reg(struct avr32_jtag *jtag_info, int reg, + uint32_t val) +{ + int retval; + uint32_t dcsr; + + /* Restore Status reg */ + retval = avr32_jtag_nexus_write(jtag_info, + AVR32_OCDREG_DCEMU, val); + if (retval != ERROR_OK) + return retval; + + retval = avr32_jtag_exec(jtag_info, MFDR(reg, AVR32_OCDREG_DCEMU)); + if (retval != ERROR_OK) + return retval; + do { + retval = avr32_jtag_nexus_read(jtag_info, + AVR32_OCDREG_DCSR, &dcsr); + } while (!(dcsr & OCDREG_DCSR_EMUD) && (retval == ERROR_OK)); + + return retval; +} + + + +int avr32_jtag_read_regs(struct avr32_jtag *jtag_info, uint32_t *regs) +{ + int i, retval; + + /* read core registers */ + for (i = 0; i < AVR32NUMCOREREGS - 1; i++) + avr32_jtag_read_reg(jtag_info, i, regs + i); + + /* read status register */ + retval = avr32_jtag_exec(jtag_info, MFSR(0, 0)); + if (retval != ERROR_OK) + return retval; + + retval = avr32_jtag_read_reg(jtag_info, 0, regs + AVR32_REG_SR); + + return retval; +} + +int avr32_jtag_write_regs(struct avr32_jtag *jtag_info, uint32_t *regs) +{ + int i, retval; + + retval = avr32_jtag_write_reg(jtag_info, 0, regs[AVR32_REG_SR]); + /* Restore Status reg */ + retval = avr32_jtag_exec(jtag_info, MTSR(0, 0)); + if (retval != ERROR_OK) + return retval; + + /* + * And now the rest of registers + */ + for (i = 0; i < AVR32NUMCOREREGS - 1; i++) + avr32_jtag_write_reg(jtag_info, i, regs[i]); + + return ERROR_OK; +} diff --git a/src/target/avr32_regs.h b/src/target/avr32_regs.h new file mode 100644 index 00000000..01ea3ed0 --- /dev/null +++ b/src/target/avr32_regs.h @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.com> * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef AVR32_REGS +#define AVR32_REGS + +enum avr32_reg_nums { + AVR32_REG_R0 = 0, + AVR32_REG_R1, + AVR32_REG_R2, + AVR32_REG_R3, + AVR32_REG_R4, + AVR32_REG_R5, + AVR32_REG_R6, + AVR32_REG_R7, + AVR32_REG_R8, + AVR32_REG_R9, + AVR32_REG_R10, + AVR32_REG_R11, + AVR32_REG_R12, + AVR32_REG_SP, + AVR32_REG_LR, + AVR32_REG_PC, + AVR32_REG_SR, +}; + +int avr32_jtag_read_regs(struct avr32_jtag *jtag_info, uint32_t *regs); +int avr32_jtag_write_regs(struct avr32_jtag *jtag_info, uint32_t *regs); + +#endif /* AVR32_REGS */ + diff --git a/src/target/target.c b/src/target/target.c index 16caea5f..c37432a3 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -70,6 +70,7 @@ extern struct target_type mips_m4k_target; extern struct target_type avr_target; extern struct target_type dsp563xx_target; extern struct target_type testee_target; +extern struct target_type avr32_ap7k_target; static struct target_type *target_types[] = { @@ -90,6 +91,7 @@ static struct target_type *target_types[] = &avr_target, &dsp563xx_target, &testee_target, + &avr32_ap7k_target, NULL, }; |