[ 2820437 ] ARM9 bus support (Jochen Friedrich)

git-svn-id: https://urjtag.svn.sourceforge.net/svnroot/urjtag/trunk@1665 b68d4a1b-bc3d-0410-92ed-d4ac073336b7
master
Arnim Läuger 16 years ago
parent 240bd7b59e
commit ed8ecbd30d

@ -1,5 +1,9 @@
2009-07-15 Arnim Laeuger <arniml>
* src/bus/arm9tdmi.c, src/bus/buses.c, src/bus/buses.h,
src/bus/Makefile.am, configure.ac, po/POTFILES.in:
[ 2820437 ] ARM9 bus support (Jochen Friedrich)
* data/broadcom/bcm4702/STEPPINGS, data/broadcom/bcm4702/bcm4702,
data/broadcom/PARTS, data/Makefile.am:
[ 2815741 ] Add bcm4702 definitions (Jochen Friedrich)

@ -477,7 +477,7 @@ AC_DEFUN([CHECK_DRIVER], [
# Enable bus drivers
AC_DEFUN([DEF_ENABLE_BUSDRIVERS], [\
au1500 avr32 bcm1250 bf526_ezkit bf527_ezkit bf533_stamp bf533_ezkit bf537_stamp bf537_ezkit bf538f_ezkit bf548_ezkit bf561_ezkit bscoach ejtag ejtag_dma\
arm9tdmi au1500 avr32 bcm1250 bf526_ezkit bf527_ezkit bf533_stamp bf533_ezkit bf537_stamp bf537_ezkit bf538f_ezkit bf548_ezkit bf561_ezkit bscoach ejtag ejtag_dma \
fjmem ixp425 ixp435 jopcyc h7202 lh7a400 mpc5200 mpc824x ppc405ep ppc440gx_ebc8 prototype pxa2x0 pxa27x \
s3c4510 sa1110 sh7727 sh7750r sh7751r sharc_21065L slsup3 tx4925 zefant_xs3])
AC_ARG_ENABLE(bus,
@ -495,6 +495,7 @@ AC_ARG_ENABLE(bus,
busdrivers=`echo ${busdrivers} | $SED -e "s/default/DEF_ENABLE_BUSDRIVERS/"`
#
enabled_bus_drivers=''
CHECK_DRIVER([$busdrivers], [enabled_bus_drivers], [arm9tdmi], [ENABLE_BUS_ARM9TDMI])
CHECK_DRIVER([$busdrivers], [enabled_bus_drivers], [au1500], [ENABLE_BUS_AU1500])
CHECK_DRIVER([$busdrivers], [enabled_bus_drivers], [avr32], [ENABLE_BUS_AVR32])
CHECK_DRIVER([$busdrivers], [enabled_bus_drivers], [bcm1250], [ENABLE_BUS_BCM1250])

@ -7,6 +7,7 @@ src/bsdl/bsdl_flex.c
src/bsdl/bsdl_sem.c
src/bsdl/vhdl_bison.c
src/bsdl/vhdl_flex.c
src/bus/arm9tdmi.c
src/bus/au1500.c
src/bus/avr32.c
src/bus/bcm1250.c

@ -34,6 +34,10 @@ libbus_la_SOURCES = \
readmem.c \
writemem.c
if ENABLE_BUS_ARM9TDMI
libbus_la_SOURCES += arm9tdmi.c
endif
if ENABLE_BUS_AU1500
libbus_la_SOURCES += au1500.c
endif

@ -0,0 +1,571 @@
/*
* $Id$
*
* ARM9TDMI core bus driver
* Copyright (C) 2003, Rongkai zhan <zhanrk@163.com>
* Copyright (C) 2009, Jochen Friedrich <jochen@scram.de>
*
* 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.
*
*/
#define ARM9DEBUG 0
#include <sysdep.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <urjtag/part.h>
#include <urjtag/bus.h>
#include <urjtag/chain.h>
#include <urjtag/bssignal.h>
#include <urjtag/tap_state.h>
#include <urjtag/tap_register.h>
#include <urjtag/data_register.h>
#include "buses.h"
#include "generic_bus.h"
typedef struct
{
uint32_t chain; /* Chain number */
} bus_params_t;
#define BP ((bus_params_t *) bus->params)
#define ARM9TDMI_ICE_DBGCTL 0x00
#define ARM9TDMI_ICE_DBGSTAT 0x01
#define DEBUG_SPEED 0
#define SYSTEM_SPEED 1
#define ARM_NOP 0xE1A00000
static urj_data_register_t *scann = NULL;
static urj_data_register_t *scan1 = NULL;
static urj_data_register_t *scan2 = NULL;
static uint32_t _data_read;
/**
* bus->driver->(*new_bus)
*
*/
static urj_bus_t *
arm9tdmi_bus_new (urj_chain_t *chain, const urj_bus_driver_t *driver,
const urj_param_t *cmd_params[])
{
return urj_bus_generic_new (chain, driver, sizeof (bus_params_t));
}
/**
* bus->driver->(*printinfo)
*
*/
static void
arm9tdmi_bus_printinfo (urj_log_level_t ll, urj_bus_t *bus)
{
int i;
for (i = 0; i < bus->chain->parts->len; i++)
if (bus->part == bus->chain->parts->parts[i])
break;
urj_log (ll, _("ARM9TDMI compatible bus driver (JTAG part No. %d)\n"),
i);
}
/**
* helper functions
*
*/
#if (ARM9DEBUG)
static void
arm9tdmi_debug_in_reg(urj_data_register_t *reg)
{
int i;
urj_log(URJ_LOG_LEVEL_ALL, "in :");
for (i = 0; i < reg->in->len; i++)
urj_log(URJ_LOG_LEVEL_ALL, reg->in->data[i]?"1":"0");
urj_log(URJ_LOG_LEVEL_ALL, "\n");
}
static void
arm9tdmi_debug_out_reg(urj_data_register_t *reg)
{
int i;
urj_log(URJ_LOG_LEVEL_ALL, "out :");
for (i = 0; i < reg->out->len; i++)
urj_log(URJ_LOG_LEVEL_ALL, reg->out->data[i]?"1":"0");
urj_log(URJ_LOG_LEVEL_ALL, "\n");
}
#endif
static void
arm9tdmi_exec_instruction(urj_bus_t *bus, unsigned int c1_inst, unsigned int c1_data, unsigned int flags)
{
int i;
for (i = 0; i < 32; i++)
scan1->in->data[66-i] = (c1_inst >> i) & 1;
scan1->in->data[34] = flags;
scan1->in->data[33] = 0;
scan1->in->data[32] = 0;
for (i = 0; i < 32; i++)
scan1->in->data[i] = (c1_data >> i) & 1;
#if (ARM9DEBUG)
arm9tdmi_debug_in_reg(scan1);
#endif
urj_tap_chain_shift_data_registers (bus->chain, 1);
#if (ARM9DEBUG)
arm9tdmi_debug_out_reg(scan1);
#endif
}
static void
arm9tdmi_select_scanchain(urj_bus_t *bus, unsigned int chain)
{
int i;
urj_part_set_instruction (bus->part, "SCAN_N");
urj_tap_chain_shift_instructions (bus->chain);
for (i = 0; i < scann->in->len; i++)
scann->in->data[i] = (chain >> i) & 1;
urj_tap_chain_shift_data_registers (bus->chain, 0);
}
static void
arm9tdmi_ice_read(urj_bus_t *bus, unsigned int reg_addr, unsigned int *reg_val)
{
int i;
for (i = 0; i < 32; i++)
scan2->in->data[i] = 0;
for (i = 0; i < 5; i++)
scan2->in->data[i+32] = (reg_addr >> i) & 1;
scan2->in->data[37] = 0;
urj_tap_chain_shift_data_registers (bus->chain, 1);
for (i = 0; i < 32; i++)
{
if (scan2->out->data[i])
*reg_val |= (1 << i);
}
}
static void
arm9tdmi_ice_write(urj_bus_t *bus, unsigned int reg_addr, unsigned int reg_val)
{
int i;
for (i = 0; i < 32; i++)
scan2->in->data[i] = (reg_val >> i) & 1;
for (i = 0; i < 5; i++)
scan2->in->data[i+32] = (reg_addr >> i) & 1;
scan2->in->data[37] = 1;
urj_tap_chain_shift_data_registers (bus->chain, 0);
}
/**
* low-level memory write
*
*/
static void
arm9tdmi_write(urj_bus_t *bus, unsigned int addr, unsigned int data, unsigned int sz)
{
unsigned int c1_inst, c1_data;
/*
* Load R0 with the address to write.
* Load R1 with the data to write.
*/
c1_inst = 0xE59F0000; /* LDR R0, [PC] */
c1_data = 0;
arm9tdmi_exec_instruction(bus, c1_inst, c1_data, DEBUG_SPEED);
c1_inst = 0xE59F1000; /* LDR R1, [PC] */
c1_data = 0;
arm9tdmi_exec_instruction(bus, c1_inst, c1_data, DEBUG_SPEED);
/* Flush pipeline before SYSTEM_SPEED access */
c1_inst = ARM_NOP;
c1_data = 0;
arm9tdmi_exec_instruction(bus, c1_inst, c1_data, DEBUG_SPEED);
c1_data = addr;
arm9tdmi_exec_instruction(bus, c1_inst, c1_data, DEBUG_SPEED);
c1_data = data;
arm9tdmi_exec_instruction(bus, c1_inst, c1_data, DEBUG_SPEED);
c1_data = 0;
arm9tdmi_exec_instruction(bus, c1_inst, c1_data, DEBUG_SPEED);
if (sz == 32)
c1_inst = 0xE5801000; /* STR R1, [R0] */
else if (sz == 16)
c1_inst = 0xE1C010B0; /* STRH R1, [R0] */
else if (sz == 8)
c1_inst = 0xE5C01000; /* STRB R1, [R0] */
c1_data = 0;
arm9tdmi_exec_instruction(bus, c1_inst, c1_data, DEBUG_SPEED);
/*
* Execute instruction at SYSTEM_SPEED as we need to access memory
*/
c1_inst = ARM_NOP;
arm9tdmi_exec_instruction(bus, c1_inst, c1_data, SYSTEM_SPEED);
urj_tap_chain_flush(bus->chain);
/* Write RESTART instruction into the TAP controller.
* When the state machine enters the Run-Test/Idle state,
* the ARM9TDMI core will revert back to system mode,
* and it will resynchronize clock to MCLK.
*/
urj_part_set_instruction (bus->part, "RESTART");
urj_tap_chain_shift_instructions (bus->chain);
/*
* Now, the ARM9TDMI core re-entered the debug state.
* Before the debug session continues, we must load the
* TAP controller with the INTEST instruction. We can use
* the instruction "STR R1, [R1]" running at debug-speed to
* read out the contents of register R1.
*/
urj_part_set_instruction (bus->part, "INTEST1");
urj_tap_chain_shift_instructions_mode (bus->chain, 0, 1,
URJ_CHAIN_EXITMODE_UPDATE);
}
/**
* low level memory read
*
*/
static unsigned int
arm9tdmi_read (urj_bus_t *bus, unsigned int addr, unsigned int sz)
{
unsigned int c1_inst, c1_data, result, i;
/*
* Load R0 with the address to read
*/
c1_inst = 0xE59F0000; /* LDR R0, [PC] */
c1_data = 0;
arm9tdmi_exec_instruction(bus, c1_inst, c1_data, DEBUG_SPEED);
c1_inst = ARM_NOP;
c1_data = 0;
arm9tdmi_exec_instruction(bus, c1_inst, c1_data, DEBUG_SPEED);
arm9tdmi_exec_instruction(bus, c1_inst, c1_data, DEBUG_SPEED);
c1_data = addr;
arm9tdmi_exec_instruction(bus, c1_inst, c1_data, DEBUG_SPEED);
c1_data = 0;
arm9tdmi_exec_instruction(bus, c1_inst, c1_data, DEBUG_SPEED);
if (sz == 32)
c1_inst = 0xE5901000; /* LDR R1, [R0] */
else if (sz == 16)
c1_inst = 0xE1D010B0; /* LDRH R1, [R0] */
else if (sz == 8)
c1_inst = 0xE5D01000; /* LDRB R1, [R0] */
c1_data = 0;
arm9tdmi_exec_instruction(bus, c1_inst, c1_data, DEBUG_SPEED);
/*
* Execute instruction at SYSTEM_SPEED as we need to access memory
*/
c1_inst = ARM_NOP;
arm9tdmi_exec_instruction(bus, c1_inst, c1_data, SYSTEM_SPEED);
urj_tap_chain_flush(bus->chain);
/* Write RESTART instruction into the TAP controller.
* When the state machine enters the Run-Test/Idle state,
* the ARM9TDMI core will revert back to system mode,
* and it will resynchronize clock to MCLK.
*/
urj_part_set_instruction (bus->part, "RESTART");
urj_tap_chain_shift_instructions (bus->chain);
/*
* Now, the ARM9TDMI core re-entered the debug state.
* Before the debug session continues, we must load the
* TAP controller with the INTEST instruction. We can use
* the instruction "STR R1, [PC]" running at debug-speed to
* read out the contents of register R1.
*/
urj_part_set_instruction (bus->part, "INTEST1");
urj_tap_chain_shift_instructions_mode (bus->chain, 0, 1,
URJ_CHAIN_EXITMODE_UPDATE);
c1_inst = 0xE58F1000; /* STR R1, [PC] */
c1_data = 0;
arm9tdmi_exec_instruction(bus, c1_inst, c1_data, DEBUG_SPEED);
c1_inst = ARM_NOP;
c1_data = 0;
arm9tdmi_exec_instruction(bus, c1_inst, c1_data, DEBUG_SPEED);
arm9tdmi_exec_instruction(bus, c1_inst, c1_data, DEBUG_SPEED);
arm9tdmi_exec_instruction(bus, c1_inst, c1_data, DEBUG_SPEED);
result = 0;
for (i = 0; i < 32; i++)
{
if (scan1->out->data[i])
result |= (1 << i);
}
arm9tdmi_exec_instruction(bus, c1_inst, c1_data, DEBUG_SPEED);
return result;
}
/**
* bus->driver->(*initbus)
*
*/
static int
arm9tdmi_bus_init (urj_bus_t *bus)
{
unsigned int i, status, success;
if (urj_tap_state (bus->chain) != URJ_TAP_STATE_RUN_TEST_IDLE)
{
/* silently skip initialization if TAP isn't in RUNTEST/IDLE state
this is required to avoid interfering with detect when initbus
is contained in the part description file
URJ_BUS_INIT() will be called latest by URJ_BUS_PREPARE() */
return URJ_STATUS_OK;
}
if (scann == NULL)
scann = urj_part_find_data_register (bus->part, "SCANN");
if (scan1 == NULL)
scan1 = urj_part_find_data_register (bus->part, "SCAN1");
if (scan2 == NULL)
scan2 = urj_part_find_data_register (bus->part, "SCAN2");
if (!(scann))
{
urj_error_set (URJ_ERROR_NOTFOUND,
_("SCANN register"));
return URJ_STATUS_FAIL;
}
if (!(scan1))
{
urj_error_set (URJ_ERROR_NOTFOUND,
_("SCAN1 register"));
return URJ_STATUS_FAIL;
}
if (!(scan2))
{
urj_error_set (URJ_ERROR_NOTFOUND,
_("SCAN2 register"));
return URJ_STATUS_FAIL;
}
/*
* select scan chain 2 -- EmbeddedICE-RT
*/
arm9tdmi_select_scanchain(bus, 2);
urj_part_set_instruction (bus->part, "INTEST2");
urj_tap_chain_shift_instructions (bus->chain);
arm9tdmi_ice_write(bus, ARM9TDMI_ICE_DBGCTL, 0x3);
urj_part_set_instruction (bus->part, "RESTART");
urj_tap_chain_shift_instructions (bus->chain);
i = 0;
success = 0;
status = 0;
while (i++ < 10) {
urj_part_set_instruction (bus->part, "INTEST2");
urj_tap_chain_shift_instructions (bus->chain);
arm9tdmi_ice_read(bus, ARM9TDMI_ICE_DBGSTAT, &status);
if (status & 0x01) {
success = 1;
break;
}
urj_part_set_instruction (bus->part, "RESTART");
urj_tap_chain_shift_instructions (bus->chain);
usleep(100);
}
if (!success)
{
urj_error_set (URJ_ERROR_TIMEOUT,
_("Failed to enter debug mode, ctrl=%s"),
urj_tap_register_get_string (scan2->out));
return URJ_STATUS_FAIL;
}
arm9tdmi_ice_write(bus, ARM9TDMI_ICE_DBGCTL, 0x00);
urj_log (URJ_LOG_LEVEL_NORMAL, _("The target is halted in "));
if (status & 0x10)
urj_log (URJ_LOG_LEVEL_NORMAL, _("THUMB mode.\n"));
else
urj_log (URJ_LOG_LEVEL_NORMAL, _("ARM mode.\n"));
/* select scan chain 1, and use INTEST instruction */
arm9tdmi_select_scanchain(bus, 1);
urj_part_set_instruction (bus->part, "INTEST1");
urj_tap_chain_shift_instructions_mode (bus->chain, 0, 1,
URJ_CHAIN_EXITMODE_UPDATE);
bus->initialized = 1;
return URJ_STATUS_OK;
}
/**
* bus->driver->(*prepare)
*
*/
static void
arm9tdmi_bus_prepare (urj_bus_t *bus)
{
if (!bus->initialized)
URJ_BUS_INIT (bus);
}
/**
* bus->driver->(*area)
*
*/
static int
arm9tdmi_bus_area (urj_bus_t *bus, uint32_t adr, urj_bus_area_t *area)
{
if (adr < UINT32_C (0xF0000000))
{
area->description = "USEG : User addresses";
area->start = UINT32_C (0x00000000);
area->length = UINT64_C (0xF0000000);
area->width = 32;
}
else
{
area->description = "FLASH : Addresses in flash (boot=0xffff0000)";
area->start = UINT32_C (0xF0000000);
area->length = UINT64_C (0x10000000);
area->width = 16;
}
return URJ_STATUS_OK;
}
static int
get_sz (uint32_t adr)
{
urj_bus_area_t area;
arm9tdmi_bus_area (NULL, adr, &area);
return area.width;
}
/**
* bus->driver->(*write)
*
*/
static void
arm9tdmi_bus_write (urj_bus_t *bus, uint32_t adr, uint32_t data)
{
urj_log (URJ_LOG_LEVEL_ALL, "%s:adr=0x%lx,got=0x%lx\n", __func__,
(long unsigned) adr, (long unsigned) data);
arm9tdmi_write (bus, adr, data, get_sz (adr));
}
/**
* bus->driver->(*read)
*
*/
static uint32_t
arm9tdmi_bus_read (urj_bus_t *bus, uint32_t adr)
{
int data = arm9tdmi_read (bus, adr, get_sz (adr));
urj_log (URJ_LOG_LEVEL_ALL, "%s:adr=0x%lx,got=0x%lx\n", __func__,
(long unsigned) adr, (long unsigned) data);
return data;
}
/**
* bus->driver->(*read_start)
*
*/
static int
arm9tdmi_bus_read_start (urj_bus_t *bus, uint32_t adr)
{
_data_read = arm9tdmi_read (bus, adr, get_sz (adr));
urj_log (URJ_LOG_LEVEL_ALL, "%s:adr=0x%lx, got=0x%lx\n", __func__,
(long unsigned) adr, (long unsigned) _data_read);
return URJ_STATUS_OK;
}
/**
* bus->driver->(*read_next)
*
*/
static uint32_t
arm9tdmi_bus_read_next (urj_bus_t *bus, uint32_t adr)
{
uint32_t tmp_value = _data_read;
_data_read = arm9tdmi_read (bus, adr, get_sz (adr));
urj_log (URJ_LOG_LEVEL_ALL, "%s:adr=0x%lx, got=0x%lx\n", __func__,
(long unsigned) adr, (long unsigned) _data_read);
return tmp_value;
}
/**
* bus->driver->(*read_end)
*
*/
static uint32_t
arm9tdmi_bus_read_end (urj_bus_t *bus)
{
return _data_read;
}
const urj_bus_driver_t urj_bus_arm9tdmi_bus = {
"arm9tdmi",
N_("ARM9TDMI compatible bus driver"),
arm9tdmi_bus_new,
urj_bus_generic_free,
arm9tdmi_bus_printinfo,
arm9tdmi_bus_prepare,
arm9tdmi_bus_area,
arm9tdmi_bus_read_start,
arm9tdmi_bus_read_next,
arm9tdmi_bus_read_end,
arm9tdmi_bus_read,
arm9tdmi_bus_write,
arm9tdmi_bus_init
};

@ -36,6 +36,9 @@
#include "buses.h"
const urj_bus_driver_t *urj_bus_drivers[] = {
#ifdef ENABLE_BUS_ARM9TDMI
&urj_bus_arm9tdmi_bus,
#endif
#ifdef ENABLE_BUS_AU1500
&urj_bus_au1500_bus,
#endif

@ -25,6 +25,7 @@
#ifndef URJ_BUS_BUSES_H
#define URJ_BUS_BUSES_H
extern const urj_bus_driver_t urj_bus_arm9tdmi_bus;
extern const urj_bus_driver_t urj_bus_au1500_bus;
extern const urj_bus_driver_t urj_bus_avr32_bus_driver;
extern const urj_bus_driver_t urj_bus_bcm1250_bus;

Loading…
Cancel
Save