/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* Copyright (C) 2008 by Hongtao Zheng *
* hontor@126.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 "arm9tdmi.h"
#include "target_type.h"
#include "register.h"
#include "arm_opcodes.h"
/*
* NOTE: this holds code that's used with multiple ARM9 processors:
* - ARM9TDMI (ARMv4T) ... in ARM920, ARM922, and ARM940 cores
* - ARM9E-S (ARMv5TE) ... in ARM946, ARM966, and ARM968 cores
* - ARM9EJS (ARMv5TEJ) ... in ARM926 core
*
* In short, the file name is a misnomer ... it is NOT specific to
* that first generation ARM9 processor, or cores using it.
*/
#if 0
#define _DEBUG_INSTRUCTION_EXECUTION_
#endif
enum arm9tdmi_vector_bit
{
ARM9TDMI_RESET_VECTOR = 0x01,
ARM9TDMI_UNDEF_VECTOR = 0x02,
ARM9TDMI_SWI_VECTOR = 0x04,
ARM9TDMI_PABT_VECTOR = 0x08,
ARM9TDMI_DABT_VECTOR = 0x10,
/* BIT(5) reserved -- must be zero */
ARM9TDMI_IRQ_VECTOR = 0x40,
ARM9TDMI_FIQ_VECTOR = 0x80,
};
static const struct arm9tdmi_vector {
const char *name;
uint32_t value;
} arm9tdmi_vectors[] = {
{"reset", ARM9TDMI_RESET_VECTOR},
{"undef", ARM9TDMI_UNDEF_VECTOR},
{"swi", ARM9TDMI_SWI_VECTOR},
{"pabt", ARM9TDMI_PABT_VECTOR},
{"dabt", ARM9TDMI_DABT_VECTOR},
{"irq", ARM9TDMI_IRQ_VECTOR},
{"fiq", ARM9TDMI_FIQ_VECTOR},
{0, 0},
};
int arm9tdmi_examine_debug_reason(struct target *target)
{
int retval = ERROR_OK;
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
/* only check the debug reason if we don't know it already */
if ((target->debug_reason != DBG_REASON_DBGRQ)
&& (target->debug_reason != DBG_REASON_SINGLESTEP))
{
struct scan_field fields[3];
uint8_t databus[4];
uint8_t instructionbus[4];
uint8_t debug_reason;
fields[0].num_bits = 32;
fields[0].out_value = NULL;
fields[0].in_value = databus;
fields[1].num_bits = 3;
fields[1].out_value = NULL;
fields[1].in_value = &debug_reason;
fields[2].num_bits = 32;
fields[2].out_value = NULL;
fields[2].in_value = instructionbus;
if ((retval = arm_jtag_scann(&arm7_9->jtag_info, 0x1, TAP_DRPAUSE)) != ERROR_OK)
{
return retval;
}
retval = arm_jtag_set_instr(&arm7_9->jtag_info, arm7_9->jtag_info.intest_instr, NULL, TAP_DRPAUSE);
if (retval != ERROR_OK)
return retval;
jtag_add_dr_scan(arm7_9->jtag_info.tap, 3, fields, TAP_DRPAUSE);
if ((retval = jtag_execute_queue()) != ERROR_OK)
{
return retval;
}
fields[0].in_value = NULL;
fields[0].out_value = databus;
fields[1].in_value = NULL;
fields[1].out_value = &debug_reason;
fields[2].in_value = NULL;
fields[2].out_value = instructionbus;
jtag_add_dr_scan(arm7_9->jtag_info.tap, 3, fields, TAP_DRPAUSE);
if (debug_reason & 0x4)
if (debug_reason & 0x2)
target->debug_reason = DBG_REASON_WPTANDBKPT;
else
target->debug_reason = DBG_REASON_WATCHPOINT;
else
target->debug_reason = DBG_REASON_BREAKPOINT;
}
return ERROR_OK;
}
/* put an instruction in the ARM9TDMI pipeline or write the data bus,
* and optionally read data
*/
int arm9tdmi_clock_out(struct arm_jtag *jtag_info, uint32_t instr,
uint32_t out, uint32_t *in, int sysspeed)
{
int retval = ERROR_OK;
struct scan_field fields[3];
uint8_t out_buf[4];
uint8_t instr_buf[4];
uint8_t sysspeed_buf = 0x0;
/* prepare buffer */
buf_set_u32(out_buf, 0, 32, out);
buf_set_u32(instr_buf, 0, 32, flip_u32(instr, 32));
if (sysspeed)
buf_set_u32(&sysspeed_buf, 2, 1, 1);
if ((retval = arm_jtag_scann(jtag_info, 0x1, TAP_DRPAUSE)) != ERROR_OK)
{
return retval;
}
retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr,