1702 lines
39 KiB
C
1702 lines
39 KiB
C
/*
|
|
* $Id: bdmlib.c,v 1.5 2005/11/04 14:33:54 ppisa Exp $
|
|
*
|
|
* Remote debugging interface for 683xx via Background Debug Mode
|
|
* needs a driver, which controls the BDM interface.
|
|
* written by G.Magin
|
|
* (C) 1996 Technische Universitaet Muenchen, Lehrstuhl fuer Prozessrechner
|
|
* (C) 1997 G. Magin
|
|
*
|
|
* Modified by Pavel Pisa pisa@cmp.felk.cvut.cz 1998
|
|
|
|
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, 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, write to
|
|
the Free Software Foundation, 59 Temple Place - Suite 330,
|
|
Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
/*
|
|
* NOTE:
|
|
* This file is assumed to be runnable only on Linux/i386 because of
|
|
* HW-restrictions: the driver is currently only available on i386-Linux
|
|
* So byte-swapping and alignment is handled directly, violating the
|
|
* GNU-coding standards. However, the "dirty spots" are restricted in this
|
|
* file. The accompanying application backend file (e.g. remote-bdm.c for
|
|
* gdb) is not affected by this restriction.
|
|
*
|
|
* If anybody wants to port to e.g. Sparc, byte-sex has to be handled in
|
|
* a more general way.
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
#include <ctype.h>
|
|
#include <sys/types.h>
|
|
#include <sys/ioctl.h>
|
|
#include <ansidecl.h>
|
|
|
|
/* #define SUPPORT_RAMINIT 0 */ /* force ram_init to be loaded */
|
|
#define RAMINIT_FILENAME "ram_init"
|
|
#define RESETINIT_FILENAME "cpu32init"
|
|
#define END_MACRO 0
|
|
#define BEGIN_MACRO 1
|
|
#define NO_SUFFIX_MACRO 2
|
|
#define BDMLIB_REQUIRED_DRIVER_VERSION 2
|
|
/*
|
|
* version 1 (cannot be accessed by ioctl): release 3/95
|
|
* version 2 (includes SENSE ioctl + ICD): release 7/96
|
|
*/
|
|
|
|
#ifdef BDMLIB_FORGDB
|
|
#include "defs.h"
|
|
#endif
|
|
|
|
#ifndef PROTO
|
|
/* this is missing in current ansidecl.h - remove it later gm */
|
|
#if defined (__STDC__) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4))
|
|
|
|
#define PROTO(type, name, arglist) type name arglist
|
|
#define PARAMS(paramlist) paramlist
|
|
#define ANSI_PROTOTYPES 1
|
|
|
|
#else /* Not ANSI C. */
|
|
|
|
#define PROTO(type, name, arglist) type name ()
|
|
#define PARAMS(paramlist) ()
|
|
|
|
#endif /* ANSI C. */
|
|
#endif
|
|
|
|
#include <bfd.h>
|
|
#include "bdmlib.h"
|
|
#include "bdm.h"
|
|
|
|
|
|
static int bdm_fd;
|
|
|
|
/* default delay for interface */
|
|
#define BDM_DEFAULT_DELAY 75
|
|
static int bdm_delay=-1;
|
|
|
|
#define BDM_DODPRINTF (1<<0)
|
|
#define BDM_GOTEXCEPTION (1<<1)
|
|
#define BDM_DEBUG_NAME "bdm-dbg.log"
|
|
static int bdm_flags = 0;
|
|
static int mbar_used = 0;
|
|
static u_long mbar_default_val = 0;
|
|
extern char hashmark;
|
|
extern int bdm_autoreset;
|
|
extern int bdm_ttcu;
|
|
|
|
|
|
static void dbprintf(const char *format, ...);
|
|
|
|
#if !defined BDMLIB_FORGDB
|
|
/*
|
|
* this is borrowed from gdb utils.c
|
|
*/
|
|
static void
|
|
error(const char *format, ...)
|
|
{
|
|
va_list args;
|
|
|
|
va_start(args, format);
|
|
vfprintf(stderr, format, args);
|
|
fprintf(stderr, "\n");
|
|
va_end(args);
|
|
}
|
|
|
|
static void
|
|
fprintf_filtered(FILE *fp, const char *format, ...)
|
|
{
|
|
va_list args;
|
|
|
|
va_start(args, format);
|
|
vfprintf(fp, format, args);
|
|
fprintf(fp, "\n");
|
|
va_end(args);
|
|
}
|
|
|
|
#define printf_filtered printf
|
|
#define xmalloc malloc
|
|
#define gdb_stderr stderr
|
|
#endif
|
|
|
|
void
|
|
bdmlib_setdebug(int switch_on)
|
|
{
|
|
if (switch_on)
|
|
bdm_flags |= BDM_DODPRINTF;
|
|
else
|
|
bdm_flags &= ~BDM_DODPRINTF;
|
|
dbprintf("Setting Debug to %d\n", switch_on);
|
|
}
|
|
|
|
int
|
|
bdmlib_querydebug(void)
|
|
{
|
|
return (bdm_flags & BDM_DODPRINTF);
|
|
}
|
|
|
|
/* startofcleanup */
|
|
int
|
|
bdmlib_isopen(void)
|
|
{
|
|
return (bdm_fd != 0);
|
|
}
|
|
|
|
/* filter to put out bdm specific status messages */
|
|
char *
|
|
bdmlib_getstatus_str(bdmstatus status)
|
|
{
|
|
int st;
|
|
static char put_buffer[128];
|
|
|
|
*put_buffer = '\0';
|
|
st = (int) status;
|
|
if (st < 0) {
|
|
return bdmlib_geterror_str(status);
|
|
}
|
|
if (status & BDM_TARGETNC) {
|
|
strcat(put_buffer, "NotConnected ");
|
|
return put_buffer;
|
|
}
|
|
strcat(put_buffer, "Connected ");
|
|
if (status & BDM_TARGETPOWER) {
|
|
strcat(put_buffer, "PowerFail ");
|
|
return put_buffer;
|
|
}
|
|
strcat(put_buffer, "PowerOK ");
|
|
if (status & BDM_TARGETSTOPPED)
|
|
strcat(put_buffer, "Frozen ");
|
|
else
|
|
strcat(put_buffer, "Running ");
|
|
if (status & BDM_TARGETRESET)
|
|
strcat(put_buffer, "Reset ");
|
|
return put_buffer;
|
|
}
|
|
|
|
static struct _err_messages {
|
|
int err_num;
|
|
char *err_msg;
|
|
}
|
|
|
|
err_messages[] = {
|
|
{ BDM_FAULT_UNKNOWN, "bdm driver recognized unknown fault" } ,
|
|
{ BDM_FAULT_POWER, "target power failed" } ,
|
|
{ BDM_FAULT_CABLE, "cable disconnected" } ,
|
|
{ BDM_FAULT_RESPONSE, "no response from target via bdm" } ,
|
|
{ BDM_FAULT_RESET, "target got a reset" } ,
|
|
{ BDM_FAULT_PORT, "wrong bdm port" } ,
|
|
{ BDM_FAULT_BERR, "bus error occured on access via bdm" } ,
|
|
{ BDM_FAULT_NVC, "bdm internal error: no valid command to bdm" } ,
|
|
{ BDM_NO_ERROR, "No error" } ,
|
|
{ BDM_ERR_NOT_OPEN, "bdm device is not open" } ,
|
|
{ BDM_ERR_ILL_IOCTL, "ioctl code does not match library ioctl type" } ,
|
|
{ BDM_ERR_WRITE_FAIL, "write to processor failed" } ,
|
|
{ BDM_ERR_READ_FAIL, "read from processor failed" } ,
|
|
{ BDM_ERR_ILL_SIZE, "illegal variable size" } ,
|
|
{ BDM_ERR_OPEN, "open error" } ,
|
|
{ BDM_ERR_LOAD, "error on loading binary file" } ,
|
|
{ BDM_ERR_MACROFILE, "error on loading macro" } ,
|
|
{ BDM_ERR_SECTION, "error on loading section" } ,
|
|
{ BDM_ERR_VERSION, "driver version conflict" } ,
|
|
};
|
|
|
|
static int err_msg_len = sizeof(err_messages) / sizeof(struct _err_messages);
|
|
|
|
/* filter to pick out bdm specific error messages */
|
|
char *
|
|
bdmlib_geterror_str(int err)
|
|
{
|
|
int i;
|
|
static char put_buffer[128];
|
|
|
|
for (i = 0; i < err_msg_len; i++) {
|
|
if (err == err_messages[i].err_num)
|
|
return err_messages[i].err_msg;
|
|
}
|
|
strncpy(put_buffer, strerror(-err), 128);
|
|
return put_buffer;
|
|
}
|
|
|
|
#define do_case(x) case x: ret = #x; break;
|
|
|
|
static char *
|
|
bdmlib_getioctlname(int ioctl)
|
|
{
|
|
char *ret;
|
|
switch (ioctl) {
|
|
do_case(BDM_INIT);
|
|
do_case(BDM_DEINIT);
|
|
do_case(BDM_RESET_CHIP);
|
|
do_case(BDM_RESTART_CHIP);
|
|
do_case(BDM_STOP_CHIP);
|
|
do_case(BDM_STEP_CHIP);
|
|
do_case(BDM_GET_STATUS);
|
|
do_case(BDM_SPEED);
|
|
do_case(BDM_RELEASE_CHIP);
|
|
do_case(BDM_DEBUG_LEVEL);
|
|
do_case(BDM_GET_VERSION);
|
|
do_case(BDM_SENSECABLE);
|
|
default:
|
|
ret = "Unknown ioctl";
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
bdmlib_setioctl(u_int code, u_int val)
|
|
{
|
|
if (bdmlib_isopen()) {
|
|
switch (code) {
|
|
case BDM_SENSECABLE:
|
|
case BDM_DEBUG_LEVEL:
|
|
break;
|
|
case BDM_SPEED:
|
|
bdm_delay = val; break;
|
|
default:
|
|
return BDM_ERR_ILL_IOCTL;
|
|
}
|
|
return ioctl(bdm_fd, code, (u_long) val);
|
|
} else {
|
|
return BDM_ERR_NOT_OPEN;
|
|
}
|
|
}
|
|
|
|
int
|
|
bdmlib_ioctl(u_int code)
|
|
{
|
|
int ret;
|
|
if (bdmlib_isopen()) {
|
|
switch (code) {
|
|
case BDM_INIT:
|
|
case BDM_RESET_CHIP:
|
|
case BDM_STOP_CHIP:
|
|
case BDM_RESTART_CHIP:
|
|
case BDM_RELEASE_CHIP:
|
|
case BDM_STEP_CHIP:
|
|
|
|
if ((ret = ioctl(bdm_fd, code, (u_long) NULL)) == -1) {
|
|
dbprintf("bdmlib_ioctl %s failed; error %d %s\n",
|
|
bdmlib_getioctlname(code), errno,
|
|
bdmlib_geterror_str(errno));
|
|
return -errno;
|
|
} else {
|
|
return BDM_NO_ERROR;
|
|
}
|
|
break;
|
|
default:
|
|
return BDM_ERR_ILL_IOCTL;
|
|
}
|
|
} else {
|
|
return BDM_ERR_NOT_OPEN;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* get status of interface
|
|
*/
|
|
bdmstatus
|
|
bdmlib_getstatus(void)
|
|
{
|
|
if (bdmlib_isopen()) {
|
|
return ioctl(bdm_fd, BDM_GET_STATUS, NULL);
|
|
} else {
|
|
return BDM_ERR_NOT_OPEN;
|
|
}
|
|
}
|
|
|
|
int
|
|
bdmlib_go(void)
|
|
{
|
|
u_short buf;
|
|
int ret;
|
|
|
|
dbprintf("bdmlib_go\n");
|
|
|
|
#if MORE_DEBUGGING
|
|
bdmlib_showpc();
|
|
#endif /* MORE_DEBUGGING */
|
|
|
|
if (bdmlib_isopen()) {
|
|
buf = BDM_GO_CMD;
|
|
ret = write(bdm_fd, &buf, 2);
|
|
if ((ret < 0) || (ret != 2)) {
|
|
dbprintf("bdm_go: write_error %d\n", errno);
|
|
return -errno;
|
|
}
|
|
} else {
|
|
return BDM_ERR_NOT_OPEN;
|
|
}
|
|
return BDM_NO_ERROR;
|
|
}
|
|
|
|
int
|
|
bdmlib_set_mbar(u_long mbar_val)
|
|
{
|
|
int ret;
|
|
bdmlib_set_sys_reg(BDM_REG_DFC, 7);
|
|
bdmlib_set_sys_reg(BDM_REG_SFC, 7);
|
|
ret = bdmlib_write_var((caddr_t)0x3ff00, BDM_SIZE_LONG, mbar_val);
|
|
if(ret >= 0){
|
|
mbar_used = 1;
|
|
mbar_default_val = mbar_val;
|
|
}
|
|
bdmlib_set_sys_reg(BDM_REG_DFC, 5);
|
|
bdmlib_set_sys_reg(BDM_REG_SFC, 5);
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
bdmlib_reset(void)
|
|
{
|
|
#if SUPPORT_RAMINIT
|
|
u_long dummy;
|
|
#endif
|
|
int ret;
|
|
|
|
dbprintf("bdmlib_reset ttcu %d\n", bdm_ttcu);
|
|
if ((ret = bdmlib_ioctl(BDM_RESTART_CHIP))) {
|
|
return ret;
|
|
}
|
|
|
|
#if MORE_DEBUGGING
|
|
printf("bdmlib_reset: RESTART_CHIP replies %d %s\n",
|
|
ret, bdmlib_geterror_str(ret));
|
|
printf("status: %s\n", bdmlib_getstatus_str(bdmlib_getstatus()));
|
|
#endif /* MORE_DEBUGGING */
|
|
|
|
/*
|
|
* it cannot break anything to set right SFC and DFC
|
|
* adress space for memory accesses
|
|
*/
|
|
|
|
bdmlib_set_sys_reg(BDM_REG_DFC, 5);
|
|
bdmlib_set_sys_reg(BDM_REG_SFC, 5);
|
|
|
|
/*
|
|
* The 68360 targets requires setup of MBAR to enable access
|
|
* to integrated modules and system configuration registers
|
|
*/
|
|
|
|
if(mbar_used) {
|
|
bdmlib_set_mbar(mbar_default_val);
|
|
}
|
|
|
|
/*
|
|
* in case we have a monitor in place, we might want to let him do
|
|
* the basic setup, let it come to the prompt...
|
|
*/
|
|
if (bdm_ttcu) {
|
|
if ((ret = bdmlib_go())) /* let the monitor come up.... */
|
|
return ret;
|
|
usleep(bdm_ttcu);
|
|
ret = bdmlib_ioctl(BDM_STOP_CHIP);
|
|
}
|
|
|
|
#if SUPPORT_RAMINIT
|
|
if ((ret = bdmlib_do_load_binary(RAMINIT_FILENAME, &dummy)) < 0) {
|
|
fprintf_filtered(gdb_stderr, "Warning: %s for file `%s'\n",
|
|
bdmlib_geterror_str(ret),
|
|
RAMINIT_FILENAME);
|
|
}
|
|
#endif /* SUPPORT_RAMINIT */
|
|
|
|
bdmlib_do_load_macro(RESETINIT_FILENAME, NO_SUFFIX_MACRO);
|
|
fprintf(stdout, "\r"); fflush(stdout);
|
|
return ret;
|
|
}
|
|
|
|
#define swaps(x) \
|
|
((u_short)((((u_short)(x) & 0x00ff) << 8) | \
|
|
(((u_short)(x) & 0xff00) >> 8)))
|
|
|
|
#define swapl(x) \
|
|
((u_int)((((u_int)(x) & 0x000000ffU) << 24) | \
|
|
(((u_int)(x) & 0x0000ff00U) << 8) | \
|
|
(((u_int)(x) & 0x00ff0000U) >> 8) | \
|
|
(((u_int)(x) & 0xff000000U) >> 24)))
|
|
|
|
static u_short *
|
|
bdmlib_conv_short_to_buf(u_short * buf, u_short val, int endianness)
|
|
{
|
|
if (endianness) {
|
|
*buf++ = swaps(val);
|
|
} else {
|
|
*buf++ = val;
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
/* conv long in host format (little endian) to buf (target format = big e) */
|
|
static u_short *
|
|
bdmlib_conv_long_to_buf(u_short * buf, u_long val, int endianness)
|
|
{
|
|
if (endianness) {
|
|
*buf++ = swaps(val & 0xffff);
|
|
*buf++ = swaps(val >> 16);
|
|
} else {
|
|
*buf++ = val >> 16;
|
|
*buf++ = val & 0xffff;
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
/* buf representation to a single short */
|
|
static u_short *
|
|
bdmlib_conv_buf_to_short(u_short * buf, u_short * val, int endianness)
|
|
{
|
|
if (endianness) {
|
|
*val = *buf++;
|
|
} else {
|
|
*val = swaps(*buf);
|
|
buf++;
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
/* buf representation to a single long */
|
|
static u_short *
|
|
bdmlib_conv_buf_to_long(u_short * buf, u_long * val, int endianness)
|
|
{
|
|
if (endianness) {
|
|
*val = (buf[0] << 16) | buf[1];
|
|
} else {
|
|
*val = (swaps(buf[1]) << 16) | swaps(buf[0]);
|
|
}
|
|
buf += 2;
|
|
return buf;
|
|
}
|
|
|
|
/*
|
|
* put a char stream of 4 bytes into a long;
|
|
* endianness=0: interprete char as little end
|
|
* else interprete char as big endian
|
|
*/
|
|
static u_char *
|
|
bdmlib_conv_char_to_long(u_char * buf, u_long * val, int endianness)
|
|
{
|
|
int i;
|
|
union {
|
|
u_long l;
|
|
u_char c[4];
|
|
} u;
|
|
|
|
if (endianness) {
|
|
for (i = 3; i >= 0; i--)
|
|
u.c[i] = *buf++;
|
|
} else {
|
|
for (i = 0; i < 4; i++)
|
|
u.c[i] = *buf++;
|
|
}
|
|
*val = u.l;
|
|
return buf;
|
|
}
|
|
|
|
/* put a char stream of 2 bytes into a short */
|
|
static u_char *
|
|
bdmlib_conv_char_to_short(u_char * buf, u_short * val, int endianness)
|
|
{
|
|
int i;
|
|
union {
|
|
u_short s;
|
|
u_char c[2];
|
|
} u;
|
|
|
|
if (endianness) {
|
|
for (i = 1; i >= 0; i--)
|
|
u.c[i] = *buf++;
|
|
} else {
|
|
for (i = 0; i < 2; i++)
|
|
u.c[i] = *buf++;
|
|
}
|
|
*val = u.s;
|
|
return buf;
|
|
}
|
|
|
|
/* put a long to a char stream */
|
|
static u_char *
|
|
bdmlib_conv_long_to_char(u_char * buf, u_long val, int endianness)
|
|
{
|
|
int i;
|
|
union {
|
|
u_long l;
|
|
u_char c[4];
|
|
} u;
|
|
|
|
u.l = val;
|
|
if (endianness) {
|
|
for (i = 3; i >= 0; i--)
|
|
*buf++ = u.c[i];
|
|
} else {
|
|
for (i = 0; i < 4; i++)
|
|
*buf++ = u.c[i];
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
/* put a short to a char stream */
|
|
static u_char *
|
|
bdmlib_conv_short_to_char(u_char * buf, u_short val, int endianness)
|
|
{
|
|
int i;
|
|
union {
|
|
u_short s;
|
|
u_char c[2];
|
|
} u;
|
|
|
|
u.s = val;
|
|
if (endianness) {
|
|
for (i = 1; i >= 0; i--)
|
|
*buf++ = u.c[i];
|
|
} else {
|
|
for (i = 0; i < 2; i++)
|
|
*buf++ = u.c[i];
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
int
|
|
bdmlib_get_sys_reg(u_int reg, u_int * ret_val)
|
|
{
|
|
u_short send;
|
|
u_short recv[2];
|
|
int ret;
|
|
|
|
send = BDM_RSREG_CMD | (reg & 0xf);
|
|
if (!bdmlib_isopen())
|
|
return BDM_ERR_NOT_OPEN;
|
|
ret = write(bdm_fd, &send, 2);
|
|
if (ret == 2) {
|
|
ret = read(bdm_fd, recv, 4);
|
|
} else {
|
|
dbprintf("bdmlib_get_sys_reg error on send: errno %d\n", errno);
|
|
return -errno;
|
|
}
|
|
bdmlib_conv_buf_to_long(recv, (u_long *) ret_val, 0);
|
|
return (ret == 4) ? BDM_NO_ERROR : -errno;
|
|
}
|
|
|
|
int
|
|
bdmlib_set_sys_reg(u_int reg, u_int cont)
|
|
{
|
|
u_short send[3];
|
|
int ret;
|
|
|
|
if (!bdmlib_isopen())
|
|
return BDM_ERR_NOT_OPEN;
|
|
send[0] = BDM_WSREG_CMD | (reg & 0xf);
|
|
bdmlib_conv_long_to_buf(&send[1], cont, 0);
|
|
if ((ret = write(bdm_fd, send, 6)) != 6) {
|
|
dbprintf("bdmlib_set_sys_reg error: reg %#x cont %#x error %d\n",
|
|
reg, cont, errno);
|
|
return -errno;
|
|
}
|
|
return BDM_NO_ERROR;
|
|
}
|
|
|
|
int
|
|
bdmlib_get_reg(u_int reg, u_int * ret_val)
|
|
{
|
|
u_short send;
|
|
u_short recv[2];
|
|
int ret;
|
|
|
|
if (!bdmlib_isopen())
|
|
return BDM_ERR_NOT_OPEN;
|
|
send = BDM_RREG_CMD | (reg & 0xf);
|
|
ret = write(bdm_fd, &send, 2);
|
|
if (ret == 2) {
|
|
ret = read(bdm_fd, recv, 4);
|
|
} else {
|
|
dbprintf("bdmlib_get_reg: error on send ret %d\n", errno);
|
|
return -errno;
|
|
}
|
|
/* get target format, as conversion will be done in higher levels */
|
|
bdmlib_conv_buf_to_long(recv, (u_long *) ret_val, 0);
|
|
return (ret == 4) ? BDM_NO_ERROR : -errno;
|
|
}
|
|
|
|
int
|
|
bdmlib_set_reg(u_int reg, u_int cont)
|
|
{
|
|
u_short send[3];
|
|
int ret;
|
|
|
|
if (!bdmlib_isopen())
|
|
return BDM_ERR_NOT_OPEN;
|
|
send[0] = BDM_WREG_CMD | (reg & 0xf);
|
|
bdmlib_conv_long_to_buf(&send[1], cont, 0);
|
|
if ((ret = write(bdm_fd, send, 6)) != 6) {
|
|
dbprintf("bdmlib_set_reg error: reg %#x to cont %#x error %#d\n",
|
|
reg, cont, errno);
|
|
return -errno;
|
|
}
|
|
return BDM_NO_ERROR;
|
|
}
|
|
|
|
int
|
|
bdmlib_write_var(caddr_t adr, u_short size, u_int val)
|
|
{
|
|
u_short buf[6], *b_ptr = buf;
|
|
int w_buf_len, r_buf_len;
|
|
int written;
|
|
|
|
dbprintf("bdmlib_write_var: addr %#x cont %#x\n", adr, val);
|
|
if (!bdmlib_isopen())
|
|
return BDM_ERR_NOT_OPEN;
|
|
size &= 0x00c0;
|
|
*b_ptr++ = (BDM_WRITE_CMD | size);
|
|
/* no need for byte swapping, as adr is already a valid long; so use 0 */
|
|
b_ptr = bdmlib_conv_long_to_buf(b_ptr, (u_long) adr, 0);
|
|
switch (size) {
|
|
case BDM_SIZE_LONG:
|
|
b_ptr = bdmlib_conv_long_to_buf(b_ptr, val, 0);
|
|
w_buf_len = 5;
|
|
break;
|
|
case BDM_SIZE_WORD:
|
|
b_ptr = bdmlib_conv_short_to_buf(b_ptr, val, 0);
|
|
w_buf_len = 4;
|
|
break;
|
|
case BDM_SIZE_BYTE:
|
|
*b_ptr++ = (u_short) (val & 0xff);
|
|
w_buf_len = 4;
|
|
break;
|
|
default:
|
|
w_buf_len = 0;
|
|
dbprintf("error! bdmlib_write_var: unknown size %#x\n", size);
|
|
return BDM_ERR_ILL_SIZE;
|
|
}
|
|
if ((written = write(bdm_fd, buf, w_buf_len * 2)) != w_buf_len * 2) {
|
|
dbprintf("error! bdmlib_write_var: write returns %d errno %d\n",
|
|
written, errno);
|
|
written = errno;
|
|
}
|
|
if ((r_buf_len = read(bdm_fd, buf, 2)) != 2) {
|
|
dbprintf(
|
|
"bdmlib_write_var: verify read return val expected 2 is %d errno %d\n",
|
|
r_buf_len, errno);
|
|
return -errno;
|
|
}
|
|
if (written == (w_buf_len*2)) {
|
|
return BDM_NO_ERROR;
|
|
} else {
|
|
return -written;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#if 1
|
|
|
|
/* slower but reliable method for writting, main solved problem is
|
|
waiting for ready after memory access achieved by read
|
|
in bdm_write_var */
|
|
|
|
int
|
|
bdmlib_write_block(caddr_t in_adr, u_int size, u_char * bl_ptr)
|
|
{
|
|
u_short buf[8];
|
|
int fills, got_size = 0;
|
|
u_long ul;
|
|
u_short us;
|
|
u_char uc;
|
|
u_int first_acc;
|
|
|
|
dbprintf("bdmlib_write_block size %#x to adr %#x ", size, in_adr);
|
|
first_acc = 4 - ((u_long) in_adr & 0x3);
|
|
if (size < first_acc) {
|
|
switch (size) {
|
|
case 0: return 0;
|
|
case 1: first_acc = 1; break;
|
|
case 2:
|
|
case 3: first_acc = first_acc&1? 1: 2; break;
|
|
}
|
|
}
|
|
switch (first_acc) {
|
|
case 4:
|
|
bl_ptr = bdmlib_conv_char_to_long(bl_ptr, &ul, 1);
|
|
if (bdmlib_write_var(in_adr, BDM_SIZE_LONG, ul) < 0) {
|
|
return got_size;
|
|
}
|
|
got_size += 4;
|
|
break;
|
|
case 3:
|
|
uc = *bl_ptr++;
|
|
if (bdmlib_write_var(in_adr, BDM_SIZE_BYTE, uc) < 0) {
|
|
return got_size;
|
|
}
|
|
in_adr += 1;
|
|
got_size += 1;
|
|
/* fall through to 'word' */
|
|
case 2:
|
|
bl_ptr = bdmlib_conv_char_to_short(bl_ptr, &us, 1);
|
|
if (bdmlib_write_var(in_adr, BDM_SIZE_WORD, us) < 0) {
|
|
return got_size;
|
|
}
|
|
got_size += 2;
|
|
break;
|
|
case 1:
|
|
uc = *bl_ptr++;
|
|
if (bdmlib_write_var(in_adr, BDM_SIZE_BYTE, uc) < 0) {
|
|
return got_size;
|
|
}
|
|
got_size += 1;
|
|
break;
|
|
default: ;
|
|
/* cannot happen */
|
|
}
|
|
|
|
|
|
buf[0] = BDM_FILL_CMD | BDM_SIZE_LONG;
|
|
fills = (size - got_size) / 4;
|
|
while (fills--) {
|
|
bl_ptr = bdmlib_conv_char_to_long(bl_ptr, &ul, 1);
|
|
bdmlib_conv_long_to_buf(&buf[1], ul, 0);
|
|
if (write(bdm_fd, &buf[0], 6) !=6) {
|
|
return got_size;
|
|
}
|
|
if (read(bdm_fd, &buf[1], 2) != 2) {
|
|
return got_size;
|
|
}
|
|
got_size += 4;
|
|
}
|
|
|
|
if (size - got_size >= 2) {
|
|
buf[0] = (BDM_FILL_CMD | BDM_SIZE_WORD);
|
|
bl_ptr = bdmlib_conv_char_to_short(bl_ptr, &us, 1);
|
|
bdmlib_conv_short_to_buf(&buf[1], us, 0);
|
|
if(write(bdm_fd, &buf[0], 4)!=4) return got_size;
|
|
if (read(bdm_fd, &buf[0], 2) != 2) return got_size;
|
|
got_size += 2;
|
|
}
|
|
if (size - got_size) {
|
|
buf[0] = (BDM_FILL_CMD | BDM_SIZE_BYTE);
|
|
buf[1] = *bl_ptr++;
|
|
if(write(bdm_fd, &buf[0], 4)!=4) return got_size;
|
|
if (read(bdm_fd, &buf[0], 2) != 2) return got_size;
|
|
got_size += 1;
|
|
}
|
|
if (size - got_size) { /* cannot happen */
|
|
error("internal error: bdmlib_write_block - cannot happen");
|
|
}
|
|
|
|
return got_size;
|
|
}
|
|
|
|
#else
|
|
|
|
int
|
|
bdmlib_write_block(caddr_t in_adr, u_int size, u_char * block)
|
|
{
|
|
u_short *buf, *buf_ptr;
|
|
int buf_len = 0; /* valid len of buf to writecmd in shorts */
|
|
u_char *bl_ptr;
|
|
u_int adr;
|
|
int fills, put_size;
|
|
u_long ul;
|
|
u_short us;
|
|
u_int first_acc;
|
|
|
|
dbprintf("bdmlib_write_block size %#x to adr %#x\n", size, in_adr);
|
|
if (!bdmlib_isopen())
|
|
return BDM_ERR_NOT_OPEN;
|
|
first_acc = 4 - ((u_long) in_adr & 0x3);
|
|
if (size < first_acc) {
|
|
switch (size) {
|
|
case 0: return 0;
|
|
case 1: first_acc = 1; break;
|
|
case 2:
|
|
case 3: first_acc = first_acc&1? 1: 2; break;
|
|
}
|
|
}
|
|
|
|
put_size = size;
|
|
adr = (u_int) in_adr;
|
|
bl_ptr = block;
|
|
buf_ptr = buf = xmalloc((size / 4 + 5) * 6);
|
|
|
|
/*
|
|
* per 4 bytes 3 shorts for fill-long-cmd
|
|
* + 3 short for initial write-long-cmd + addr
|
|
* = 1 * 3 shorts
|
|
* + worst case both a write-byte and write-short on begin & end
|
|
* = 4 * 3 shorts
|
|
*/
|
|
|
|
switch (first_acc) {
|
|
case 4:
|
|
*buf_ptr++ = (BDM_WRITE_CMD | BDM_SIZE_LONG);
|
|
*buf_ptr++ = (adr & 0xffff0000) >> 16; /* h-Address */
|
|
*buf_ptr++ = (adr & 0x0000ffff); /* l-Address */
|
|
bl_ptr = bdmlib_conv_char_to_long(bl_ptr, &ul, 1);
|
|
buf_ptr = bdmlib_conv_long_to_buf(buf_ptr, ul, 0);
|
|
adr += 4;
|
|
size -= 4;
|
|
buf_len = 5;
|
|
break;
|
|
case 3:
|
|
*buf_ptr++ = (BDM_WRITE_CMD | BDM_SIZE_BYTE);
|
|
*buf_ptr++ = (adr & 0xffff0000) >> 16; /* h-Address */
|
|
*buf_ptr++ = (adr & 0x0000ffff); /* l-Address */
|
|
*buf_ptr++ = *bl_ptr++;
|
|
adr += 1;
|
|
size -= 1;
|
|
buf_len = 4;
|
|
/* fall through to 'word' */
|
|
case 2:
|
|
*buf_ptr++ = (BDM_WRITE_CMD | BDM_SIZE_WORD);
|
|
*buf_ptr++ = (adr & 0xffff0000) >> 16; /* h-Address */
|
|
*buf_ptr++ = (adr & 0x0000ffff); /* l-Address */
|
|
bl_ptr = bdmlib_conv_char_to_short(bl_ptr, &us, 1);
|
|
buf_ptr = bdmlib_conv_short_to_buf(buf_ptr, us, 0);
|
|
adr += 2;
|
|
size -= 2;
|
|
buf_len += 4;
|
|
break;
|
|
case 1:
|
|
*buf_ptr++ = (BDM_WRITE_CMD | BDM_SIZE_BYTE);
|
|
*buf_ptr++ = (adr & 0xffff0000) >> 16; /* h-Address */
|
|
*buf_ptr++ = (adr & 0x0000ffff); /* l-Address */
|
|
*buf_ptr++ = *bl_ptr++;
|
|
adr += 1;
|
|
size -= 1;
|
|
buf_len = 4;
|
|
break;
|
|
default:
|
|
/* cannot happen */
|
|
}
|
|
fills = size / 4;
|
|
size -= fills * 4;
|
|
buf_len += (fills * 3);
|
|
while (fills--) {
|
|
*buf_ptr++ = (BDM_FILL_CMD | BDM_SIZE_LONG);
|
|
bl_ptr = bdmlib_conv_char_to_long(bl_ptr, &ul, 1);
|
|
buf_ptr = bdmlib_conv_long_to_buf(buf_ptr, ul, 0);
|
|
}
|
|
|
|
if(size>=2){
|
|
*buf_ptr++ = (BDM_FILL_CMD | BDM_SIZE_WORD);
|
|
bl_ptr = bdmlib_conv_char_to_short(bl_ptr, &us, 1);
|
|
buf_ptr = bdmlib_conv_short_to_buf(buf_ptr, us, 0);
|
|
buf_len += 2;
|
|
size -= 2;
|
|
}
|
|
if(size>=1){
|
|
*buf_ptr++ = (BDM_FILL_CMD | BDM_SIZE_BYTE);
|
|
*buf_ptr++ = *bl_ptr;
|
|
buf_len += 2;
|
|
size--;
|
|
}
|
|
if(size){
|
|
error("internal error: bdmlib_write_block: size=%d!=0",size);
|
|
}
|
|
|
|
/* now we have a whole buf we can send in one chunk to 'write' */
|
|
|
|
buf_len *= 2; /* now buflen in bytes */
|
|
if ((size = write(bdm_fd, buf, buf_len)) != buf_len) {
|
|
dbprintf("error! bdmlib_write_block: write %d returns %d errno %d %s\n",
|
|
buf_len, size, errno, bdmlib_geterror_str(-errno));
|
|
put_size = 0;
|
|
}
|
|
/*
|
|
* FIXME: needs more persistence on trying to write; analyze reason
|
|
* for not writing, and if possible, try again with rest of the buf
|
|
* give up on detected bus-err
|
|
*/
|
|
|
|
free(buf);
|
|
return put_size;
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
/* return format in *val is target byte ordering */
|
|
int
|
|
bdmlib_read_var(caddr_t adr, u_short size, void *val)
|
|
{
|
|
u_short buf[6], *b_ptr = buf;
|
|
int count;
|
|
|
|
/* u_char *cptr; u_short *sptr; u_long *lptr; */
|
|
|
|
dbprintf("bdmlib_read_var size %#x from adr %#x ", size, adr);
|
|
if (!bdmlib_isopen())
|
|
return BDM_ERR_NOT_OPEN;
|
|
size &= 0x00c0;
|
|
*b_ptr++ = (BDM_READ_CMD | size);
|
|
/* no need for byte swapping, as adr is already a valid long; so use 0 */
|
|
b_ptr = bdmlib_conv_long_to_buf(b_ptr, (u_long) adr, 0);
|
|
if ((count = write(bdm_fd, buf, 6)) != 6) {
|
|
dbprintf("bdmlib_read_var error: write returns %d\n", count);
|
|
return BDM_ERR_WRITE_FAIL;
|
|
}
|
|
switch (size) {
|
|
case BDM_SIZE_LONG:
|
|
if ((count = read(bdm_fd, buf, 4)) == 4) {
|
|
*(u_long *) val = (buf[0] << 16) | buf[1];
|
|
}
|
|
break;
|
|
case BDM_SIZE_WORD:
|
|
if ((count = read(bdm_fd, buf, 2)) == 2) {
|
|
*(u_short *) val = (u_short) buf[0];
|
|
/* sptr = (u_short*) val; *sptr = (u_short) buf[0]; */
|
|
}
|
|
break;
|
|
case BDM_SIZE_BYTE:
|
|
if ((count = read(bdm_fd, buf, 2)) == 2) {
|
|
count = 1;
|
|
*(u_char *) val = (u_char) (buf[0] & 0xff);
|
|
/* cptr = (u_char*)val; *cptr = (u_char) (buf[0] & 0xff); */
|
|
}
|
|
break;
|
|
default:
|
|
dbprintf("\n\terror! bdmlib_read_var: unknown size %#x\n", size);
|
|
}
|
|
if (count < 0) {
|
|
dbprintf("\nerror %d (%s)\n", errno, bdmlib_geterror_str(errno));
|
|
return -errno;
|
|
}
|
|
/* val = (u_int*) ((u_long)val & ~3); */
|
|
dbprintf(" cont %#x\n", *(u_long *) ((long) val & ~3));
|
|
return count; /* _must_ return count */
|
|
}
|
|
|
|
int
|
|
bdmlib_read_block(caddr_t in_adr, u_int size, u_char * bl_ptr)
|
|
{
|
|
u_short buf[8];
|
|
u_short dump_cmd;
|
|
int dumps, got_size = 0;
|
|
u_long ul;
|
|
u_short us;
|
|
u_char uc;
|
|
u_int first_acc;
|
|
|
|
dbprintf("bdmlib_read_block size %#x from adr %#x ", size, in_adr);
|
|
first_acc = 4 - ((u_long) in_adr & 0x3);
|
|
if (size < first_acc) {
|
|
switch (size) {
|
|
case 0: return 0;
|
|
case 1: first_acc = 1; break;
|
|
case 2:
|
|
case 3: first_acc = first_acc&1? 1: 2; break;
|
|
}
|
|
}
|
|
switch (first_acc) {
|
|
case 4:
|
|
if (bdmlib_read_var(in_adr, BDM_SIZE_LONG, &ul) != 4) {
|
|
return got_size;
|
|
}
|
|
bl_ptr = bdmlib_conv_long_to_char(bl_ptr, ul, 1);
|
|
got_size += 4;
|
|
break;
|
|
case 3:
|
|
if (bdmlib_read_var(in_adr, BDM_SIZE_BYTE, &uc) != 1) {
|
|
return got_size;
|
|
}
|
|
*bl_ptr++ = uc;
|
|
got_size += 1;
|
|
in_adr += 1;
|
|
/* fall through to 'word' */
|
|
case 2:
|
|
if (bdmlib_read_var(in_adr, BDM_SIZE_WORD, &us) != 2) {
|
|
return got_size;
|
|
}
|
|
bl_ptr = bdmlib_conv_short_to_char(bl_ptr, us, 1);
|
|
got_size += 2;
|
|
break;
|
|
case 1:
|
|
if (bdmlib_read_var(in_adr, BDM_SIZE_BYTE, &uc) != 1) {
|
|
return got_size;
|
|
}
|
|
*bl_ptr++ = uc;
|
|
got_size += 1;
|
|
break;
|
|
default: ;
|
|
/* cannot happen */
|
|
}
|
|
|
|
|
|
dump_cmd = BDM_DUMP_CMD | BDM_SIZE_LONG;
|
|
dumps = (size - got_size) / 4;
|
|
while (dumps--) {
|
|
write(bdm_fd, &dump_cmd, 2);
|
|
if (read(bdm_fd, &buf, 4) != 4) {
|
|
return got_size;
|
|
}
|
|
bdmlib_conv_buf_to_long(buf, &ul, 1);
|
|
bl_ptr = bdmlib_conv_long_to_char(bl_ptr, ul, 1);
|
|
got_size += 4;
|
|
}
|
|
|
|
if (size - got_size >= 2) {
|
|
dump_cmd = BDM_DUMP_CMD | BDM_SIZE_WORD;
|
|
write(bdm_fd, &dump_cmd, 2);
|
|
if (read(bdm_fd, &buf, 2) != 2) {
|
|
return got_size;
|
|
}
|
|
bdmlib_conv_buf_to_short(buf, &us, 1);
|
|
bl_ptr = bdmlib_conv_short_to_char(bl_ptr, us, 1);
|
|
got_size += 2;
|
|
}
|
|
if (size - got_size) {
|
|
dump_cmd = BDM_DUMP_CMD | BDM_SIZE_BYTE;
|
|
write(bdm_fd, &dump_cmd, 2);
|
|
if (read(bdm_fd, &buf, 2) != 2) {
|
|
return got_size;
|
|
}
|
|
*bl_ptr++ = *buf & 0xff;
|
|
got_size += 1;
|
|
}
|
|
if (size - got_size) { /* cannot happen */
|
|
error("internal error: bdmlib_read_block - cannot happen");
|
|
}
|
|
|
|
return got_size;
|
|
}
|
|
|
|
void
|
|
bdmlib_propeller(u_long addr, FILE * fp)
|
|
{
|
|
static char *str = "\\|/-";
|
|
static int index;
|
|
|
|
if (!hashmark) return;
|
|
fprintf(fp, "%c 0x%08lx\b\b\b\b\b\b\b\b\b\b\b\b", str[index++], addr);
|
|
fflush(fp);
|
|
index %= 4;
|
|
}
|
|
|
|
/*
|
|
* Open a connection the target via bdm
|
|
* name is the devicename of bdm and the filename to be used
|
|
* used for communication.
|
|
*/
|
|
int
|
|
bdmlib_open(char *name)
|
|
{
|
|
int ret;
|
|
int version;
|
|
|
|
if (bdmlib_isopen()) {
|
|
dbprintf("bdmlib_open: tried to open twice\n");
|
|
return BDM_ERR_OPEN;
|
|
}
|
|
if ((bdm_fd = open(name, O_RDWR)) < 0) {
|
|
dbprintf(
|
|
"bdmlib_open: Warning trouble on opening %s: reply %d errno %d\n",
|
|
name, bdm_fd, errno);
|
|
fprintf(stderr, "Warning: trouble on opening %s: %s\n", name,
|
|
bdmlib_geterror_str(-errno));
|
|
bdm_fd = 0; /* mark unused */
|
|
return BDM_FAULT_PORT;
|
|
}
|
|
bdmlib_ioctl(BDM_INIT);
|
|
if (bdm_delay>=0) {
|
|
/* delay has been set before */
|
|
bdmlib_setioctl(BDM_SPEED, bdm_delay);
|
|
} else {
|
|
bdmlib_setioctl(BDM_SPEED, BDM_DEFAULT_DELAY);
|
|
}
|
|
|
|
if (((ret = ioctl(bdm_fd, BDM_GET_VERSION, (u_long) &version)) < 0) ||
|
|
(version < BDMLIB_REQUIRED_DRIVER_VERSION)) {
|
|
if (ret < 0) version = 1;
|
|
fprintf(stderr, "Error:\tBDM device driver version conflict.\n");
|
|
fprintf(stderr,
|
|
"\tyou need at least version %d, currently installed is version %d.\n",
|
|
BDMLIB_REQUIRED_DRIVER_VERSION, version);
|
|
fprintf(stderr, "\tAborting operation\n");
|
|
close(bdm_fd);
|
|
return BDM_ERR_VERSION;
|
|
}
|
|
return BDM_NO_ERROR;
|
|
}
|
|
|
|
int
|
|
bdmlib_close(quitting)
|
|
int quitting;
|
|
{
|
|
dbprintf("bdmlib_close: quitting %d\n", quitting);
|
|
|
|
if (quitting) {
|
|
bdmlib_reset();
|
|
bdmlib_ioctl(BDM_RELEASE_CHIP);
|
|
}
|
|
close(bdm_fd);
|
|
bdm_fd = 0;
|
|
return BDM_NO_ERROR;
|
|
}
|
|
|
|
#define swap_l(x) (x>>24) | ((x>>8)&0xff00) | ((x<<8)&0xff0000) | ((x&0xff)<<24)
|
|
|
|
void
|
|
bdmlib_showpc(void)
|
|
{
|
|
u_int sr, usp, ssp, vbr;
|
|
u_int pcc, rpc, a7;
|
|
|
|
bdmlib_get_sys_reg(BDM_REG_SR, &sr);
|
|
bdmlib_get_sys_reg(BDM_REG_USP, &usp);
|
|
bdmlib_get_reg(BDM_REG_A7, &a7);
|
|
bdmlib_get_sys_reg(BDM_REG_SSP, &ssp);
|
|
printf(" SR: %9x USP: %9x A7: %9x SSP: %9x\n",
|
|
swap_l(sr), swap_l(usp), swap_l(a7), swap_l(ssp));
|
|
|
|
bdmlib_get_sys_reg(BDM_REG_PCC, &pcc);
|
|
bdmlib_get_sys_reg(BDM_REG_RPC, &rpc);
|
|
bdmlib_get_sys_reg(BDM_REG_VBR, &vbr);
|
|
printf("PCC: %9x RPC: %9x VBR: %9x\n",
|
|
swap_l(pcc), swap_l(rpc), swap_l(vbr));
|
|
}
|
|
|
|
#define LINE_LEN 256
|
|
static char *
|
|
get_line(FILE * f, int *line_nr)
|
|
{
|
|
static char line_buf[LINE_LEN];
|
|
|
|
while (!feof(f)) {
|
|
fgets(line_buf, LINE_LEN, f);
|
|
(*line_nr)++;
|
|
if (line_buf[0] == '#')
|
|
continue;
|
|
if (line_buf[0] == '\n')
|
|
continue;
|
|
if (line_buf[0] == '\0')
|
|
continue;
|
|
return line_buf;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* retval is just if we found the macro file, no errors!
|
|
*/
|
|
int
|
|
bdmlib_do_load_macro(char *file_name, int which_suffix)
|
|
{
|
|
char m_name[256];
|
|
FILE *m_file;
|
|
char *lptr;
|
|
char cmd;
|
|
int line_nr, ret, size;
|
|
bfd_vma addr1, addr2;
|
|
short size_tag;
|
|
u_char *buf;
|
|
int errorcount = 0;
|
|
char * begin_suffix = ".bdmmb", *end_suffix = ".bdmme", *no_suffix = "";
|
|
char * suffix;
|
|
|
|
|
|
dbprintf("bdmlib_do_load_macro %s suffix %d\n", file_name, which_suffix);
|
|
strcpy(m_name, file_name);
|
|
if ((lptr = rindex(m_name, '.')) != 0) {
|
|
*lptr = '\0';
|
|
}
|
|
switch (which_suffix) {
|
|
case BEGIN_MACRO: suffix = begin_suffix; break;
|
|
case END_MACRO: suffix = end_suffix; break;
|
|
case NO_SUFFIX_MACRO: suffix = no_suffix; break;
|
|
default: suffix = no_suffix;
|
|
}
|
|
strcat(m_name, suffix);
|
|
if ((m_file = fopen(m_name, "r")) == NULL) {
|
|
dbprintf("\tno macro file found\n");
|
|
return BDM_ERR_MACROFILE; /* no macro file available, quit silently */
|
|
}
|
|
if (!(bdmlib_getstatus() & BDM_TARGETSTOPPED)) {
|
|
dbprintf("\twarning: chip needs stopping\n");
|
|
bdmlib_ioctl(BDM_STOP_CHIP);
|
|
}
|
|
line_nr = 0;
|
|
while ((lptr = get_line(m_file, &line_nr))) {
|
|
cmd = *lptr++;
|
|
addr1 = strtoul (lptr, &lptr, 0);
|
|
addr2 = strtoul (lptr, &lptr, 0);
|
|
size = strtol (lptr, &lptr, 0);
|
|
bdmlib_propeller(addr1, stdout);
|
|
switch (toupper(cmd)) {
|
|
case 'W':
|
|
dbprintf("\twrite to addr %#x cont %#x size %d\n",
|
|
addr1, addr2, size);
|
|
switch (size) {
|
|
case 1:
|
|
size_tag = BDM_SIZE_BYTE;
|
|
size = 8;
|
|
break;
|
|
case 2:
|
|
size_tag = BDM_SIZE_WORD;
|
|
size = 8;
|
|
break;
|
|
case 4:
|
|
size_tag = BDM_SIZE_LONG;
|
|
size = 10;
|
|
break;
|
|
default:
|
|
error("\
|
|
Error in processing macro %s line %d 'W' command:\n\t\
|
|
size must be either 1,2,4 bytes, '%d' is not allowed",
|
|
m_name, line_nr, size);
|
|
continue;
|
|
}
|
|
if ((ret = bdmlib_write_var((caddr_t) addr1, size_tag, (u_int) addr2)) < 0) {
|
|
errorcount++;
|
|
dbprintf("\
|
|
Error in processing macro %s line %d 'W' command:\n\t\
|
|
bdm_write size mismatch: send %d returned %d errno %d",
|
|
m_name, line_nr, size, ret, errno);
|
|
}
|
|
break;
|
|
case 'C':
|
|
dbprintf("\tcopy from %#x to %#x size %d\n",
|
|
addr1, addr2, size);
|
|
buf = xmalloc(size);
|
|
if ((ret = bdmlib_read_block((caddr_t) addr1, size, buf)) != size) {
|
|
errorcount++;
|
|
error("\
|
|
Error in processing macro %s line %d 'C' command:\n\t\
|
|
bdm_copy size mismatch on read from %#x: wanted %d got %d",
|
|
m_name, line_nr, addr1, size, ret);
|
|
} else {
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < size; i++) {
|
|
if (!(i % 16))
|
|
printf("\n0x%08X: ", (unsigned int) addr1 + i);
|
|
printf("0x%02X ", buf[i]);
|
|
}
|
|
printf("\n");
|
|
}
|
|
if ((ret = bdmlib_write_block((caddr_t) addr2, size, buf)) != size) {
|
|
errorcount++;
|
|
error("\
|
|
Error in processing macro %s line %d 'C' command:\n\t\
|
|
bdm_copy size mismatch on write to %#x: wanted %d got %d",
|
|
m_name, line_nr, addr2, size, ret);
|
|
}
|
|
}
|
|
free(buf);
|
|
break;
|
|
case 'Z':
|
|
dbprintf("\tzero from %#x with %#x size %#x\n",
|
|
addr1, addr2 & 0xff, size);
|
|
buf = xmalloc(size);
|
|
memset(buf, addr2, size);
|
|
if ((ret = bdmlib_write_block((caddr_t) addr1, size, buf)) != size) {
|
|
errorcount++;
|
|
error("\
|
|
Error in processing macro %s line %d 'Z' command:\n\t\
|
|
bdm_set size mismatch on write to %#x: wanted %d got %d",
|
|
m_name, line_nr, addr1, size, ret);
|
|
|
|
}
|
|
free(buf);
|
|
break;
|
|
case 'M':
|
|
dbprintf("\tMBAR setup to %#x\n", addr1);
|
|
if ((ret = bdmlib_set_mbar((u_long) addr1))) {
|
|
errorcount++;
|
|
error("\
|
|
Error in processing macro %s line %d 'M' command:\n\t\
|
|
MBAR set returned %d",
|
|
m_name, line_nr, ret);
|
|
|
|
}
|
|
break;
|
|
#if DEBUGGING_MACROS
|
|
case 'T':
|
|
{
|
|
int i;
|
|
|
|
buf = xmalloc(size);
|
|
for (i = 0; i < size; i++)
|
|
buf[i] = i;
|
|
bdmlib_write_block(addr1, size, buf);
|
|
free(buf);
|
|
}
|
|
break;
|
|
#endif /* DEBUGGING_MACROS */
|
|
default:
|
|
dbprintf("\tcmd %c unknown\n", cmd);
|
|
}
|
|
}
|
|
if (hashmark) {
|
|
printf(" \b\b\b\b\b\b\b\b\b\b\b\b");
|
|
fflush(stdout);
|
|
}
|
|
if(m_file) fclose(m_file);
|
|
dbprintf("\tfinished macro. errorcount %d\n", errorcount);
|
|
return 0;
|
|
/*
|
|
* dont give back errorcount, errors will show up on binary
|
|
* download also.
|
|
*/
|
|
}
|
|
|
|
bdmlib_bfilt_t * bdmlib_bfilt=NULL;
|
|
|
|
int
|
|
bdmlib_wrb_filt(bdmlib_bfilt_t * filt, caddr_t in_adr,
|
|
u_int size, u_char * bl_ptr)
|
|
{
|
|
int ret, part_ret;
|
|
u_int part_size;
|
|
if (!size) return 0;
|
|
|
|
while (filt) {
|
|
if((in_adr<=filt->end_adr)&&
|
|
(in_adr+size-1>=filt->begin_adr)) {
|
|
ret = 0;
|
|
if(in_adr<filt->begin_adr) {
|
|
part_size=filt->begin_adr-in_adr;
|
|
part_ret=bdmlib_wrb_filt(filt->next,in_adr,part_size,bl_ptr);
|
|
ret+=part_ret;
|
|
if(part_ret!=part_size) return ret;
|
|
in_adr+=part_size;
|
|
bl_ptr+=part_size;
|
|
size-=part_size;
|
|
}
|
|
part_size=filt->end_adr-in_adr+1;
|
|
if (part_size>=size) {
|
|
part_size=size;
|
|
size=0;
|
|
} else size-=part_size;
|
|
part_ret=filt->wrb_filt(filt,in_adr,part_size,bl_ptr);
|
|
ret+=part_ret;
|
|
if(part_ret!=part_size) {
|
|
dbprintf("write error on filt write, address 0x%lx size %d acknowledged %d errno %d\n",
|
|
(long)in_adr, part_size, part_ret, errno);
|
|
return ret;
|
|
}
|
|
in_adr+=part_size;
|
|
bl_ptr+=part_size;
|
|
if(!size) return ret;
|
|
ret+=bdmlib_wrb_filt(filt->next,in_adr,size,bl_ptr);
|
|
return ret;
|
|
}
|
|
filt=filt->next;
|
|
}
|
|
/* regular memory block write */
|
|
if ((ret = bdmlib_write_block(in_adr, size, bl_ptr)) != size) {
|
|
dbprintf("write error on block write, written %d acknowledged %d errno %d\n",
|
|
size, ret, errno);
|
|
return ret;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int bdmlib_load_use_lma=0;
|
|
static int load_section_error;
|
|
|
|
static void
|
|
bdmlib_load_section(bfd * abfd, sec_ptr sec, PTR ignore)
|
|
{
|
|
u_long addr;
|
|
u_long dfc;
|
|
u_long load_bytes;
|
|
file_ptr offset;
|
|
int ret, cnt;
|
|
char cbuf[512];
|
|
|
|
dbprintf("bdmlib_load_section:\n\tsection %s index %d\n",
|
|
sec->name, sec->index);
|
|
dbprintf("\tflags %#x raw_size 0x%08lx cooked_size 0x%08lx\n",
|
|
sec->flags, (long)bfd_get_section_limit(abfd, sec), (long)bfd_get_section_size(sec));
|
|
dbprintf("\tvma %#x lma %#x output_offset %#x\n",
|
|
sec->vma, sec->lma, sec->output_offset);
|
|
if ((load_section_error < 0) ||
|
|
((bfd_get_section_flags(abfd, sec) & SEC_LOAD) == 0)) {
|
|
return;
|
|
}
|
|
if (bfd_get_section_flags(abfd, sec) & SEC_CODE)
|
|
dfc = 0x6; /* Supervisor program space */
|
|
else
|
|
dfc = 0x5; /* Supervisor data space */
|
|
if ((ret = bdmlib_set_sys_reg(BDM_REG_DFC, dfc)) < 0) {
|
|
load_section_error = ret;
|
|
return;
|
|
}
|
|
if(!bdmlib_load_use_lma)
|
|
addr = bfd_section_vma(abfd, sec);
|
|
else
|
|
addr = bfd_section_lma(abfd, sec);
|
|
|
|
/* there used to be bfd_get_section_size_before_reloc() */
|
|
if ((load_bytes = bfd_section_size(abfd,sec)) == 0)
|
|
return;
|
|
offset = 0;
|
|
while (load_bytes) {
|
|
if (load_bytes > sizeof(cbuf)) {
|
|
cnt = sizeof(cbuf);
|
|
} else {
|
|
cnt = load_bytes;
|
|
}
|
|
if (!bfd_get_section_contents(abfd, sec, cbuf, offset, cnt)) {
|
|
dbprintf("read error section %s\n", sec->name);
|
|
load_section_error = BDM_ERR_LOAD;
|
|
return;
|
|
}
|
|
if ((ret = bdmlib_wrb_filt(bdmlib_bfilt,(caddr_t) addr, cnt, cbuf)) != cnt) {
|
|
dbprintf("write error on block write, written %d acknowledged %d errno %d\n",
|
|
cnt, ret, errno);
|
|
load_section_error = BDM_ERR_LOAD;
|
|
return;
|
|
}
|
|
|
|
load_bytes -= cnt;
|
|
addr += cnt;
|
|
offset += cnt;
|
|
bdmlib_propeller(addr, stdout);
|
|
}
|
|
}
|
|
|
|
static int bfd_initialized;
|
|
static bfd * prepare_binary(char *file_name)
|
|
{
|
|
bfd *abfd;
|
|
|
|
if (!bfd_initialized) {
|
|
bfd_init();
|
|
bfd_initialized = 1;
|
|
}
|
|
abfd = bfd_openr(file_name, 0);
|
|
if (!abfd) {
|
|
dbprintf("Unable to open file %s\n", file_name);
|
|
return NULL;
|
|
}
|
|
if (bfd_check_format(abfd, bfd_object) == 0) {
|
|
dbprintf("File %s is not an object file\n", file_name);
|
|
bfd_close(abfd);
|
|
return NULL;
|
|
}
|
|
return abfd;
|
|
}
|
|
|
|
/*
|
|
* load a binary file, returns error codes
|
|
*/
|
|
int
|
|
bdmlib_do_load_binary(char *file_name, char *entry_name, u_long *entry_pt)
|
|
{
|
|
bfd *abfd;
|
|
int ret;
|
|
u_long entry_addr = 0;
|
|
|
|
if ((abfd = prepare_binary(file_name)) == NULL)
|
|
return BDM_ERR_OPEN;
|
|
|
|
if (entry_name)
|
|
while (isspace(*entry_name))
|
|
entry_name++;
|
|
|
|
if (entry_name && isdigit(*entry_name)) {
|
|
entry_addr = strtoul (entry_name, NULL, 0);
|
|
} else if (entry_name) {
|
|
long i, symcnt;
|
|
asymbol **symtab;
|
|
if ((i=bfd_get_symtab_upper_bound(abfd))<=0 || !(symtab=malloc(i)))
|
|
return BDM_ERR_OPEN;
|
|
if ((symcnt = bfd_canonicalize_symtab (abfd, symtab))<0)
|
|
return BDM_ERR_OPEN;
|
|
|
|
for (i=0; i<symcnt; i++) {
|
|
if (!strcmp (entry_name, symtab[i]->name)) {
|
|
entry_addr = symtab[i]->section->vma + symtab[i]->value;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
entry_addr = bfd_get_start_address(abfd);
|
|
}
|
|
if(entry_pt) *entry_pt = entry_addr;
|
|
|
|
load_section_error = BDM_NO_ERROR;
|
|
if (!(bdmlib_getstatus() & BDM_TARGETSTOPPED) &&
|
|
((ret = bdmlib_ioctl(BDM_STOP_CHIP)))) {
|
|
dbprintf("bdmlib_do_load_binary: %d %s\n",
|
|
errno, bdmlib_geterror_str(-errno));
|
|
return -errno;
|
|
}
|
|
bfd_map_over_sections(abfd, bdmlib_load_section, NULL);
|
|
if (hashmark) {
|
|
printf(" . \b\b\b\b\b\b\b\b\b\b\b\b");
|
|
fflush(stdout);
|
|
}
|
|
bfd_close(abfd);
|
|
return load_section_error;
|
|
}
|
|
|
|
int
|
|
bdmlib_do_load_binary_section(char *file_name, char *section_name)
|
|
{
|
|
bfd *abfd;
|
|
asection *sec;
|
|
int ret;
|
|
|
|
if ((abfd = prepare_binary(file_name)) == NULL)
|
|
return BDM_ERR_OPEN;
|
|
|
|
if ((sec = bfd_get_section_by_name(abfd, section_name)) == NULL)
|
|
return BDM_ERR_SECTION;
|
|
|
|
load_section_error = BDM_NO_ERROR;
|
|
if (!(bdmlib_getstatus() & BDM_TARGETSTOPPED) &&
|
|
((ret = bdmlib_ioctl(BDM_STOP_CHIP)))) {
|
|
dbprintf("bdmlib_do_load_binary: %d %s\n",
|
|
errno, bdmlib_geterror_str(-errno));
|
|
return -errno;
|
|
}
|
|
|
|
if (hashmark) {
|
|
printf(" "); fflush(stdout);
|
|
}
|
|
bdmlib_load_section(abfd, sec, NULL);
|
|
if (hashmark) {
|
|
printf("\r \r");
|
|
fflush(stdout);
|
|
}
|
|
bfd_close(abfd);
|
|
return load_section_error;
|
|
}
|
|
|
|
/*
|
|
* Load a file.
|
|
* This is supposed to be coff here, but bfd should handle other formats...
|
|
*
|
|
* use a macro for target specific manipulations, eg. setting
|
|
* chipselect, switching memory banks, etc.
|
|
*/
|
|
|
|
int
|
|
bdmlib_load(char *file, char *entry_name, u_long * entry_pt)
|
|
{
|
|
int ret = 0;
|
|
u_int sfc, dfc;
|
|
int we_have_macro_files = 0;
|
|
#if SUPPORT_RAMINIT
|
|
u_long dummy;
|
|
#endif
|
|
|
|
if (!bdmlib_isopen())
|
|
return BDM_ERR_NOT_OPEN;
|
|
dbprintf("bdmlib_load: program name %s\n", file);
|
|
|
|
if (bdm_autoreset) bdmlib_reset();
|
|
if (!(bdmlib_getstatus() & BDM_TARGETSTOPPED))
|
|
if ((ret = bdmlib_ioctl(BDM_STOP_CHIP))) {
|
|
fprintf_filtered(gdb_stderr, "%s", bdmlib_geterror_str(ret));
|
|
error("Download failed\n");
|
|
return ret; /* this is for non-gdb applications */
|
|
}
|
|
|
|
bdmlib_set_sys_reg(BDM_REG_DFC, 5);
|
|
if ((ret = bdmlib_set_sys_reg(BDM_REG_SFC, 5)) < 0) {
|
|
return ret;
|
|
}
|
|
bdmlib_get_sys_reg(BDM_REG_DFC, &dfc);
|
|
bdmlib_get_sys_reg(BDM_REG_SFC, &sfc);
|
|
dbprintf("\tDFC %x SFC %x\n", dfc, sfc);
|
|
|
|
we_have_macro_files = !bdmlib_do_load_macro(file, BEGIN_MACRO);
|
|
|
|
#if SUPPORT_RAMINIT
|
|
if ((ret = bdmlib_do_load_binary(RAMINIT_FILENAME, &dummy)) < 0) {
|
|
error("ram_init load error.\n");
|
|
}
|
|
#endif /* SUPPORT_RAMINIT */
|
|
|
|
if ((ret = bdmlib_do_load_binary(file, entry_name, entry_pt)) < 0) {
|
|
error("Download failed.");
|
|
return ret;
|
|
}
|
|
if (we_have_macro_files)
|
|
bdmlib_do_load_macro(file, END_MACRO);
|
|
return BDM_NO_ERROR;
|
|
|
|
}
|
|
|
|
static FILE *debug_fp;
|
|
|
|
static int
|
|
open_debug(void)
|
|
{
|
|
if ((debug_fp = fopen(BDM_DEBUG_NAME, "w")) == NULL) {
|
|
perror("bdm-dbprintf");
|
|
fprintf_filtered(gdb_stderr, "bdm: opening debug %s\n",
|
|
BDM_DEBUG_NAME);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* debug printf for Log-file */
|
|
void
|
|
dbprintf(const char *format, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
if (bdm_flags & BDM_DODPRINTF) {
|
|
if ((!debug_fp) && open_debug()) return;
|
|
va_start(ap, format);
|
|
vfprintf(debug_fp, format, ap); fflush(debug_fp);
|
|
va_end(ap);
|
|
} else if (debug_fp) {
|
|
fclose(debug_fp);
|
|
debug_fp = NULL;
|
|
}
|
|
}
|
|
|
|
void
|
|
bdmlib_log(const char *format, ...)
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
/*
|
|
* this would normally call dbprintf(); however it seems not possible
|
|
* to do nested varargs calls....
|
|
*/
|
|
|
|
if (bdm_flags & BDM_DODPRINTF) {
|
|
if ((!debug_fp) && open_debug()) return;
|
|
va_start(ap, format);
|
|
fprintf(debug_fp, "%s: ",
|
|
#if defined BDMLIB_FORGDB
|
|
"GDB"
|
|
#elif defined BDMLIB_FORFLT
|
|
"FLT"
|
|
#else
|
|
"???"
|
|
#endif
|
|
);
|
|
vfprintf(debug_fp, format, ap); fflush(debug_fp);
|
|
va_end(ap);
|
|
} else if (debug_fp) {
|
|
fclose(debug_fp);
|
|
debug_fp = NULL;
|
|
}
|
|
}
|