2008-02-25 11:48:04 -06:00
|
|
|
/***************************************************************************
|
|
|
|
* Copyright (C) 2005 by Dominic Rath *
|
|
|
|
* Dominic.Rath@gmx.de *
|
|
|
|
* *
|
2008-09-20 05:50:53 -05:00
|
|
|
* Copyright (C) 2008 by Spencer Oliver *
|
|
|
|
* spen@spen-soft.co.uk *
|
|
|
|
* *
|
2008-02-25 11:48:04 -06:00
|
|
|
* 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 "arm966e.h"
|
2009-05-31 07:38:28 -05:00
|
|
|
#include "target_type.h"
|
2009-12-07 16:54:12 -06:00
|
|
|
#include "arm_opcodes.h"
|
2008-02-25 11:48:04 -06:00
|
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
#define _DEBUG_INSTRUCTION_EXECUTION_
|
|
|
|
#endif
|
|
|
|
|
2009-11-13 12:11:13 -06:00
|
|
|
int arm966e_init_arch_info(struct target *target, struct arm966e_common *arm966e, struct jtag_tap *tap)
|
2008-02-25 11:48:04 -06:00
|
|
|
{
|
2009-11-17 03:09:50 -06:00
|
|
|
struct arm7_9_common *arm7_9 = &arm966e->arm7_9_common;
|
2008-12-13 00:25:50 -06:00
|
|
|
|
2009-11-17 03:09:50 -06:00
|
|
|
/* initialize arm7/arm9 specific info (including armv4_5) */
|
|
|
|
arm9tdmi_init_arch_info(target, arm7_9, tap);
|
2008-02-25 11:48:04 -06:00
|
|
|
|
|
|
|
arm966e->common_magic = ARM966E_COMMON_MAGIC;
|
2008-12-13 00:25:50 -06:00
|
|
|
|
2008-02-25 11:48:04 -06:00
|
|
|
/* The ARM966E-S implements the ARMv5TE architecture which
|
|
|
|
* has the BKPT instruction, so we don't have to use a watchpoint comparator
|
|
|
|
*/
|
|
|
|
arm7_9->arm_bkpt = ARMV5_BKPT(0x0);
|
|
|
|
arm7_9->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff;
|
2008-12-13 00:25:50 -06:00
|
|
|
|
2008-02-25 11:48:04 -06:00
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
2009-11-13 12:11:13 -06:00
|
|
|
static int arm966e_target_create(struct target *target, Jim_Interp *interp)
|
2008-02-25 11:48:04 -06:00
|
|
|
{
|
2009-11-13 10:40:18 -06:00
|
|
|
struct arm966e_common *arm966e = calloc(1,sizeof(struct arm966e_common));
|
2008-12-13 00:25:50 -06:00
|
|
|
|
2009-11-05 22:35:53 -06:00
|
|
|
return arm966e_init_arch_info(target, arm966e, target->tap);
|
2008-02-25 11:48:04 -06:00
|
|
|
}
|
|
|
|
|
2009-11-13 15:25:47 -06:00
|
|
|
static int arm966e_verify_pointer(struct command_context *cmd_ctx,
|
2009-11-13 10:40:18 -06:00
|
|
|
struct arm966e_common *arm966e)
|
2008-02-25 11:48:04 -06:00
|
|
|
{
|
2009-11-06 00:03:33 -06:00
|
|
|
if (arm966e->common_magic != ARM966E_COMMON_MAGIC) {
|
|
|
|
command_print(cmd_ctx, "target is not an ARM966");
|
|
|
|
return ERROR_TARGET_INVALID;
|
2008-02-25 11:48:04 -06:00
|
|
|
}
|
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
2010-01-07 18:39:32 -06:00
|
|
|
/*
|
|
|
|
* REVISIT: The "read_cp15" and "write_cp15" commands could hook up
|
|
|
|
* to eventual mrc() and mcr() routines ... the reg_addr values being
|
|
|
|
* constructed (for CP15 only) from Opcode_1, Opcode_2, and CRn values.
|
|
|
|
* See section 7.3 of the ARM966E-S TRM.
|
|
|
|
*/
|
|
|
|
|
2009-11-13 12:11:13 -06:00
|
|
|
static int arm966e_read_cp15(struct target *target, int reg_addr, uint32_t *value)
|
2008-02-25 11:48:04 -06:00
|
|
|
{
|
2008-10-14 06:06:30 -05:00
|
|
|
int retval = ERROR_OK;
|
2009-11-13 10:40:03 -06:00
|
|
|
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
|
2009-11-13 10:41:00 -06:00
|
|
|
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
|
2009-11-13 05:28:03 -06:00
|
|
|
struct scan_field fields[3];
|
2009-06-18 02:04:08 -05:00
|
|
|
uint8_t reg_addr_buf = reg_addr & 0x3f;
|
|
|
|
uint8_t nr_w_buf = 0;
|
2008-12-13 00:25:50 -06:00
|
|
|
|
2010-03-18 06:07:41 -05:00
|
|
|
if ((retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE)) != ERROR_OK)
|
2008-10-14 06:06:30 -05:00
|
|
|
{
|
|
|
|
return retval;
|
|
|
|
}
|
2010-03-18 06:07:41 -05:00
|
|
|
arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_IDLE);
|
2008-02-25 11:48:04 -06:00
|
|
|
|
|
|
|
fields[0].num_bits = 32;
|
2010-01-07 18:39:32 -06:00
|
|
|
/* REVISIT: table 7-2 shows that bits 31-31 need to be
|
|
|
|
* specified for accessing BIST registers ...
|
|
|
|
*/
|
2008-02-25 11:48:04 -06:00
|
|
|
fields[0].out_value = NULL;
|
|
|
|
fields[0].in_value = NULL;
|
|
|
|
|
|
|
|
fields[1].num_bits = 6;
|
|
|
|
fields[1].out_value = ®_addr_buf;
|
|
|
|
fields[1].in_value = NULL;
|
|
|
|
|
|
|
|
fields[2].num_bits = 1;
|
|
|
|
fields[2].out_value = &nr_w_buf;
|
|
|
|
fields[2].in_value = NULL;
|
2008-12-13 00:25:50 -06:00
|
|
|
|
2010-03-16 08:13:03 -05:00
|
|
|
jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
|
2008-02-25 11:48:04 -06:00
|
|
|
|
2009-06-18 02:04:08 -05:00
|
|
|
fields[1].in_value = (uint8_t *)value;
|
2009-05-07 08:36:35 -05:00
|
|
|
|
2010-03-16 08:13:03 -05:00
|
|
|
jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
|
2009-05-07 08:36:35 -05:00
|
|
|
|
2009-06-19 03:18:36 -05:00
|
|
|
jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)value);
|
2008-02-25 11:48:04 -06:00
|
|
|
|
|
|
|
|
|
|
|
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
|
2009-05-10 14:01:03 -05:00
|
|
|
if ((retval = jtag_execute_queue()) != ERROR_OK)
|
2008-10-14 06:06:30 -05:00
|
|
|
{
|
|
|
|
return retval;
|
|
|
|
}
|
2008-03-25 10:45:17 -05:00
|
|
|
LOG_DEBUG("addr: 0x%x value: %8.8x", reg_addr, *value);
|
2008-02-25 11:48:04 -06:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
2009-11-05 22:35:53 -06:00
|
|
|
// EXPORTED to str9x (flash)
|
2009-11-13 12:11:13 -06:00
|
|
|
int arm966e_write_cp15(struct target *target, int reg_addr, uint32_t value)
|
2008-02-25 11:48:04 -06:00
|
|
|
{
|
2008-10-14 06:06:30 -05:00
|
|
|
int retval = ERROR_OK;
|
2009-11-13 10:40:03 -06:00
|
|
|
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
|
2009-11-13 10:41:00 -06:00
|
|
|
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
|
2009-11-13 05:28:03 -06:00
|
|
|
struct scan_field fields[3];
|
2009-06-18 02:04:08 -05:00
|
|
|
uint8_t reg_addr_buf = reg_addr & 0x3f;
|
|
|
|
uint8_t nr_w_buf = 1;
|
|
|
|
uint8_t value_buf[4];
|
2008-12-13 00:25:50 -06:00
|
|
|
|
2008-02-25 11:48:04 -06:00
|
|
|
buf_set_u32(value_buf, 0, 32, value);
|
2008-12-13 00:25:50 -06:00
|
|
|
|
2010-03-18 06:07:41 -05:00
|
|
|
if ((retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE)) != ERROR_OK)
|
2008-10-14 06:06:30 -05:00
|
|
|
{
|
|
|
|
return retval;
|
|
|
|
}
|
2010-03-18 06:07:41 -05:00
|
|
|
arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_IDLE);
|
2008-02-25 11:48:04 -06:00
|
|
|
|
|
|
|
fields[0].num_bits = 32;
|
|
|
|
fields[0].out_value = value_buf;
|
|
|
|
fields[0].in_value = NULL;
|
2009-05-07 08:36:35 -05:00
|
|
|
|
2008-02-25 11:48:04 -06:00
|
|
|
fields[1].num_bits = 6;
|
|
|
|
fields[1].out_value = ®_addr_buf;
|
|
|
|
fields[1].in_value = NULL;
|
2009-05-07 08:36:35 -05:00
|
|
|
|
2008-02-25 11:48:04 -06:00
|
|
|
fields[2].num_bits = 1;
|
|
|
|
fields[2].out_value = &nr_w_buf;
|
|
|
|
fields[2].in_value = NULL;
|
2009-05-07 08:36:35 -05:00
|
|
|
|
2010-03-16 08:13:03 -05:00
|
|
|
jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
|
2008-02-25 11:48:04 -06:00
|
|
|
|
|
|
|
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
|
2008-03-25 10:45:17 -05:00
|
|
|
LOG_DEBUG("addr: 0x%x value: %8.8x", reg_addr, value);
|
2008-02-25 11:48:04 -06:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
2009-11-10 01:56:52 -06:00
|
|
|
COMMAND_HANDLER(arm966e_handle_cp15_command)
|
2008-02-25 11:48:04 -06:00
|
|
|
{
|
|
|
|
int retval;
|
2009-11-15 07:57:37 -06:00
|
|
|
struct target *target = get_current_target(CMD_CTX);
|
2009-11-13 10:40:18 -06:00
|
|
|
struct arm966e_common *arm966e = target_to_arm966(target);
|
2008-02-25 11:48:04 -06:00
|
|
|
|
2009-11-15 07:57:37 -06:00
|
|
|
retval = arm966e_verify_pointer(CMD_CTX, arm966e);
|
2009-11-06 00:03:33 -06:00
|
|
|
if (retval != ERROR_OK)
|
|
|
|
return retval;
|
2008-12-13 00:25:50 -06:00
|
|
|
|
2008-02-25 11:48:04 -06:00
|
|
|
if (target->state != TARGET_HALTED)
|
|
|
|
{
|
2009-11-15 07:57:37 -06:00
|
|
|
command_print(CMD_CTX, "target must be stopped for \"%s\" command", CMD_NAME);
|
2008-02-25 11:48:04 -06:00
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* one or more argument, access a single register (write if second argument is given */
|
2009-11-15 06:57:12 -06:00
|
|
|
if (CMD_ARGC >= 1)
|
2008-02-25 11:48:04 -06:00
|
|
|
{
|
2009-10-24 08:36:05 -05:00
|
|
|
uint32_t address;
|
2009-11-15 10:15:59 -06:00
|
|
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address);
|
2008-02-25 11:48:04 -06:00
|
|
|
|
2009-11-15 06:57:12 -06:00
|
|
|
if (CMD_ARGC == 1)
|
2008-02-25 11:48:04 -06:00
|
|
|
{
|
2009-06-18 02:08:52 -05:00
|
|
|
uint32_t value;
|
2008-02-25 11:48:04 -06:00
|
|
|
if ((retval = arm966e_read_cp15(target, address, &value)) != ERROR_OK)
|
|
|
|
{
|
2009-11-15 07:57:37 -06:00
|
|
|
command_print(CMD_CTX,
|
2009-11-12 16:21:33 -06:00
|
|
|
"couldn't access reg %" PRIi32,
|
|
|
|
address);
|
2008-02-25 11:48:04 -06:00
|
|
|
return ERROR_OK;
|
|
|
|
}
|
2009-05-10 14:01:03 -05:00
|
|
|
if ((retval = jtag_execute_queue()) != ERROR_OK)
|
2008-10-14 06:06:30 -05:00
|
|
|
{
|
|
|
|
return retval;
|
|
|
|
}
|
2008-12-13 00:25:50 -06:00
|
|
|
|
2009-11-15 07:57:37 -06:00
|
|
|
command_print(CMD_CTX, "%" PRIi32 ": %8.8" PRIx32,
|
2009-11-12 16:21:33 -06:00
|
|
|
address, value);
|
2008-02-25 11:48:04 -06:00
|
|
|
}
|
2009-11-15 06:57:12 -06:00
|
|
|
else if (CMD_ARGC == 2)
|
2008-02-25 11:48:04 -06:00
|
|
|
{
|
2009-10-24 08:36:05 -05:00
|
|
|
uint32_t value;
|
2009-11-15 10:15:59 -06:00
|
|
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
|
2008-02-25 11:48:04 -06:00
|
|
|
if ((retval = arm966e_write_cp15(target, address, value)) != ERROR_OK)
|
|
|
|
{
|
2009-11-15 07:57:37 -06:00
|
|
|
command_print(CMD_CTX,
|
2009-11-12 16:21:33 -06:00
|
|
|
"couldn't access reg %" PRIi32,
|
|
|
|
address);
|
2008-02-25 11:48:04 -06:00
|
|
|
return ERROR_OK;
|
|
|
|
}
|
2009-11-15 07:57:37 -06:00
|
|
|
command_print(CMD_CTX, "%" PRIi32 ": %8.8" PRIx32,
|
2009-11-12 16:21:33 -06:00
|
|
|
address, value);
|
2008-02-25 11:48:04 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
2009-11-23 09:43:05 -06:00
|
|
|
static const struct command_registration arm966e_exec_command_handlers[] = {
|
|
|
|
{
|
|
|
|
.name = "cp15",
|
|
|
|
.handler = arm966e_handle_cp15_command,
|
|
|
|
.mode = COMMAND_EXEC,
|
2010-01-07 18:39:32 -06:00
|
|
|
.usage = "regnum [value]",
|
2009-11-23 09:43:05 -06:00
|
|
|
.help = "display/modify cp15 register",
|
|
|
|
},
|
|
|
|
COMMAND_REGISTRATION_DONE
|
|
|
|
};
|
|
|
|
|
2009-11-23 10:17:01 -06:00
|
|
|
const struct command_registration arm966e_command_handlers[] = {
|
|
|
|
{
|
|
|
|
.chain = arm9tdmi_command_handlers,
|
|
|
|
},
|
2009-11-23 09:43:05 -06:00
|
|
|
{
|
|
|
|
.name = "arm966e",
|
|
|
|
.mode = COMMAND_ANY,
|
|
|
|
.help = "arm966e command group",
|
|
|
|
.chain = arm966e_exec_command_handlers,
|
|
|
|
},
|
|
|
|
COMMAND_REGISTRATION_DONE
|
|
|
|
};
|
|
|
|
|
2009-11-05 22:35:53 -06:00
|
|
|
/** Holds methods for ARM966 targets. */
|
2009-11-13 11:52:20 -06:00
|
|
|
struct target_type arm966e_target =
|
2009-11-05 22:35:53 -06:00
|
|
|
{
|
|
|
|
.name = "arm966e",
|
|
|
|
|
|
|
|
.poll = arm7_9_poll,
|
2009-12-07 16:54:13 -06:00
|
|
|
.arch_state = arm_arch_state,
|
2009-11-05 22:35:53 -06:00
|
|
|
|
|
|
|
.target_request_data = arm7_9_target_request_data,
|
|
|
|
|
|
|
|
.halt = arm7_9_halt,
|
|
|
|
.resume = arm7_9_resume,
|
|
|
|
.step = arm7_9_step,
|
|
|
|
|
|
|
|
.assert_reset = arm7_9_assert_reset,
|
|
|
|
.deassert_reset = arm7_9_deassert_reset,
|
|
|
|
.soft_reset_halt = arm7_9_soft_reset_halt,
|
|
|
|
|
2009-12-07 16:54:13 -06:00
|
|
|
.get_gdb_reg_list = arm_get_gdb_reg_list,
|
2009-11-05 22:35:53 -06:00
|
|
|
|
|
|
|
.read_memory = arm7_9_read_memory,
|
|
|
|
.write_memory = arm7_9_write_memory,
|
|
|
|
.bulk_write_memory = arm7_9_bulk_write_memory,
|
2009-11-15 12:35:34 -06:00
|
|
|
|
|
|
|
.checksum_memory = arm_checksum_memory,
|
|
|
|
.blank_check_memory = arm_blank_check_memory,
|
2009-11-05 22:35:53 -06:00
|
|
|
|
|
|
|
.run_algorithm = armv4_5_run_algorithm,
|
|
|
|
|
|
|
|
.add_breakpoint = arm7_9_add_breakpoint,
|
|
|
|
.remove_breakpoint = arm7_9_remove_breakpoint,
|
|
|
|
.add_watchpoint = arm7_9_add_watchpoint,
|
|
|
|
.remove_watchpoint = arm7_9_remove_watchpoint,
|
|
|
|
|
2009-11-23 10:17:01 -06:00
|
|
|
.commands = arm966e_command_handlers,
|
2009-11-05 22:35:53 -06:00
|
|
|
.target_create = arm966e_target_create,
|
|
|
|
.init_target = arm9tdmi_init_target,
|
2009-11-13 18:26:39 -06:00
|
|
|
.examine = arm7_9_examine,
|
2010-01-11 08:30:22 -06:00
|
|
|
.check_reset = arm7_9_check_reset,
|
2009-11-05 22:35:53 -06:00
|
|
|
};
|