8 changed files with 1705 additions and 0 deletions
File diff suppressed because it is too large
@ -0,0 +1,76 @@ |
|||
/* sim-rx.h --- interface between rl78 simulator and GDB.
|
|||
|
|||
Copyright 2011-2012 Free Software Foundation, Inc. |
|||
|
|||
Contributed by Red Hat. |
|||
|
|||
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 3 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, see <http://www.gnu.org/licenses/>. */
|
|||
|
|||
#if !defined (SIM_RL78_H) |
|||
#define SIM_RL78_H |
|||
|
|||
enum sim_rl78_regnum |
|||
{ |
|||
sim_rl78_bank0_r0_regnum, |
|||
sim_rl78_bank0_r1_regnum, |
|||
sim_rl78_bank0_r2_regnum, |
|||
sim_rl78_bank0_r3_regnum, |
|||
sim_rl78_bank0_r4_regnum, |
|||
sim_rl78_bank0_r5_regnum, |
|||
sim_rl78_bank0_r6_regnum, |
|||
sim_rl78_bank0_r7_regnum, |
|||
|
|||
sim_rl78_bank1_r0_regnum, |
|||
sim_rl78_bank1_r1_regnum, |
|||
sim_rl78_bank1_r2_regnum, |
|||
sim_rl78_bank1_r3_regnum, |
|||
sim_rl78_bank1_r4_regnum, |
|||
sim_rl78_bank1_r5_regnum, |
|||
sim_rl78_bank1_r6_regnum, |
|||
sim_rl78_bank1_r7_regnum, |
|||
|
|||
sim_rl78_bank2_r0_regnum, |
|||
sim_rl78_bank2_r1_regnum, |
|||
sim_rl78_bank2_r2_regnum, |
|||
sim_rl78_bank2_r3_regnum, |
|||
sim_rl78_bank2_r4_regnum, |
|||
sim_rl78_bank2_r5_regnum, |
|||
sim_rl78_bank2_r6_regnum, |
|||
sim_rl78_bank2_r7_regnum, |
|||
|
|||
sim_rl78_bank3_r0_regnum, |
|||
sim_rl78_bank3_r1_regnum, |
|||
sim_rl78_bank3_r2_regnum, |
|||
sim_rl78_bank3_r3_regnum, |
|||
sim_rl78_bank3_r4_regnum, |
|||
sim_rl78_bank3_r5_regnum, |
|||
sim_rl78_bank3_r6_regnum, |
|||
sim_rl78_bank3_r7_regnum, |
|||
|
|||
sim_rl78_psw_regnum, |
|||
sim_rl78_es_regnum, |
|||
sim_rl78_cs_regnum, |
|||
sim_rl78_pc_regnum, |
|||
|
|||
sim_rl78_spl_regnum, |
|||
sim_rl78_sph_regnum, |
|||
sim_rl78_pmc_regnum, |
|||
sim_rl78_mem_regnum, |
|||
|
|||
sim_rl78_num_regs |
|||
}; |
|||
|
|||
#endif /* SIM_RL78_H */ |
|||
@ -0,0 +1,573 @@ |
|||
/* gdb-if.c -- sim interface to GDB.
|
|||
|
|||
Copyright (C) 2011-2012 Free Software Foundation, Inc. |
|||
Contributed by Red Hat, Inc. |
|||
|
|||
This file is part of the GNU simulators. |
|||
|
|||
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 3 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, see <http://www.gnu.org/licenses/>. */
|
|||
|
|||
#include "config.h" |
|||
#include <stdio.h> |
|||
#include <assert.h> |
|||
#include <signal.h> |
|||
#include <string.h> |
|||
#include <ctype.h> |
|||
#include <stdlib.h> |
|||
|
|||
#include "ansidecl.h" |
|||
#include "gdb/callback.h" |
|||
#include "gdb/remote-sim.h" |
|||
#include "gdb/signals.h" |
|||
#include "gdb/sim-rl78.h" |
|||
|
|||
#include "cpu.h" |
|||
#include "mem.h" |
|||
#include "load.h" |
|||
#include "trace.h" |
|||
|
|||
/* Ideally, we'd wrap up all the minisim's data structures in an
|
|||
object and pass that around. However, neither GDB nor run needs |
|||
that ability. |
|||
|
|||
So we just have one instance, that lives in global variables, and |
|||
each time we open it, we re-initialize it. */ |
|||
|
|||
struct sim_state |
|||
{ |
|||
const char *message; |
|||
}; |
|||
|
|||
static struct sim_state the_minisim = { |
|||
"This is the sole rl78 minisim instance." |
|||
}; |
|||
|
|||
static int open; |
|||
|
|||
static unsigned char hw_breakpoints[MEM_SIZE/8]; |
|||
|
|||
static struct host_callback_struct *host_callbacks; |
|||
|
|||
/* Open an instance of the sim. For this sim, only one instance
|
|||
is permitted. If sim_open() is called multiple times, the sim |
|||
will be reset. */ |
|||
|
|||
SIM_DESC |
|||
sim_open (SIM_OPEN_KIND kind, |
|||
struct host_callback_struct *callback, |
|||
struct bfd *abfd, char **argv) |
|||
{ |
|||
if (open) |
|||
fprintf (stderr, "rl78 minisim: re-opened sim\n"); |
|||
|
|||
/* The 'run' interface doesn't use this function, so we don't care
|
|||
about KIND; it's always SIM_OPEN_DEBUG. */ |
|||
if (kind != SIM_OPEN_DEBUG) |
|||
fprintf (stderr, "rl78 minisim: sim_open KIND != SIM_OPEN_DEBUG: %d\n", |
|||
kind); |
|||
|
|||
/* We use this for the load command. Perhaps someday, it'll be used
|
|||
for syscalls too. */ |
|||
host_callbacks = callback; |
|||
|
|||
/* We don't expect any command-line arguments. */ |
|||
|
|||
init_cpu (); |
|||
trace = 0; |
|||
|
|||
sim_disasm_init (abfd); |
|||
open = 1; |
|||
return &the_minisim; |
|||
} |
|||
|
|||
/* Verify the sim descriptor. Just print a message if the descriptor
|
|||
doesn't match. Nothing bad will happen if the descriptor doesn't |
|||
match because all of the state is global. But if it doesn't |
|||
match, that means there's a problem with the caller. */ |
|||
|
|||
static void |
|||
check_desc (SIM_DESC sd) |
|||
{ |
|||
if (sd != &the_minisim) |
|||
fprintf (stderr, "rl78 minisim: desc != &the_minisim\n"); |
|||
} |
|||
|
|||
/* Close the sim. */ |
|||
|
|||
void |
|||
sim_close (SIM_DESC sd, int quitting) |
|||
{ |
|||
check_desc (sd); |
|||
|
|||
/* Not much to do. At least free up our memory. */ |
|||
init_mem (); |
|||
|
|||
open = 0; |
|||
} |
|||
|
|||
/* Open the program to run; print a message if the program cannot
|
|||
be opened. */ |
|||
|
|||
static bfd * |
|||
open_objfile (const char *filename) |
|||
{ |
|||
bfd *prog = bfd_openr (filename, 0); |
|||
|
|||
if (!prog) |
|||
{ |
|||
fprintf (stderr, "Can't read %s\n", filename); |
|||
return 0; |
|||
} |
|||
|
|||
if (!bfd_check_format (prog, bfd_object)) |
|||
{ |
|||
fprintf (stderr, "%s not a rl78 program\n", filename); |
|||
return 0; |
|||
} |
|||
|
|||
return prog; |
|||
} |
|||
|
|||
/* Load a program. */ |
|||
|
|||
SIM_RC |
|||
sim_load (SIM_DESC sd, char *prog, struct bfd *abfd, int from_tty) |
|||
{ |
|||
check_desc (sd); |
|||
|
|||
if (!abfd) |
|||
abfd = open_objfile (prog); |
|||
if (!abfd) |
|||
return SIM_RC_FAIL; |
|||
|
|||
rl78_load (abfd, host_callbacks, "sim"); |
|||
|
|||
return SIM_RC_OK; |
|||
} |
|||
|
|||
/* Create inferior. */ |
|||
|
|||
SIM_RC |
|||
sim_create_inferior (SIM_DESC sd, struct bfd *abfd, char **argv, char **env) |
|||
{ |
|||
check_desc (sd); |
|||
|
|||
if (abfd) |
|||
rl78_load (abfd, 0, "sim"); |
|||
|
|||
return SIM_RC_OK; |
|||
} |
|||
|
|||
/* Read memory. */ |
|||
|
|||
int |
|||
sim_read (SIM_DESC sd, SIM_ADDR mem, unsigned char *buf, int length) |
|||
{ |
|||
check_desc (sd); |
|||
|
|||
if (mem >= MEM_SIZE) |
|||
return 0; |
|||
else if (mem + length > MEM_SIZE) |
|||
length = MEM_SIZE - mem; |
|||
|
|||
mem_get_blk (mem, buf, length); |
|||
return length; |
|||
} |
|||
|
|||
/* Write memory. */ |
|||
|
|||
int |
|||
sim_write (SIM_DESC sd, SIM_ADDR mem, const unsigned char *buf, int length) |
|||
{ |
|||
check_desc (sd); |
|||
|
|||
if (mem >= MEM_SIZE) |
|||
return 0; |
|||
else if (mem + length > MEM_SIZE) |
|||
length = MEM_SIZE - mem; |
|||
|
|||
mem_put_blk (mem, buf, length); |
|||
return length; |
|||
} |
|||
|
|||
/* Read the LENGTH bytes at BUF as an little-endian value. */ |
|||
|
|||
static SI |
|||
get_le (unsigned char *buf, int length) |
|||
{ |
|||
SI acc = 0; |
|||
|
|||
while (--length >= 0) |
|||
acc = (acc << 8) + buf[length]; |
|||
|
|||
return acc; |
|||
} |
|||
|
|||
/* Store VAL as a little-endian value in the LENGTH bytes at BUF. */ |
|||
|
|||
static void |
|||
put_le (unsigned char *buf, int length, SI val) |
|||
{ |
|||
int i; |
|||
|
|||
for (i = 0; i < length; i++) |
|||
{ |
|||
buf[i] = val & 0xff; |
|||
val >>= 8; |
|||
} |
|||
} |
|||
|
|||
/* Verify that REGNO is in the proper range. Return 0 if not and
|
|||
something non-zero if so. */ |
|||
|
|||
static int |
|||
check_regno (enum sim_rl78_regnum regno) |
|||
{ |
|||
return 0 <= regno && regno < sim_rl78_num_regs; |
|||
} |
|||
|
|||
/* Return the size of the register REGNO. */ |
|||
|
|||
static size_t |
|||
reg_size (enum sim_rl78_regnum regno) |
|||
{ |
|||
size_t size; |
|||
|
|||
if (regno == sim_rl78_pc_regnum) |
|||
size = 4; |
|||
else |
|||
size = 1; |
|||
|
|||
return size; |
|||
} |
|||
|
|||
/* Return the register address associated with the register specified by
|
|||
REGNO. */ |
|||
|
|||
static unsigned long |
|||
reg_addr (enum sim_rl78_regnum regno) |
|||
{ |
|||
if (sim_rl78_bank0_r0_regnum <= regno |
|||
&& regno <= sim_rl78_bank0_r7_regnum) |
|||
return 0xffef8 + (regno - sim_rl78_bank0_r0_regnum); |
|||
else if (sim_rl78_bank1_r0_regnum <= regno |
|||
&& regno <= sim_rl78_bank1_r7_regnum) |
|||
return 0xffef0 + (regno - sim_rl78_bank1_r0_regnum); |
|||
else if (sim_rl78_bank2_r0_regnum <= regno |
|||
&& regno <= sim_rl78_bank2_r7_regnum) |
|||
return 0xffee8 + (regno - sim_rl78_bank2_r0_regnum); |
|||
else if (sim_rl78_bank3_r0_regnum <= regno |
|||
&& regno <= sim_rl78_bank3_r7_regnum) |
|||
return 0xffee0 + (regno - sim_rl78_bank3_r0_regnum); |
|||
else if (regno == sim_rl78_psw_regnum) |
|||
return 0xffffa; |
|||
else if (regno == sim_rl78_es_regnum) |
|||
return 0xffffd; |
|||
else if (regno == sim_rl78_cs_regnum) |
|||
return 0xffffc; |
|||
/* Note: We can't handle PC here because it's not memory mapped. */ |
|||
else if (regno == sim_rl78_spl_regnum) |
|||
return 0xffff8; |
|||
else if (regno == sim_rl78_sph_regnum) |
|||
return 0xffff9; |
|||
else if (regno == sim_rl78_pmc_regnum) |
|||
return 0xffffe; |
|||
else if (regno == sim_rl78_mem_regnum) |
|||
return 0xfffff; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
/* Fetch the contents of the register specified by REGNO, placing the
|
|||
contents in BUF. The length LENGTH must match the sim's internal |
|||
notion of the register's size. */ |
|||
|
|||
int |
|||
sim_fetch_register (SIM_DESC sd, int regno, unsigned char *buf, int length) |
|||
{ |
|||
size_t size; |
|||
SI val; |
|||
|
|||
check_desc (sd); |
|||
|
|||
if (!check_regno (regno)) |
|||
return 0; |
|||
|
|||
size = reg_size (regno); |
|||
|
|||
if (length != size) |
|||
return 0; |
|||
|
|||
if (regno == sim_rl78_pc_regnum) |
|||
val = pc; |
|||
else |
|||
val = memory[reg_addr (regno)]; |
|||
|
|||
put_le (buf, length, val); |
|||
|
|||
return size; |
|||
} |
|||
|
|||
/* Store the value stored in BUF to the register REGNO. The length
|
|||
LENGTH must match the sim's internal notion of the register size. */ |
|||
|
|||
int |
|||
sim_store_register (SIM_DESC sd, int regno, unsigned char *buf, int length) |
|||
{ |
|||
size_t size; |
|||
SI val; |
|||
|
|||
check_desc (sd); |
|||
|
|||
if (!check_regno (regno)) |
|||
return -1; |
|||
|
|||
size = reg_size (regno); |
|||
|
|||
if (length != size) |
|||
return -1; |
|||
|
|||
val = get_le (buf, length); |
|||
|
|||
if (regno == sim_rl78_pc_regnum) |
|||
pc = val; |
|||
else |
|||
memory[reg_addr (regno)] = val; |
|||
return size; |
|||
} |
|||
|
|||
/* Print out message associated with "info target". */ |
|||
|
|||
void |
|||
sim_info (SIM_DESC sd, int verbose) |
|||
{ |
|||
check_desc (sd); |
|||
|
|||
printf ("The rl78 minisim doesn't collect any statistics.\n"); |
|||
} |
|||
|
|||
static volatile int stop; |
|||
static enum sim_stop reason; |
|||
int siggnal; |
|||
|
|||
|
|||
/* Given a signal number used by the rl78 bsp (that is, newlib),
|
|||
return the corresponding signal numbers. */ |
|||
|
|||
int |
|||
rl78_signal_to_target (int sig) |
|||
{ |
|||
switch (sig) |
|||
{ |
|||
case 4: |
|||
return TARGET_SIGNAL_ILL; |
|||
|
|||
case 5: |
|||
return TARGET_SIGNAL_TRAP; |
|||
|
|||
case 10: |
|||
return TARGET_SIGNAL_BUS; |
|||
|
|||
case 11: |
|||
return TARGET_SIGNAL_SEGV; |
|||
|
|||
case 24: |
|||
return TARGET_SIGNAL_XCPU; |
|||
break; |
|||
|
|||
case 2: |
|||
return TARGET_SIGNAL_INT; |
|||
|
|||
case 8: |
|||
return TARGET_SIGNAL_FPE; |
|||
break; |
|||
|
|||
case 6: |
|||
return TARGET_SIGNAL_ABRT; |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
|
|||
/* Take a step return code RC and set up the variables consulted by
|
|||
sim_stop_reason appropriately. */ |
|||
|
|||
void |
|||
handle_step (int rc) |
|||
{ |
|||
if (RL78_STEPPED (rc) || RL78_HIT_BREAK (rc)) |
|||
{ |
|||
reason = sim_stopped; |
|||
siggnal = TARGET_SIGNAL_TRAP; |
|||
} |
|||
else if (RL78_STOPPED (rc)) |
|||
{ |
|||
reason = sim_stopped; |
|||
siggnal = rl78_signal_to_target (RL78_STOP_SIG (rc)); |
|||
} |
|||
else |
|||
{ |
|||
assert (RL78_EXITED (rc)); |
|||
reason = sim_exited; |
|||
siggnal = RL78_EXIT_STATUS (rc); |
|||
} |
|||
} |
|||
|
|||
|
|||
/* Resume execution after a stop. */ |
|||
|
|||
void |
|||
sim_resume (SIM_DESC sd, int step, int sig_to_deliver) |
|||
{ |
|||
int rc; |
|||
|
|||
check_desc (sd); |
|||
|
|||
if (sig_to_deliver != 0) |
|||
{ |
|||
fprintf (stderr, |
|||
"Warning: the rl78 minisim does not implement " |
|||
"signal delivery yet.\n" "Resuming with no signal.\n"); |
|||
} |
|||
|
|||
/* We don't clear 'stop' here, because then we would miss
|
|||
interrupts that arrived on the way here. Instead, we clear |
|||
the flag in sim_stop_reason, after GDB has disabled the |
|||
interrupt signal handler. */ |
|||
for (;;) |
|||
{ |
|||
if (stop) |
|||
{ |
|||
stop = 0; |
|||
reason = sim_stopped; |
|||
siggnal = TARGET_SIGNAL_INT; |
|||
break; |
|||
} |
|||
|
|||
if (hw_breakpoints[pc >> 3] |
|||
&& (hw_breakpoints[pc >> 3] & (1 << (pc & 0x7)))) |
|||
{ |
|||
reason = sim_stopped; |
|||
siggnal = TARGET_SIGNAL_TRAP; |
|||
break; |
|||
} |
|||
rc = setjmp (decode_jmp_buf); |
|||
if (rc == 0) |
|||
rc = decode_opcode (); |
|||
|
|||
if (!RL78_STEPPED (rc) || step) |
|||
{ |
|||
handle_step (rc); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
/* Stop the sim. */ |
|||
|
|||
int |
|||
sim_stop (SIM_DESC sd) |
|||
{ |
|||
stop = 1; |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
/* Fetch the stop reason and signal. */ |
|||
|
|||
void |
|||
sim_stop_reason (SIM_DESC sd, enum sim_stop *reason_p, int *sigrc_p) |
|||
{ |
|||
check_desc (sd); |
|||
|
|||
*reason_p = reason; |
|||
*sigrc_p = siggnal; |
|||
} |
|||
|
|||
/* Execute the sim-specific command associated with GDB's "sim ..."
|
|||
command. */ |
|||
|
|||
void |
|||
sim_do_command (SIM_DESC sd, char *cmd) |
|||
{ |
|||
char *args; |
|||
|
|||
check_desc (sd); |
|||
|
|||
if (cmd == NULL) |
|||
{ |
|||
cmd = ""; |
|||
args = ""; |
|||
} |
|||
else |
|||
{ |
|||
char *p = cmd; |
|||
|
|||
/* Skip leading whitespace. */ |
|||
while (isspace (*p)) |
|||
p++; |
|||
|
|||
/* Find the extent of the command word. */ |
|||
for (p = cmd; *p; p++) |
|||
if (isspace (*p)) |
|||
break; |
|||
|
|||
/* Null-terminate the command word, and record the start of any
|
|||
further arguments. */ |
|||
if (*p) |
|||
{ |
|||
*p = '\0'; |
|||
args = p + 1; |
|||
while (isspace (*args)) |
|||
args++; |
|||
} |
|||
else |
|||
args = p; |
|||
} |
|||
|
|||
if (strcmp (cmd, "trace") == 0) |
|||
{ |
|||
if (strcmp (args, "on") == 0) |
|||
trace = 1; |
|||
else if (strcmp (args, "off") == 0) |
|||
trace = 0; |
|||
else |
|||
printf ("The 'sim trace' command expects 'on' or 'off' " |
|||
"as an argument.\n"); |
|||
} |
|||
else if (strcmp (cmd, "verbose") == 0) |
|||
{ |
|||
if (strcmp (args, "on") == 0) |
|||
verbose = 1; |
|||
else if (strcmp (args, "noisy") == 0) |
|||
verbose = 2; |
|||
else if (strcmp (args, "off") == 0) |
|||
verbose = 0; |
|||
else |
|||
printf ("The 'sim verbose' command expects 'on', 'noisy', or 'off'" |
|||
" as an argument.\n"); |
|||
} |
|||
else |
|||
printf ("The 'sim' command expects either 'trace' or 'verbose'" |
|||
" as a subcommand.\n"); |
|||
} |
|||
|
|||
/* Stub for command completion. */ |
|||
|
|||
char ** |
|||
sim_complete_command (SIM_DESC sd, char *text, char *word) |
|||
{ |
|||
return NULL; |
|||
} |
|||
Loading…
Reference in new issue