1101 lines
27 KiB
C
1101 lines
27 KiB
C
|
/* Remote debugging interface for Densan DVE-R3900 ROM monitor for
|
||
|
GDB, the GNU debugger.
|
||
|
Copyright 1997 Free Software Foundation, Inc.
|
||
|
|
||
|
This file is part of GDB.
|
||
|
|
||
|
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. */
|
||
|
|
||
|
#include "defs.h"
|
||
|
#include "gdbcore.h"
|
||
|
#include "target.h"
|
||
|
#include "monitor.h"
|
||
|
#include "serial.h"
|
||
|
#include "inferior.h"
|
||
|
#include "command.h"
|
||
|
#include "gdb_string.h"
|
||
|
#include <time.h>
|
||
|
|
||
|
/* Type of function passed to bfd_map_over_sections. */
|
||
|
|
||
|
typedef void (*section_map_func) PARAMS ((bfd * abfd, asection * sect, PTR obj));
|
||
|
|
||
|
/* Packet escape character used by Densan monitor. */
|
||
|
|
||
|
#define PESC 0xdc
|
||
|
|
||
|
/* Maximum packet size. This is actually smaller than necessary
|
||
|
just to be safe. */
|
||
|
|
||
|
#define MAXPSIZE 1024
|
||
|
|
||
|
/* External functions. */
|
||
|
|
||
|
extern void report_transfer_performance PARAMS ((unsigned long,
|
||
|
time_t, time_t));
|
||
|
|
||
|
/* Certain registers are "bitmapped", in that the monitor can only display
|
||
|
them or let the user modify them as a series of named bitfields.
|
||
|
This structure describes a field in a bitmapped register. */
|
||
|
|
||
|
struct bit_field
|
||
|
{
|
||
|
char *prefix; /* string appearing before the value */
|
||
|
char *suffix; /* string appearing after the value */
|
||
|
char *user_name; /* name used by human when entering field value */
|
||
|
int length; /* number of bits in the field */
|
||
|
int start; /* starting (least significant) bit number of field */
|
||
|
};
|
||
|
|
||
|
/* Local functions for register manipulation. */
|
||
|
|
||
|
static void r3900_supply_register PARAMS ((char *regname, int regnamelen,
|
||
|
char *val, int vallen));
|
||
|
static void fetch_bad_vaddr PARAMS ((void));
|
||
|
static unsigned long fetch_fields PARAMS ((struct bit_field * bf));
|
||
|
static void fetch_bitmapped_register PARAMS ((int regno,
|
||
|
struct bit_field * bf));
|
||
|
static void r3900_fetch_registers PARAMS ((int regno));
|
||
|
static void store_bitmapped_register PARAMS ((int regno,
|
||
|
struct bit_field * bf));
|
||
|
static void r3900_store_registers PARAMS ((int regno));
|
||
|
|
||
|
/* Local functions for fast binary loading. */
|
||
|
|
||
|
static void write_long PARAMS ((char *buf, long n));
|
||
|
static void write_long_le PARAMS ((char *buf, long n));
|
||
|
static int debug_readchar PARAMS ((int hex));
|
||
|
static void debug_write PARAMS ((unsigned char *buf, int buflen));
|
||
|
static void ignore_packet PARAMS ((void));
|
||
|
static void send_packet PARAMS ((char type, unsigned char *buf, int buflen,
|
||
|
int seq));
|
||
|
static void process_read_request PARAMS ((unsigned char *buf, int buflen));
|
||
|
static void count_section PARAMS ((bfd * abfd, asection * s,
|
||
|
unsigned int *section_count));
|
||
|
static void load_section PARAMS ((bfd * abfd, asection * s,
|
||
|
unsigned int *data_count));
|
||
|
static void r3900_load PARAMS ((char *filename, int from_tty));
|
||
|
|
||
|
/* Miscellaneous local functions. */
|
||
|
|
||
|
static void r3900_open PARAMS ((char *args, int from_tty));
|
||
|
|
||
|
|
||
|
/* Pointers to static functions in monitor.c for fetching and storing
|
||
|
registers. We can't use these function in certain cases where the Densan
|
||
|
monitor acts perversely: for registers that it displays in bit-map
|
||
|
format, and those that can't be modified at all. In those cases
|
||
|
we have to use our own functions to fetch and store their values. */
|
||
|
|
||
|
static void (*orig_monitor_fetch_registers) PARAMS ((int regno));
|
||
|
static void (*orig_monitor_store_registers) PARAMS ((int regno));
|
||
|
|
||
|
/* Pointer to static function in monitor. for loading programs.
|
||
|
We use this function for loading S-records via the serial link. */
|
||
|
|
||
|
static void (*orig_monitor_load) PARAMS ((char *file, int from_tty));
|
||
|
|
||
|
/* This flag is set if a fast ethernet download should be used. */
|
||
|
|
||
|
static int ethernet = 0;
|
||
|
|
||
|
/* This array of registers needs to match the indexes used by GDB. The
|
||
|
whole reason this exists is because the various ROM monitors use
|
||
|
different names than GDB does, and don't support all the registers
|
||
|
either. */
|
||
|
|
||
|
static char *r3900_regnames[NUM_REGS] =
|
||
|
{
|
||
|
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
|
||
|
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
|
||
|
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
|
||
|
"r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
|
||
|
|
||
|
"S", /* PS_REGNUM */
|
||
|
"l", /* LO_REGNUM */
|
||
|
"h", /* HI_REGNUM */
|
||
|
"B", /* BADVADDR_REGNUM */
|
||
|
"Pcause", /* CAUSE_REGNUM */
|
||
|
"p" /* PC_REGNUM */
|
||
|
};
|
||
|
|
||
|
|
||
|
/* Table of register names produced by monitor's register dump command. */
|
||
|
|
||
|
static struct reg_entry
|
||
|
{
|
||
|
char *name;
|
||
|
int regno;
|
||
|
}
|
||
|
reg_table[] =
|
||
|
{
|
||
|
{
|
||
|
"r0_zero", 0
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r1_at", 1
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r2_v0", 2
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r3_v1", 3
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r4_a0", 4
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r5_a1", 5
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r6_a2", 6
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r7_a3", 7
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r8_t0", 8
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r9_t1", 9
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r10_t2", 10
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r11_t3", 11
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r12_t4", 12
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r13_t5", 13
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r14_t6", 14
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r15_t7", 15
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r16_s0", 16
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r17_s1", 17
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r18_s2", 18
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r19_s3", 19
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r20_s4", 20
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r21_s5", 21
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r22_s6", 22
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r23_s7", 23
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r24_t8", 24
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r25_t9", 25
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r26_k0", 26
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r27_k1", 27
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r28_gp", 28
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r29_sp", 29
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r30_fp", 30
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"r31_ra", 31
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"HI", HI_REGNUM
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"LO", LO_REGNUM
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"PC", PC_REGNUM
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
"BadV", BADVADDR_REGNUM
|
||
|
}
|
||
|
,
|
||
|
{
|
||
|
NULL, 0
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
/* The monitor displays the cache register along with the status register,
|
||
|
as if they were a single register. So when we want to fetch the
|
||
|
status register, parse but otherwise ignore the fields of the
|
||
|
cache register that the monitor displays. Register fields that should
|
||
|
be ignored have a length of zero in the tables below. */
|
||
|
|
||
|
static struct bit_field status_fields[] =
|
||
|
{
|
||
|
/* Status register portion */
|
||
|
{"SR[<CU=", " ", "cu", 4, 28},
|
||
|
{"RE=", " ", "re", 1, 25},
|
||
|
{"BEV=", " ", "bev", 1, 22},
|
||
|
{"TS=", " ", "ts", 1, 21},
|
||
|
{"Nmi=", " ", "nmi", 1, 20},
|
||
|
{"INT=", " ", "int", 6, 10},
|
||
|
{"SW=", ">]", "sw", 2, 8},
|
||
|
{"[<KUO=", " ", "kuo", 1, 5},
|
||
|
{"IEO=", " ", "ieo", 1, 4},
|
||
|
{"KUP=", " ", "kup", 1, 3},
|
||
|
{"IEP=", " ", "iep", 1, 2},
|
||
|
{"KUC=", " ", "kuc", 1, 1},
|
||
|
{"IEC=", ">]", "iec", 1, 0},
|
||
|
|
||
|
/* Cache register portion (dummy for parsing only) */
|
||
|
{"CR[<IalO=", " ", "ialo", 0, 13},
|
||
|
{"DalO=", " ", "dalo", 0, 12},
|
||
|
{"IalP=", " ", "ialp", 0, 11},
|
||
|
{"DalP=", " ", "dalp", 0, 10},
|
||
|
{"IalC=", " ", "ialc", 0, 9},
|
||
|
{"DalC=", ">] ", "dalc", 0, 8},
|
||
|
|
||
|
{NULL, NULL, 0, 0} /* end of table marker */
|
||
|
};
|
||
|
|
||
|
|
||
|
#if 0 /* FIXME: Enable when we add support for modifying cache register. */
|
||
|
static struct bit_field cache_fields[] =
|
||
|
{
|
||
|
/* Status register portion (dummy for parsing only) */
|
||
|
{"SR[<CU=", " ", "cu", 0, 28},
|
||
|
{"RE=", " ", "re", 0, 25},
|
||
|
{"BEV=", " ", "bev", 0, 22},
|
||
|
{"TS=", " ", "ts", 0, 21},
|
||
|
{"Nmi=", " ", "nmi", 0, 20},
|
||
|
{"INT=", " ", "int", 0, 10},
|
||
|
{"SW=", ">]", "sw", 0, 8},
|
||
|
{"[<KUO=", " ", "kuo", 0, 5},
|
||
|
{"IEO=", " ", "ieo", 0, 4},
|
||
|
{"KUP=", " ", "kup", 0, 3},
|
||
|
{"IEP=", " ", "iep", 0, 2},
|
||
|
{"KUC=", " ", "kuc", 0, 1},
|
||
|
{"IEC=", ">]", "iec", 0, 0},
|
||
|
|
||
|
/* Cache register portion */
|
||
|
{"CR[<IalO=", " ", "ialo", 1, 13},
|
||
|
{"DalO=", " ", "dalo", 1, 12},
|
||
|
{"IalP=", " ", "ialp", 1, 11},
|
||
|
{"DalP=", " ", "dalp", 1, 10},
|
||
|
{"IalC=", " ", "ialc", 1, 9},
|
||
|
{"DalC=", ">] ", "dalc", 1, 8},
|
||
|
|
||
|
{NULL, NULL, NULL, 0, 0} /* end of table marker */
|
||
|
};
|
||
|
#endif
|
||
|
|
||
|
|
||
|
static struct bit_field cause_fields[] =
|
||
|
{
|
||
|
{"<BD=", " ", "bd", 1, 31},
|
||
|
{"CE=", " ", "ce", 2, 28},
|
||
|
{"IP=", " ", "ip", 6, 10},
|
||
|
{"SW=", " ", "sw", 2, 8},
|
||
|
{"EC=", ">]", "ec", 5, 2},
|
||
|
|
||
|
{NULL, NULL, NULL, 0, 0} /* end of table marker */
|
||
|
};
|
||
|
|
||
|
|
||
|
/* The monitor prints register values in the form
|
||
|
|
||
|
regname = xxxx xxxx
|
||
|
|
||
|
We look up the register name in a table, and remove the embedded space in
|
||
|
the hex value before passing it to monitor_supply_register. */
|
||
|
|
||
|
static void
|
||
|
r3900_supply_register (regname, regnamelen, val, vallen)
|
||
|
char *regname;
|
||
|
int regnamelen;
|
||
|
char *val;
|
||
|
int vallen;
|
||
|
{
|
||
|
int regno = -1;
|
||
|
int i;
|
||
|
char valbuf[10];
|
||
|
char *p;
|
||
|
|
||
|
/* Perform some sanity checks on the register name and value. */
|
||
|
if (regnamelen < 2 || regnamelen > 7 || vallen != 9)
|
||
|
return;
|
||
|
|
||
|
/* Look up the register name. */
|
||
|
for (i = 0; reg_table[i].name != NULL; i++)
|
||
|
{
|
||
|
int rlen = strlen (reg_table[i].name);
|
||
|
if (rlen == regnamelen && strncmp (regname, reg_table[i].name, rlen) == 0)
|
||
|
{
|
||
|
regno = reg_table[i].regno;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (regno == -1)
|
||
|
return;
|
||
|
|
||
|
/* Copy the hex value to a buffer and eliminate the embedded space. */
|
||
|
for (i = 0, p = valbuf; i < vallen; i++)
|
||
|
if (val[i] != ' ')
|
||
|
*p++ = val[i];
|
||
|
*p = '\0';
|
||
|
|
||
|
monitor_supply_register (regno, valbuf);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Fetch the BadVaddr register. Unlike the other registers, this
|
||
|
one can't be modified, and the monitor won't even prompt to let
|
||
|
you modify it. */
|
||
|
|
||
|
static void
|
||
|
fetch_bad_vaddr ()
|
||
|
{
|
||
|
char buf[20];
|
||
|
|
||
|
monitor_printf ("xB\r");
|
||
|
monitor_expect ("BadV=", NULL, 0);
|
||
|
monitor_expect_prompt (buf, sizeof (buf));
|
||
|
monitor_supply_register (BADVADDR_REGNUM, buf);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Read a series of bit fields from the monitor, and return their
|
||
|
combined binary value. */
|
||
|
|
||
|
static unsigned long
|
||
|
fetch_fields (bf)
|
||
|
struct bit_field *bf;
|
||
|
{
|
||
|
char buf[20];
|
||
|
unsigned long val = 0;
|
||
|
unsigned long bits;
|
||
|
|
||
|
for (; bf->prefix != NULL; bf++)
|
||
|
{
|
||
|
monitor_expect (bf->prefix, NULL, 0); /* get prefix */
|
||
|
monitor_expect (bf->suffix, buf, sizeof (buf)); /* hex value, suffix */
|
||
|
if (bf->length != 0)
|
||
|
{
|
||
|
bits = strtoul (buf, NULL, 16); /* get field value */
|
||
|
bits &= ((1 << bf->length) - 1); /* mask out useless bits */
|
||
|
val |= bits << bf->start; /* insert into register */
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return val;
|
||
|
}
|
||
|
|
||
|
|
||
|
static void
|
||
|
fetch_bitmapped_register (regno, bf)
|
||
|
int regno;
|
||
|
struct bit_field *bf;
|
||
|
{
|
||
|
unsigned long val;
|
||
|
unsigned char regbuf[MAX_REGISTER_RAW_SIZE];
|
||
|
|
||
|
monitor_printf ("x%s\r", r3900_regnames[regno]);
|
||
|
val = fetch_fields (bf);
|
||
|
monitor_printf (".\r");
|
||
|
monitor_expect_prompt (NULL, 0);
|
||
|
|
||
|
/* supply register stores in target byte order, so swap here */
|
||
|
|
||
|
store_unsigned_integer (regbuf, REGISTER_RAW_SIZE (regno), val);
|
||
|
supply_register (regno, regbuf);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Fetch all registers (if regno is -1), or one register from the
|
||
|
monitor. For most registers, we can use the generic monitor_
|
||
|
monitor_fetch_registers function. But others are displayed in
|
||
|
a very unusual fashion by the monitor, and must be handled specially. */
|
||
|
|
||
|
static void
|
||
|
r3900_fetch_registers (regno)
|
||
|
int regno;
|
||
|
{
|
||
|
switch (regno)
|
||
|
{
|
||
|
case BADVADDR_REGNUM:
|
||
|
fetch_bad_vaddr ();
|
||
|
return;
|
||
|
case PS_REGNUM:
|
||
|
fetch_bitmapped_register (PS_REGNUM, status_fields);
|
||
|
return;
|
||
|
case CAUSE_REGNUM:
|
||
|
fetch_bitmapped_register (CAUSE_REGNUM, cause_fields);
|
||
|
return;
|
||
|
default:
|
||
|
orig_monitor_fetch_registers (regno);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Write the new value of the bitmapped register to the monitor. */
|
||
|
|
||
|
static void
|
||
|
store_bitmapped_register (regno, bf)
|
||
|
int regno;
|
||
|
struct bit_field *bf;
|
||
|
{
|
||
|
unsigned long oldval, newval;
|
||
|
|
||
|
/* Fetch the current value of the register. */
|
||
|
monitor_printf ("x%s\r", r3900_regnames[regno]);
|
||
|
oldval = fetch_fields (bf);
|
||
|
newval = read_register (regno);
|
||
|
|
||
|
/* To save time, write just the fields that have changed. */
|
||
|
for (; bf->prefix != NULL; bf++)
|
||
|
{
|
||
|
if (bf->length != 0)
|
||
|
{
|
||
|
unsigned long oldbits, newbits, mask;
|
||
|
|
||
|
mask = (1 << bf->length) - 1;
|
||
|
oldbits = (oldval >> bf->start) & mask;
|
||
|
newbits = (newval >> bf->start) & mask;
|
||
|
if (oldbits != newbits)
|
||
|
monitor_printf ("%s %lx ", bf->user_name, newbits);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
monitor_printf (".\r");
|
||
|
monitor_expect_prompt (NULL, 0);
|
||
|
}
|
||
|
|
||
|
|
||
|
static void
|
||
|
r3900_store_registers (regno)
|
||
|
int regno;
|
||
|
{
|
||
|
switch (regno)
|
||
|
{
|
||
|
case PS_REGNUM:
|
||
|
store_bitmapped_register (PS_REGNUM, status_fields);
|
||
|
return;
|
||
|
case CAUSE_REGNUM:
|
||
|
store_bitmapped_register (CAUSE_REGNUM, cause_fields);
|
||
|
return;
|
||
|
default:
|
||
|
orig_monitor_store_registers (regno);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Write a 4-byte integer to the buffer in big-endian order. */
|
||
|
|
||
|
static void
|
||
|
write_long (buf, n)
|
||
|
char *buf;
|
||
|
long n;
|
||
|
{
|
||
|
buf[0] = (n >> 24) & 0xff;
|
||
|
buf[1] = (n >> 16) & 0xff;
|
||
|
buf[2] = (n >> 8) & 0xff;
|
||
|
buf[3] = n & 0xff;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Write a 4-byte integer to the buffer in little-endian order. */
|
||
|
|
||
|
static void
|
||
|
write_long_le (buf, n)
|
||
|
char *buf;
|
||
|
long n;
|
||
|
{
|
||
|
buf[0] = n & 0xff;
|
||
|
buf[1] = (n >> 8) & 0xff;
|
||
|
buf[2] = (n >> 16) & 0xff;
|
||
|
buf[3] = (n >> 24) & 0xff;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Read a character from the monitor. If remote debugging is on,
|
||
|
print the received character. If HEX is non-zero, print the
|
||
|
character in hexadecimal; otherwise, print it in ASCII. */
|
||
|
|
||
|
static int
|
||
|
debug_readchar (hex)
|
||
|
int hex;
|
||
|
{
|
||
|
char buf[10];
|
||
|
int c = monitor_readchar ();
|
||
|
|
||
|
if (remote_debug > 0)
|
||
|
{
|
||
|
if (hex)
|
||
|
sprintf (buf, "[%02x]", c & 0xff);
|
||
|
else if (c == '\0')
|
||
|
strcpy (buf, "\\0");
|
||
|
else
|
||
|
{
|
||
|
buf[0] = c;
|
||
|
buf[1] = '\0';
|
||
|
}
|
||
|
puts_debug ("Read -->", buf, "<--");
|
||
|
}
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Send a buffer of characters to the monitor. If remote debugging is on,
|
||
|
print the sent buffer in hex. */
|
||
|
|
||
|
static void
|
||
|
debug_write (buf, buflen)
|
||
|
unsigned char *buf;
|
||
|
int buflen;
|
||
|
{
|
||
|
char s[10];
|
||
|
|
||
|
monitor_write (buf, buflen);
|
||
|
|
||
|
if (remote_debug > 0)
|
||
|
{
|
||
|
while (buflen-- > 0)
|
||
|
{
|
||
|
sprintf (s, "[%02x]", *buf & 0xff);
|
||
|
puts_debug ("Sent -->", s, "<--");
|
||
|
buf++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Ignore a packet sent to us by the monitor. It send packets
|
||
|
when its console is in "communications interface" mode. A packet
|
||
|
is of this form:
|
||
|
|
||
|
start of packet flag (one byte: 0xdc)
|
||
|
packet type (one byte)
|
||
|
length (low byte)
|
||
|
length (high byte)
|
||
|
data (length bytes)
|
||
|
|
||
|
The last two bytes of the data field are a checksum, but we don't
|
||
|
bother to verify it.
|
||
|
*/
|
||
|
|
||
|
static void
|
||
|
ignore_packet ()
|
||
|
{
|
||
|
int c;
|
||
|
int len;
|
||
|
|
||
|
/* Ignore lots of trash (messages about section addresses, for example)
|
||
|
until we see the start of a packet. */
|
||
|
for (len = 0; len < 256; len++)
|
||
|
{
|
||
|
c = debug_readchar (0);
|
||
|
if (c == PESC)
|
||
|
break;
|
||
|
}
|
||
|
if (len == 8)
|
||
|
error ("Packet header byte not found; %02x seen instead.", c);
|
||
|
|
||
|
/* Read the packet type and length. */
|
||
|
c = debug_readchar (1); /* type */
|
||
|
|
||
|
c = debug_readchar (1); /* low byte of length */
|
||
|
len = c & 0xff;
|
||
|
|
||
|
c = debug_readchar (1); /* high byte of length */
|
||
|
len += (c & 0xff) << 8;
|
||
|
|
||
|
/* Ignore the rest of the packet. */
|
||
|
while (len-- > 0)
|
||
|
c = debug_readchar (1);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Encapsulate some data into a packet and send it to the monitor.
|
||
|
|
||
|
The 'p' packet is a special case. This is a packet we send
|
||
|
in response to a read ('r') packet from the monitor. This function
|
||
|
appends a one-byte sequence number to the data field of such a packet.
|
||
|
*/
|
||
|
|
||
|
static void
|
||
|
send_packet (type, buf, buflen, seq)
|
||
|
char type;
|
||
|
unsigned char *buf;
|
||
|
int buflen, seq;
|
||
|
{
|
||
|
unsigned char hdr[4];
|
||
|
int len = buflen;
|
||
|
int sum, i;
|
||
|
|
||
|
/* If this is a 'p' packet, add one byte for a sequence number. */
|
||
|
if (type == 'p')
|
||
|
len++;
|
||
|
|
||
|
/* If the buffer has a non-zero length, add two bytes for a checksum. */
|
||
|
if (len > 0)
|
||
|
len += 2;
|
||
|
|
||
|
/* Write the packet header. */
|
||
|
hdr[0] = PESC;
|
||
|
hdr[1] = type;
|
||
|
hdr[2] = len & 0xff;
|
||
|
hdr[3] = (len >> 8) & 0xff;
|
||
|
debug_write (hdr, sizeof (hdr));
|
||
|
|
||
|
if (len)
|
||
|
{
|
||
|
/* Write the packet data. */
|
||
|
debug_write (buf, buflen);
|
||
|
|
||
|
/* Write the sequence number if this is a 'p' packet. */
|
||
|
if (type == 'p')
|
||
|
{
|
||
|
hdr[0] = seq;
|
||
|
debug_write (hdr, 1);
|
||
|
}
|
||
|
|
||
|
/* Write the checksum. */
|
||
|
sum = 0;
|
||
|
for (i = 0; i < buflen; i++)
|
||
|
{
|
||
|
int tmp = (buf[i] & 0xff);
|
||
|
if (i & 1)
|
||
|
sum += tmp;
|
||
|
else
|
||
|
sum += tmp << 8;
|
||
|
}
|
||
|
if (type == 'p')
|
||
|
{
|
||
|
if (buflen & 1)
|
||
|
sum += (seq & 0xff);
|
||
|
else
|
||
|
sum += (seq & 0xff) << 8;
|
||
|
}
|
||
|
sum = (sum & 0xffff) + ((sum >> 16) & 0xffff);
|
||
|
sum += (sum >> 16) & 1;
|
||
|
sum = ~sum;
|
||
|
|
||
|
hdr[0] = (sum >> 8) & 0xff;
|
||
|
hdr[1] = sum & 0xff;
|
||
|
debug_write (hdr, 2);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Respond to an expected read request from the monitor by sending
|
||
|
data in chunks. Handle all acknowledgements and handshaking packets.
|
||
|
|
||
|
The monitor expects a response consisting of a one or more 'p' packets,
|
||
|
each followed by a portion of the data requested. The 'p' packet
|
||
|
contains only a four-byte integer, the value of which is the number
|
||
|
of bytes of data we are about to send. Following the 'p' packet,
|
||
|
the monitor expects the data bytes themselves in raw, unpacketized,
|
||
|
form, without even a checksum.
|
||
|
*/
|
||
|
|
||
|
static void
|
||
|
process_read_request (buf, buflen)
|
||
|
unsigned char *buf;
|
||
|
int buflen;
|
||
|
{
|
||
|
unsigned char len[4];
|
||
|
int i, chunk;
|
||
|
unsigned char seq;
|
||
|
|
||
|
/* Discard the read request. FIXME: we have to hope it's for
|
||
|
the exact number of bytes we want to send; should check for this. */
|
||
|
ignore_packet ();
|
||
|
|
||
|
for (i = chunk = 0, seq = 0; i < buflen; i += chunk, seq++)
|
||
|
{
|
||
|
/* Don't send more than MAXPSIZE bytes at a time. */
|
||
|
chunk = buflen - i;
|
||
|
if (chunk > MAXPSIZE)
|
||
|
chunk = MAXPSIZE;
|
||
|
|
||
|
/* Write a packet containing the number of bytes we are sending. */
|
||
|
write_long_le (len, chunk);
|
||
|
send_packet ('p', len, sizeof (len), seq);
|
||
|
|
||
|
/* Write the data in raw form following the packet. */
|
||
|
debug_write (&buf[i], chunk);
|
||
|
|
||
|
/* Discard the ACK packet. */
|
||
|
ignore_packet ();
|
||
|
}
|
||
|
|
||
|
/* Send an "end of data" packet. */
|
||
|
send_packet ('e', "", 0, 0);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Count loadable sections (helper function for r3900_load). */
|
||
|
|
||
|
static void
|
||
|
count_section (abfd, s, section_count)
|
||
|
bfd *abfd;
|
||
|
asection *s;
|
||
|
unsigned int *section_count;
|
||
|
{
|
||
|
if (s->flags & SEC_LOAD && bfd_section_size (abfd, s) != 0)
|
||
|
(*section_count)++;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Load a single BFD section (helper function for r3900_load).
|
||
|
|
||
|
WARNING: this code is filled with assumptions about how
|
||
|
the Densan monitor loads programs. The monitor issues
|
||
|
packets containing read requests, but rather than respond
|
||
|
to them in an general way, we expect them to following
|
||
|
a certain pattern.
|
||
|
|
||
|
For example, we know that the monitor will start loading by
|
||
|
issuing an 8-byte read request for the binary file header.
|
||
|
We know this is coming and ignore the actual contents
|
||
|
of the read request packet.
|
||
|
*/
|
||
|
|
||
|
static void
|
||
|
load_section (abfd, s, data_count)
|
||
|
bfd *abfd;
|
||
|
asection *s;
|
||
|
unsigned int *data_count;
|
||
|
{
|
||
|
if (s->flags & SEC_LOAD)
|
||
|
{
|
||
|
bfd_size_type section_size = bfd_section_size (abfd, s);
|
||
|
bfd_vma section_base = bfd_section_lma (abfd, s);
|
||
|
unsigned char *buffer;
|
||
|
unsigned char header[8];
|
||
|
|
||
|
/* Don't output zero-length sections. */
|
||
|
if (section_size == 0)
|
||
|
return;
|
||
|
if (data_count)
|
||
|
*data_count += section_size;
|
||
|
|
||
|
/* Print some fluff about the section being loaded. */
|
||
|
printf_filtered ("Loading section %s, size 0x%lx lma ",
|
||
|
bfd_section_name (abfd, s), (long) section_size);
|
||
|
print_address_numeric (section_base, 1, gdb_stdout);
|
||
|
printf_filtered ("\n");
|
||
|
gdb_flush (gdb_stdout);
|
||
|
|
||
|
/* Write the section header (location and size). */
|
||
|
write_long (&header[0], (long) section_base);
|
||
|
write_long (&header[4], (long) section_size);
|
||
|
process_read_request (header, sizeof (header));
|
||
|
|
||
|
/* Read the section contents into a buffer, write it out,
|
||
|
then free the buffer. */
|
||
|
buffer = (unsigned char *) xmalloc (section_size);
|
||
|
bfd_get_section_contents (abfd, s, buffer, 0, section_size);
|
||
|
process_read_request (buffer, section_size);
|
||
|
free (buffer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* When the ethernet is used as the console port on the Densan board,
|
||
|
we can use the "Rm" command to do a fast binary load. The format
|
||
|
of the download data is:
|
||
|
|
||
|
number of sections (4 bytes)
|
||
|
starting address (4 bytes)
|
||
|
repeat for each section:
|
||
|
location address (4 bytes)
|
||
|
section size (4 bytes)
|
||
|
binary data
|
||
|
|
||
|
The 4-byte fields are all in big-endian order.
|
||
|
|
||
|
Using this command is tricky because we have to put the monitor
|
||
|
into a special funky "communications interface" mode, in which
|
||
|
it sends and receives packets of data along with the normal prompt.
|
||
|
*/
|
||
|
|
||
|
static void
|
||
|
r3900_load (filename, from_tty)
|
||
|
char *filename;
|
||
|
int from_tty;
|
||
|
{
|
||
|
bfd *abfd;
|
||
|
unsigned int data_count = 0;
|
||
|
time_t start_time, end_time; /* for timing of download */
|
||
|
int section_count = 0;
|
||
|
unsigned char buffer[8];
|
||
|
|
||
|
/* If we are not using the ethernet, use the normal monitor load,
|
||
|
which sends S-records over the serial link. */
|
||
|
if (!ethernet)
|
||
|
{
|
||
|
orig_monitor_load (filename, from_tty);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* Open the file. */
|
||
|
if (filename == NULL || filename[0] == 0)
|
||
|
filename = get_exec_file (1);
|
||
|
abfd = bfd_openr (filename, 0);
|
||
|
if (!abfd)
|
||
|
error ("Unable to open file %s\n", filename);
|
||
|
if (bfd_check_format (abfd, bfd_object) == 0)
|
||
|
error ("File is not an object file\n");
|
||
|
|
||
|
/* Output the "vconsi" command to get the monitor in the communication
|
||
|
state where it will accept a load command. This will cause
|
||
|
the monitor to emit a packet before each prompt, so ignore the packet. */
|
||
|
monitor_printf ("vconsi\r");
|
||
|
ignore_packet ();
|
||
|
monitor_expect_prompt (NULL, 0);
|
||
|
|
||
|
/* Output the "Rm" (load) command and respond to the subsequent "open"
|
||
|
packet by sending an ACK packet. */
|
||
|
monitor_printf ("Rm\r");
|
||
|
ignore_packet ();
|
||
|
send_packet ('a', "", 0, 0);
|
||
|
|
||
|
/* Output the fast load header (number of sections and starting address). */
|
||
|
bfd_map_over_sections ((bfd *) abfd, (section_map_func) count_section,
|
||
|
§ion_count);
|
||
|
write_long (&buffer[0], (long) section_count);
|
||
|
if (exec_bfd)
|
||
|
write_long (&buffer[4], (long) bfd_get_start_address (exec_bfd));
|
||
|
else
|
||
|
write_long (&buffer[4], 0);
|
||
|
process_read_request (buffer, sizeof (buffer));
|
||
|
|
||
|
/* Output the section data. */
|
||
|
start_time = time (NULL);
|
||
|
bfd_map_over_sections (abfd, (section_map_func) load_section, &data_count);
|
||
|
end_time = time (NULL);
|
||
|
|
||
|
/* Acknowledge the close packet and put the monitor back into
|
||
|
"normal" mode so it won't send packets any more. */
|
||
|
ignore_packet ();
|
||
|
send_packet ('a', "", 0, 0);
|
||
|
monitor_expect_prompt (NULL, 0);
|
||
|
monitor_printf ("vconsx\r");
|
||
|
monitor_expect_prompt (NULL, 0);
|
||
|
|
||
|
/* Print start address and download performance information. */
|
||
|
printf_filtered ("Start address 0x%lx\n", (long) bfd_get_start_address (abfd));
|
||
|
report_transfer_performance (data_count, start_time, end_time);
|
||
|
|
||
|
/* Finally, make the PC point at the start address */
|
||
|
if (exec_bfd)
|
||
|
write_pc (bfd_get_start_address (exec_bfd));
|
||
|
|
||
|
inferior_pid = 0; /* No process now */
|
||
|
|
||
|
/* This is necessary because many things were based on the PC at the
|
||
|
time that we attached to the monitor, which is no longer valid
|
||
|
now that we have loaded new code (and just changed the PC).
|
||
|
Another way to do this might be to call normal_stop, except that
|
||
|
the stack may not be valid, and things would get horribly
|
||
|
confused... */
|
||
|
clear_symtab_users ();
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Commands to send to the monitor when first connecting:
|
||
|
* The bare carriage return forces a prompt from the monitor
|
||
|
(monitor doesn't prompt immediately after a reset).
|
||
|
* The "vconsx" switches the monitor back to interactive mode
|
||
|
in case an aborted download had left it in packet mode.
|
||
|
* The "Xtr" command causes subsequent "t" (trace) commands to display
|
||
|
the general registers only.
|
||
|
* The "Xxr" command does the same thing for the "x" (examine
|
||
|
registers) command.
|
||
|
* The "bx" command clears all breakpoints.
|
||
|
*/
|
||
|
|
||
|
static char *r3900_inits[] =
|
||
|
{"\r", "vconsx\r", "Xtr\r", "Xxr\r", "bx\r", NULL};
|
||
|
static char *dummy_inits[] =
|
||
|
{NULL};
|
||
|
|
||
|
static struct target_ops r3900_ops;
|
||
|
static struct monitor_ops r3900_cmds;
|
||
|
|
||
|
static void
|
||
|
r3900_open (args, from_tty)
|
||
|
char *args;
|
||
|
int from_tty;
|
||
|
{
|
||
|
char buf[64];
|
||
|
int i;
|
||
|
|
||
|
monitor_open (args, &r3900_cmds, from_tty);
|
||
|
|
||
|
/* We have to handle sending the init strings ourselves, because
|
||
|
the first two strings we send (carriage returns) may not be echoed
|
||
|
by the monitor, but the rest will be. */
|
||
|
monitor_printf_noecho ("\r\r");
|
||
|
for (i = 0; r3900_inits[i] != NULL; i++)
|
||
|
{
|
||
|
monitor_printf (r3900_inits[i]);
|
||
|
monitor_expect_prompt (NULL, 0);
|
||
|
}
|
||
|
|
||
|
/* Attempt to determine whether the console device is ethernet or serial.
|
||
|
This will tell us which kind of load to use (S-records over a serial
|
||
|
link, or the Densan fast binary multi-section format over the net). */
|
||
|
|
||
|
ethernet = 0;
|
||
|
monitor_printf ("v\r");
|
||
|
if (monitor_expect ("console device :", NULL, 0) != -1)
|
||
|
if (monitor_expect ("\n", buf, sizeof (buf)) != -1)
|
||
|
if (strstr (buf, "ethernet") != NULL)
|
||
|
ethernet = 1;
|
||
|
monitor_expect_prompt (NULL, 0);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
_initialize_r3900_rom ()
|
||
|
{
|
||
|
r3900_cmds.flags = MO_NO_ECHO_ON_OPEN |
|
||
|
MO_ADDR_BITS_REMOVE |
|
||
|
MO_CLR_BREAK_USES_ADDR |
|
||
|
MO_GETMEM_READ_SINGLE |
|
||
|
MO_PRINT_PROGRAM_OUTPUT;
|
||
|
|
||
|
r3900_cmds.init = dummy_inits;
|
||
|
r3900_cmds.cont = "g\r";
|
||
|
r3900_cmds.step = "t\r";
|
||
|
r3900_cmds.set_break = "b %A\r"; /* COREADDR */
|
||
|
r3900_cmds.clr_break = "b %A,0\r"; /* COREADDR */
|
||
|
r3900_cmds.fill = "fx %A s %x %x\r"; /* COREADDR, len, val */
|
||
|
|
||
|
r3900_cmds.setmem.cmdb = "sx %A %x\r"; /* COREADDR, val */
|
||
|
r3900_cmds.setmem.cmdw = "sh %A %x\r"; /* COREADDR, val */
|
||
|
r3900_cmds.setmem.cmdl = "sw %A %x\r"; /* COREADDR, val */
|
||
|
|
||
|
r3900_cmds.getmem.cmdb = "sx %A\r"; /* COREADDR */
|
||
|
r3900_cmds.getmem.cmdw = "sh %A\r"; /* COREADDR */
|
||
|
r3900_cmds.getmem.cmdl = "sw %A\r"; /* COREADDR */
|
||
|
r3900_cmds.getmem.resp_delim = " : ";
|
||
|
r3900_cmds.getmem.term = " ";
|
||
|
r3900_cmds.getmem.term_cmd = ".\r";
|
||
|
|
||
|
r3900_cmds.setreg.cmd = "x%s %x\r"; /* regname, val */
|
||
|
|
||
|
r3900_cmds.getreg.cmd = "x%s\r"; /* regname */
|
||
|
r3900_cmds.getreg.resp_delim = "=";
|
||
|
r3900_cmds.getreg.term = " ";
|
||
|
r3900_cmds.getreg.term_cmd = ".\r";
|
||
|
|
||
|
r3900_cmds.dump_registers = "x\r";
|
||
|
r3900_cmds.register_pattern =
|
||
|
"\\([a-zA-Z0-9_]+\\) *=\\([0-9a-f]+ [0-9a-f]+\\b\\)";
|
||
|
r3900_cmds.supply_register = r3900_supply_register;
|
||
|
/* S-record download, via "keyboard port". */
|
||
|
r3900_cmds.load = "r0\r";
|
||
|
r3900_cmds.prompt = "#";
|
||
|
r3900_cmds.line_term = "\r";
|
||
|
r3900_cmds.target = &r3900_ops;
|
||
|
r3900_cmds.stopbits = SERIAL_1_STOPBITS;
|
||
|
r3900_cmds.regnames = r3900_regnames;
|
||
|
r3900_cmds.magic = MONITOR_OPS_MAGIC;
|
||
|
|
||
|
init_monitor_ops (&r3900_ops);
|
||
|
|
||
|
r3900_ops.to_shortname = "r3900";
|
||
|
r3900_ops.to_longname = "R3900 monitor";
|
||
|
r3900_ops.to_doc = "Debug using the DVE R3900 monitor.\n\
|
||
|
Specify the serial device it is connected to (e.g. /dev/ttya).";
|
||
|
r3900_ops.to_open = r3900_open;
|
||
|
|
||
|
/* Override the functions to fetch and store registers. But save the
|
||
|
addresses of the default functions, because we will use those functions
|
||
|
for "normal" registers. */
|
||
|
|
||
|
orig_monitor_fetch_registers = r3900_ops.to_fetch_registers;
|
||
|
orig_monitor_store_registers = r3900_ops.to_store_registers;
|
||
|
r3900_ops.to_fetch_registers = r3900_fetch_registers;
|
||
|
r3900_ops.to_store_registers = r3900_store_registers;
|
||
|
|
||
|
/* Override the load function, but save the address of the default
|
||
|
function to use when loading S-records over a serial link. */
|
||
|
orig_monitor_load = r3900_ops.to_load;
|
||
|
r3900_ops.to_load = r3900_load;
|
||
|
|
||
|
add_target (&r3900_ops);
|
||
|
}
|