#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>
#include "regcache.h"
#include "mips-tdep.h"
typedef void (*section_map_func) (bfd * abfd, asection * sect, void *obj);
#define PESC 0xdc
#define MAXPSIZE 1024
extern void report_transfer_performance (unsigned long, time_t, time_t);
struct bit_field
{
char *prefix;
char *suffix;
char *user_name;
int length;
int start;
};
static void r3900_supply_register (char *regname, int regnamelen,
char *val, int vallen);
static void fetch_bad_vaddr (void);
static unsigned long fetch_fields (struct bit_field *bf);
static void fetch_bitmapped_register (int regno, struct bit_field *bf);
static void r3900_fetch_registers (int regno);
static void store_bitmapped_register (int regno, struct bit_field *bf);
static void r3900_store_registers (int regno);
static void write_long (char *buf, long n);
static void write_long_le (char *buf, long n);
static int debug_readchar (int hex);
static void debug_write (unsigned char *buf, int buflen);
static void ignore_packet (void);
static void send_packet (char type, unsigned char *buf, int buflen, int seq);
static void process_read_request (unsigned char *buf, int buflen);
static void count_section (bfd * abfd, asection * s,
unsigned int *section_count);
static void load_section (bfd * abfd, asection * s, unsigned int *data_count);
static void r3900_load (char *filename, int from_tty);
static void r3900_open (char *args, int from_tty);
static void (*orig_monitor_fetch_registers) (int regno);
static void (*orig_monitor_store_registers) (int regno);
static void (*orig_monitor_load) (char *file, int from_tty);
static int ethernet = 0;
static char *r3900_regnames[] =
{
"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",
"l",
"h",
"B",
"Pcause",
"p"
};
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", MIPS_EMBED_HI_REGNUM
}
,
{
"LO", MIPS_EMBED_LO_REGNUM
}
,
{
"PC", MIPS_EMBED_PC_REGNUM
}
,
{
"BadV", MIPS_EMBED_BADVADDR_REGNUM
}
,
{
NULL, 0
}
};
static struct bit_field status_fields[] =
{
{"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},
{"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}
};
#if 0
static struct bit_field cache_fields[] =
{
{"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},
{"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}
};
#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}
};
static void
r3900_supply_register (char *regname, int regnamelen, char *val, int vallen)
{
int regno = -1;
int i;
char valbuf[10];
char *p;
if (regnamelen < 2 || regnamelen > 7 || vallen != 9)
return;
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;
for (i = 0, p = valbuf; i < vallen; i++)
if (val[i] != ' ')
*p++ = val[i];
*p = '\0';
monitor_supply_register (regno, valbuf);
}
static void
fetch_bad_vaddr (void)
{
char buf[20];
monitor_printf ("xB\r");
monitor_expect ("BadV=", NULL, 0);
monitor_expect_prompt (buf, sizeof (buf));
monitor_supply_register (mips_regnum (current_gdbarch)->badvaddr, buf);
}
static unsigned long
fetch_fields (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);
monitor_expect (bf->suffix, buf, sizeof (buf));
if (bf->length != 0)
{
bits = strtoul (buf, NULL, 16);
bits &= ((1 << bf->length) - 1);
val |= bits << bf->start;
}
}
return val;
}
static void
fetch_bitmapped_register (int regno, struct bit_field *bf)
{
unsigned long val;
unsigned char regbuf[MAX_REGISTER_SIZE];
char *regname = NULL;
if (regno >= sizeof (r3900_regnames) / sizeof (r3900_regnames[0]))
internal_error (__FILE__, __LINE__,
_("fetch_bitmapped_register: regno out of bounds"));
else
regname = r3900_regnames[regno];
monitor_printf ("x%s\r", regname);
val = fetch_fields (bf);
monitor_printf (".\r");
monitor_expect_prompt (NULL, 0);
store_unsigned_integer (regbuf, register_size (current_gdbarch, regno), val);
regcache_raw_supply (current_regcache, regno, regbuf);
}
static void
r3900_fetch_registers (int regno)
{
if (regno == mips_regnum (current_gdbarch)->badvaddr)
fetch_bad_vaddr ();
else if (regno == PS_REGNUM)
fetch_bitmapped_register (PS_REGNUM, status_fields);
else if (regno == mips_regnum (current_gdbarch)->cause)
fetch_bitmapped_register (mips_regnum (current_gdbarch)->cause,
cause_fields);
else
orig_monitor_fetch_registers (regno);
}
static void
store_bitmapped_register (int regno, struct bit_field *bf)
{
unsigned long oldval, newval;
char *regname = NULL;
if (regno >= sizeof (r3900_regnames) / sizeof (r3900_regnames[0]))
internal_error (__FILE__, __LINE__,
_("fetch_bitmapped_register: regno out of bounds"));
else
regname = r3900_regnames[regno];
monitor_printf ("x%s\r", regname);
oldval = fetch_fields (bf);
newval = read_register (regno);
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 (int regno)
{
if (regno == PS_REGNUM)
store_bitmapped_register (PS_REGNUM, status_fields);
else if (regno == mips_regnum (current_gdbarch)->cause)
store_bitmapped_register (mips_regnum (current_gdbarch)->cause,
cause_fields);
else
orig_monitor_store_registers (regno);
}
static void
write_long (char *buf, long n)
{
buf[0] = (n >> 24) & 0xff;
buf[1] = (n >> 16) & 0xff;
buf[2] = (n >> 8) & 0xff;
buf[3] = n & 0xff;
}
static void
write_long_le (char *buf, long n)
{
buf[0] = n & 0xff;
buf[1] = (n >> 8) & 0xff;
buf[2] = (n >> 16) & 0xff;
buf[3] = (n >> 24) & 0xff;
}
static int
debug_readchar (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;
}
static void
debug_write (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++;
}
}
}
static void
ignore_packet (void)
{
int c = -1;
int len;
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);
c = debug_readchar (1);
c = debug_readchar (1);
len = c & 0xff;
c = debug_readchar (1);
len += (c & 0xff) << 8;
while (len-- > 0)
c = debug_readchar (1);
}
static void
send_packet (char type, unsigned char *buf, int buflen, int seq)
{
unsigned char hdr[4];
int len = buflen;
int sum, i;
if (type == 'p')
len++;
if (len > 0)
len += 2;
hdr[0] = PESC;
hdr[1] = type;
hdr[2] = len & 0xff;
hdr[3] = (len >> 8) & 0xff;
debug_write (hdr, sizeof (hdr));
if (len)
{
debug_write (buf, buflen);
if (type == 'p')
{
hdr[0] = seq;
debug_write (hdr, 1);
}
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);
}
}
static void
process_read_request (unsigned char *buf, int buflen)
{
unsigned char len[4];
int i, chunk;
unsigned char seq;
ignore_packet ();
for (i = chunk = 0, seq = 0; i < buflen; i += chunk, seq++)
{
chunk = buflen - i;
if (chunk > MAXPSIZE)
chunk = MAXPSIZE;
write_long_le (len, chunk);
send_packet ('p', len, sizeof (len), seq);
debug_write (&buf[i], chunk);
ignore_packet ();
}
send_packet ('e', "", 0, 0);
}
static void
count_section (bfd *abfd, asection *s, unsigned int *section_count)
{
if (s->flags & SEC_LOAD && bfd_section_size (abfd, s) != 0)
(*section_count)++;
}
static void
load_section (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];
if (section_size == 0)
return;
if (data_count)
*data_count += section_size;
printf_filtered ("Loading section %s, size 0x%lx lma ",
bfd_section_name (abfd, s), (long) section_size);
deprecated_print_address_numeric (section_base, 1, gdb_stdout);
printf_filtered ("\n");
gdb_flush (gdb_stdout);
write_long (&header[0], (long) section_base);
write_long (&header[4], (long) section_size);
process_read_request (header, sizeof (header));
buffer = (unsigned char *) xmalloc (section_size);
bfd_get_section_contents (abfd, s, buffer, 0, section_size);
process_read_request (buffer, section_size);
xfree (buffer);
}
}
static void
r3900_load (char *filename, int from_tty)
{
bfd *abfd;
unsigned int data_count = 0;
time_t start_time, end_time;
int section_count = 0;
unsigned char buffer[8];
if (!ethernet)
{
orig_monitor_load (filename, from_tty);
return;
}
if (filename == NULL || filename[0] == 0)
filename = get_exec_file (1);
abfd = bfd_openr (filename, 0);
if (!abfd)
error (_("Unable to open file %s."), filename);
if (bfd_check_format (abfd, bfd_object) == 0)
error (_("File is not an object file."));
monitor_printf ("vconsi\r");
ignore_packet ();
monitor_expect_prompt (NULL, 0);
monitor_printf ("Rm\r");
ignore_packet ();
send_packet ('a', "", 0, 0);
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));
start_time = time (NULL);
bfd_map_over_sections (abfd, (section_map_func) load_section, &data_count);
end_time = time (NULL);
ignore_packet ();
send_packet ('a', "", 0, 0);
monitor_expect_prompt (NULL, 0);
monitor_printf ("vconsx\r");
monitor_expect_prompt (NULL, 0);
printf_filtered ("Start address 0x%lx\n", (long) bfd_get_start_address (abfd));
report_transfer_performance (data_count, start_time, end_time);
if (exec_bfd)
write_pc (bfd_get_start_address (exec_bfd));
inferior_ptid = null_ptid;
clear_symtab_users ();
}
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 (char *args, int from_tty)
{
char buf[64];
int i;
monitor_open (args, &r3900_cmds, from_tty);
monitor_printf_noecho ("\r\r");
for (i = 0; r3900_inits[i] != NULL; i++)
{
monitor_printf (r3900_inits[i]);
monitor_expect_prompt (NULL, 0);
}
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 (void)
{
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";
r3900_cmds.clr_break = "b %A,0\r";
r3900_cmds.fill = "fx %A s %x %x\r";
r3900_cmds.setmem.cmdb = "sx %A %x\r";
r3900_cmds.setmem.cmdw = "sh %A %x\r";
r3900_cmds.setmem.cmdl = "sw %A %x\r";
r3900_cmds.getmem.cmdb = "sx %A\r";
r3900_cmds.getmem.cmdw = "sh %A\r";
r3900_cmds.getmem.cmdl = "sw %A\r";
r3900_cmds.getmem.resp_delim = " : ";
r3900_cmds.getmem.term = " ";
r3900_cmds.getmem.term_cmd = ".\r";
r3900_cmds.setreg.cmd = "x%s %x\r";
r3900_cmds.getreg.cmd = "x%s\r";
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;
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;
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;
orig_monitor_load = r3900_ops.to_load;
r3900_ops.to_load = r3900_load;
add_target (&r3900_ops);
}