[sim]
* configure.tgt: Add rl78 support. * configure: Regenerate. * rl78: New directory. * MAINTAINERS: Add myself as RL78 maintainer. [gdb] * NEWS: Mention RL78 simulator.
This commit is contained in:
parent
1e3a8f45c5
commit
87326c782a
@ -1,3 +1,7 @@
|
||||
2011-11-28 DJ Delorie <dj@redhat.com>
|
||||
|
||||
* NEWS: Mention RL78 simulator.
|
||||
|
||||
2011-11-28 Joel Brobecker <brobecker@adacore.com>
|
||||
|
||||
* symfile.h (struct quick_symbol_functions): Fix the documentation
|
||||
|
4
gdb/NEWS
4
gdb/NEWS
@ -233,6 +233,10 @@ qTMinFTPILen
|
||||
|
||||
Texas Instruments TMS320C6x tic6x-*-*
|
||||
|
||||
* New Simulators
|
||||
|
||||
Renesas RL78 rl78-*-elf
|
||||
|
||||
*** Changes in GDB 7.3.1
|
||||
|
||||
* The build failure for NetBSD and OpenBSD targets have now been fixed.
|
||||
|
@ -1,3 +1,10 @@
|
||||
2011-11-28 DJ Delorie <dj@redhat.com>
|
||||
|
||||
* configure.tgt: Add rl78 support.
|
||||
* configure: Regenerate.
|
||||
* rl78: New directory.
|
||||
* MAINTAINERS: Add myself as RL78 maintainer.
|
||||
|
||||
2011-07-08 Hans-Peter Nilsson <hp@axis.com>
|
||||
|
||||
* MAINTAINERS: Remove Thiemo Seufer.
|
||||
|
@ -15,6 +15,7 @@ cr16 M R Swami Reddy <MR.Swami.Reddy@nsc.com>
|
||||
frv Dave Brolley <brolley@redhat.com>
|
||||
igen (igen simulators)
|
||||
lm32 Jon Beniston <jon@beniston.com>
|
||||
rl78 DJ Delorie <dj@redhat.com>
|
||||
m32c DJ Delorie <dj@redhat.com>
|
||||
m32r Doug Evans <dje@sebabeach.org>
|
||||
m68hc11 Stephane Carrez <stcarrez@nerim.fr>
|
||||
|
8
sim/configure
vendored
8
sim/configure
vendored
@ -652,6 +652,7 @@ microblaze
|
||||
mips
|
||||
mn10300
|
||||
moxie
|
||||
rl78
|
||||
rx
|
||||
sh64
|
||||
sh
|
||||
@ -3773,6 +3774,13 @@ subdirs="$subdirs arm"
|
||||
subdirs="$subdirs rx"
|
||||
|
||||
|
||||
;;
|
||||
rl78-*-*)
|
||||
|
||||
sim_arch=rl78
|
||||
subdirs="$subdirs rl78"
|
||||
|
||||
|
||||
;;
|
||||
sh64*-*-*)
|
||||
|
||||
|
@ -86,6 +86,9 @@ case "${target}" in
|
||||
SIM_ARCH(moxie)
|
||||
sim_testsuite=yes
|
||||
;;
|
||||
rl78-*-*)
|
||||
SIM_ARCH(rl78)
|
||||
;;
|
||||
rx-*-*)
|
||||
SIM_ARCH(rx)
|
||||
;;
|
||||
|
52
sim/rl78/Makefile.in
Normal file
52
sim/rl78/Makefile.in
Normal file
@ -0,0 +1,52 @@
|
||||
#### Makefile.in --- Makefile template for the RL78 simulator
|
||||
|
||||
### Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
|
||||
### Contributed by Red Hat, Inc.
|
||||
###
|
||||
### This file is part of the GNU simulators.
|
||||
###
|
||||
### The GNU simulators are free software; you can redistribute them and/or
|
||||
### modify them 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.
|
||||
###
|
||||
### The GNU simulators are distributed in the hope that they 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 the GNU simulators; if not, write to the Free Software
|
||||
### Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
### 02110-1301, USA
|
||||
|
||||
## COMMON_PRE_CONFIG_FRAG
|
||||
|
||||
SIM_EXTRA_CFLAGS = -Wall
|
||||
|
||||
SIM_RUN_OBJS = \
|
||||
main.o
|
||||
|
||||
SIM_OBJS = \
|
||||
load.o \
|
||||
mem.o \
|
||||
cpu.o \
|
||||
rl78.o \
|
||||
trace.o
|
||||
|
||||
## COMMON_POST_CONFIG_FRAG
|
||||
|
||||
arch = rl78
|
||||
|
||||
err.o : err.h
|
||||
fpu.o : cpu.h fpu.h
|
||||
gdb-if.o : cpu.h mem.h load.h \
|
||||
$(srcdir)/../../include/gdb/callback.h \
|
||||
$(srcdir)/../../include/gdb/remote-sim.h \
|
||||
$(srcdir)/../../include/gdb/signals.h \
|
||||
$(srcdir)/../../include/gdb/sim-rl78.h
|
||||
load.o : ../../bfd/bfd.h cpu.h mem.h
|
||||
main.o : ../../bfd/bfd.h cpu.h mem.h load.h
|
||||
mem.o : mem.h cpu.h
|
||||
reg.o : cpu.h
|
||||
rl78.o : $(srcdir)/../../include/opcode/rl78.h cpu.h mem.h
|
113
sim/rl78/config.in
Normal file
113
sim/rl78/config.in
Normal file
@ -0,0 +1,113 @@
|
||||
/* config.in. Generated from configure.in by autoheader. */
|
||||
|
||||
/* Define to 1 if translation of program messages to the user's native
|
||||
language is requested. */
|
||||
#undef ENABLE_NLS
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#undef HAVE_DLFCN_H
|
||||
|
||||
/* Define to 1 if you have the <errno.h> header file. */
|
||||
#undef HAVE_ERRNO_H
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#undef HAVE_FCNTL_H
|
||||
|
||||
/* Define to 1 if you have the <fpu_control.h> header file. */
|
||||
#undef HAVE_FPU_CONTROL_H
|
||||
|
||||
/* Define to 1 if you have the <getopt.h> header file. */
|
||||
#undef HAVE_GETOPT_H
|
||||
|
||||
/* Define to 1 if you have the `getrusage' function. */
|
||||
#undef HAVE_GETRUSAGE
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the `nsl' library (-lnsl). */
|
||||
#undef HAVE_LIBNSL
|
||||
|
||||
/* Define to 1 if you have the `socket' library (-lsocket). */
|
||||
#undef HAVE_LIBSOCKET
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the `sigaction' function. */
|
||||
#undef HAVE_SIGACTION
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <sys/resource.h> header file. */
|
||||
#undef HAVE_SYS_RESOURCE_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#undef HAVE_SYS_TIME_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the `time' function. */
|
||||
#undef HAVE_TIME
|
||||
|
||||
/* Define to 1 if you have the <time.h> header file. */
|
||||
#undef HAVE_TIME_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to 1 if you have the <zlib.h> header file. */
|
||||
#undef HAVE_ZLIB_H
|
||||
|
||||
/* Define to 1 if you have the `__setfpucw' function. */
|
||||
#undef HAVE___SETFPUCW
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Additional package description */
|
||||
#undef PKGVERSION
|
||||
|
||||
/* Bug reporting address */
|
||||
#undef REPORT_BUGS_TO
|
||||
|
||||
/* Define as the return type of signal handlers (`int' or `void'). */
|
||||
#undef RETSIGTYPE
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* --enable-cycle-accurate */
|
||||
#undef CYCLE_ACCURATE
|
||||
|
||||
/* --enable-cycle-stats */
|
||||
#undef CYCLE_STATS
|
5867
sim/rl78/configure
vendored
Executable file
5867
sim/rl78/configure
vendored
Executable file
File diff suppressed because it is too large
Load Diff
30
sim/rl78/configure.ac
Normal file
30
sim/rl78/configure.ac
Normal file
@ -0,0 +1,30 @@
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
|
||||
dnl Copyright (C) 2005, 2007, 2008, 2009, 2010, 2011
|
||||
dnl Free Software Foundation, Inc.
|
||||
dnl Contributed by Red Hat, Inc.
|
||||
dnl
|
||||
dnl This file is part of the GNU simulators.
|
||||
dnl
|
||||
dnl This program is free software; you can redistribute it and/or modify
|
||||
dnl it under the terms of the GNU General Public License as published by
|
||||
dnl the Free Software Foundation; either version 3 of the License, or
|
||||
dnl (at your option) any later version.
|
||||
dnl
|
||||
dnl This program is distributed in the hope that it will be useful,
|
||||
dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
dnl GNU General Public License for more details.
|
||||
dnl
|
||||
dnl You should have received a copy of the GNU General Public License
|
||||
dnl along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
dnl
|
||||
AC_PREREQ(2.64)dnl
|
||||
AC_INIT(Makefile.in)
|
||||
sinclude(../common/acinclude.m4)
|
||||
|
||||
SIM_AC_COMMON
|
||||
|
||||
AC_CHECK_HEADERS(getopt.h)
|
||||
|
||||
SIM_AC_OUTPUT
|
334
sim/rl78/cpu.c
Normal file
334
sim/rl78/cpu.c
Normal file
@ -0,0 +1,334 @@
|
||||
/* cpu.c --- CPU for RL78 simulator.
|
||||
|
||||
Copyright (C) 2011
|
||||
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 <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "opcode/rl78.h"
|
||||
#include "mem.h"
|
||||
#include "cpu.h"
|
||||
|
||||
int verbose = 0;
|
||||
int trace = 0;
|
||||
int rl78_in_gdb = 1;
|
||||
int timer_enabled = 2;
|
||||
|
||||
#define REGISTER_ADDRESS 0xffee0
|
||||
|
||||
typedef struct {
|
||||
unsigned char x;
|
||||
unsigned char a;
|
||||
unsigned char c;
|
||||
unsigned char b;
|
||||
unsigned char e;
|
||||
unsigned char d;
|
||||
unsigned char l;
|
||||
unsigned char h;
|
||||
} RegBank;
|
||||
|
||||
static void trace_register_init ();
|
||||
|
||||
/* This maps PSW to a pointer into memory[] */
|
||||
static RegBank *regbase_table[256];
|
||||
|
||||
#define regbase regbase_table[memory[RL78_SFR_PSW]]
|
||||
|
||||
#define REG(r) ((regbase)->r)
|
||||
|
||||
void
|
||||
init_cpu (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
init_mem ();
|
||||
|
||||
memset (memory+REGISTER_ADDRESS, 0x11, 8 * 4);
|
||||
memory[RL78_SFR_PSW] = 0x06;
|
||||
memory[RL78_SFR_ES] = 0x0f;
|
||||
memory[RL78_SFR_CS] = 0x00;
|
||||
memory[RL78_SFR_PMC] = 0x00;
|
||||
|
||||
for (i = 0; i < 256; i ++)
|
||||
{
|
||||
int rb0 = (i & RL78_PSW_RBS0) ? 1 : 0;
|
||||
int rb1 = (i & RL78_PSW_RBS1) ? 2 : 0;
|
||||
int rb = rb1 | rb0;
|
||||
regbase_table[i] = (RegBank *)(memory + (3 - rb) * 8 + REGISTER_ADDRESS);
|
||||
}
|
||||
|
||||
trace_register_init ();
|
||||
|
||||
/* This means "by default" */
|
||||
timer_enabled = 2;
|
||||
}
|
||||
|
||||
SI
|
||||
get_reg (RL78_Register regno)
|
||||
{
|
||||
switch (regno)
|
||||
{
|
||||
case RL78_Reg_None:
|
||||
/* Conditionals do this. */
|
||||
return 0;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
case RL78_Reg_X: return REG (x);
|
||||
case RL78_Reg_A: return REG (a);
|
||||
case RL78_Reg_C: return REG (c);
|
||||
case RL78_Reg_B: return REG (b);
|
||||
case RL78_Reg_E: return REG (e);
|
||||
case RL78_Reg_D: return REG (d);
|
||||
case RL78_Reg_L: return REG (l);
|
||||
case RL78_Reg_H: return REG (h);
|
||||
case RL78_Reg_AX: return REG (a) * 256 + REG (x);
|
||||
case RL78_Reg_BC: return REG (b) * 256 + REG (c);
|
||||
case RL78_Reg_DE: return REG (d) * 256 + REG (e);
|
||||
case RL78_Reg_HL: return REG (h) * 256 + REG (l);
|
||||
case RL78_Reg_SP: return memory[RL78_SFR_SP] + 256 * memory[RL78_SFR_SP+1];
|
||||
case RL78_Reg_PSW: return memory[RL78_SFR_PSW];
|
||||
case RL78_Reg_CS: return memory[RL78_SFR_CS];
|
||||
case RL78_Reg_ES: return memory[RL78_SFR_ES];
|
||||
case RL78_Reg_PMC: return memory[RL78_SFR_PMC];
|
||||
case RL78_Reg_MEM: return memory[RL78_SFR_MEM];
|
||||
}
|
||||
}
|
||||
|
||||
extern unsigned char initted[];
|
||||
|
||||
SI
|
||||
set_reg (RL78_Register regno, SI val)
|
||||
{
|
||||
switch (regno)
|
||||
{
|
||||
case RL78_Reg_None:
|
||||
abort ();
|
||||
case RL78_Reg_X: REG (x) = val; break;
|
||||
case RL78_Reg_A: REG (a) = val; break;
|
||||
case RL78_Reg_C: REG (c) = val; break;
|
||||
case RL78_Reg_B: REG (b) = val; break;
|
||||
case RL78_Reg_E: REG (e) = val; break;
|
||||
case RL78_Reg_D: REG (d) = val; break;
|
||||
case RL78_Reg_L: REG (l) = val; break;
|
||||
case RL78_Reg_H: REG (h) = val; break;
|
||||
case RL78_Reg_AX:
|
||||
REG (a) = val >> 8;
|
||||
REG (x) = val & 0xff;
|
||||
break;
|
||||
case RL78_Reg_BC:
|
||||
REG (b) = val >> 8;
|
||||
REG (c) = val & 0xff;
|
||||
break;
|
||||
case RL78_Reg_DE:
|
||||
REG (d) = val >> 8;
|
||||
REG (e) = val & 0xff;
|
||||
break;
|
||||
case RL78_Reg_HL:
|
||||
REG (h) = val >> 8;
|
||||
REG (l) = val & 0xff;
|
||||
break;
|
||||
case RL78_Reg_SP:
|
||||
if (val & 1)
|
||||
{
|
||||
printf ("Warning: SP value 0x%04x truncated at pc=0x%05x\n", val, pc);
|
||||
val &= ~1;
|
||||
}
|
||||
{
|
||||
int old_sp = get_reg (RL78_Reg_SP);
|
||||
if (val < old_sp)
|
||||
{
|
||||
int i;
|
||||
for (i = val; i < old_sp; i ++)
|
||||
initted[i + 0xf0000] = 0;
|
||||
}
|
||||
}
|
||||
memory[RL78_SFR_SP] = val & 0xff;
|
||||
memory[RL78_SFR_SP + 1] = val >> 8;
|
||||
break;
|
||||
case RL78_Reg_PSW: memory[RL78_SFR_PSW] = val; break;
|
||||
case RL78_Reg_CS: memory[RL78_SFR_CS] = val; break;
|
||||
case RL78_Reg_ES: memory[RL78_SFR_ES] = val; break;
|
||||
case RL78_Reg_PMC: memory[RL78_SFR_PMC] = val; break;
|
||||
case RL78_Reg_MEM: memory[RL78_SFR_MEM] = val; break;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
int
|
||||
condition_true (RL78_Condition cond_id, int val)
|
||||
{
|
||||
int psw = get_reg (RL78_Reg_PSW);
|
||||
int z = (psw & RL78_PSW_Z) ? 1 : 0;
|
||||
int cy = (psw & RL78_PSW_CY) ? 1 : 0;
|
||||
|
||||
switch (cond_id)
|
||||
{
|
||||
case RL78_Condition_T:
|
||||
return val != 0;
|
||||
case RL78_Condition_F:
|
||||
return val == 0;
|
||||
case RL78_Condition_C:
|
||||
return cy;
|
||||
case RL78_Condition_NC:
|
||||
return !cy;
|
||||
case RL78_Condition_H:
|
||||
return !(z | cy);
|
||||
case RL78_Condition_NH:
|
||||
return z | cy;
|
||||
case RL78_Condition_Z:
|
||||
return z;
|
||||
case RL78_Condition_NZ:
|
||||
return !z;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
|
||||
const char * const
|
||||
reg_names[] = {
|
||||
"none",
|
||||
"x",
|
||||
"a",
|
||||
"c",
|
||||
"b",
|
||||
"e",
|
||||
"d",
|
||||
"l",
|
||||
"h",
|
||||
"ax",
|
||||
"bc",
|
||||
"de",
|
||||
"hl",
|
||||
"sp",
|
||||
"psw",
|
||||
"cs",
|
||||
"es",
|
||||
"pmc",
|
||||
"mem"
|
||||
};
|
||||
|
||||
static char *
|
||||
psw_string (int psw)
|
||||
{
|
||||
static char buf[30];
|
||||
const char *comma = "";
|
||||
|
||||
buf[0] = 0;
|
||||
if (psw == 0)
|
||||
strcpy (buf, "-");
|
||||
else
|
||||
{
|
||||
#define PSW1(bit, name) if (psw & bit) { strcat (buf, comma); strcat (buf, name); comma = ","; }
|
||||
PSW1 (RL78_PSW_IE, "ie");
|
||||
PSW1 (RL78_PSW_Z, "z");
|
||||
PSW1 (RL78_PSW_RBS1, "r1");
|
||||
PSW1 (RL78_PSW_AC, "ac");
|
||||
PSW1 (RL78_PSW_RBS0, "r0");
|
||||
PSW1 (RL78_PSW_ISP1, "i1");
|
||||
PSW1 (RL78_PSW_ISP0, "i0");
|
||||
PSW1 (RL78_PSW_CY, "cy");
|
||||
}
|
||||
printf ("%s", buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static unsigned char old_regs[32];
|
||||
static int old_psw;
|
||||
static int old_sp;
|
||||
|
||||
int trace_register_words;
|
||||
|
||||
void
|
||||
trace_register_changes (void)
|
||||
{
|
||||
int i;
|
||||
int any = 0;
|
||||
|
||||
if (!trace)
|
||||
return;
|
||||
|
||||
#define TB(name,nv,ov) if (nv != ov) { printf ("%s: \033[31m%02x \033[32m%02x\033[0m ", name, ov, nv); ov = nv; any = 1; }
|
||||
#define TW(name,nv,ov) if (nv != ov) { printf ("%s: \033[31m%04x \033[32m%04x\033[0m ", name, ov, nv); ov = nv; any = 1; }
|
||||
|
||||
if (trace_register_words)
|
||||
{
|
||||
#define TRW(name, idx) TW (name, memory[REGISTER_ADDRESS + (idx)], old_regs[idx])
|
||||
for (i = 0; i < 32; i += 2)
|
||||
{
|
||||
char buf[10];
|
||||
int o, n, a;
|
||||
switch (i)
|
||||
{
|
||||
case 0: strcpy (buf, "AX"); break;
|
||||
case 2: strcpy (buf, "BC"); break;
|
||||
case 4: strcpy (buf, "DE"); break;
|
||||
case 6: strcpy (buf, "HL"); break;
|
||||
default: sprintf (buf, "r%d", i); break;
|
||||
}
|
||||
a = REGISTER_ADDRESS + (i ^ 0x18);
|
||||
o = old_regs[i ^ 0x18] + old_regs[(i ^ 0x18) + 1] * 256;
|
||||
n = memory[a] + memory[a + 1] * 256;
|
||||
TW (buf, n, o);
|
||||
old_regs[i ^ 0x18] = n;
|
||||
old_regs[(i ^ 0x18) + 1] = n >> 8;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < 32; i ++)
|
||||
{
|
||||
char buf[10];
|
||||
if (i < 8)
|
||||
{
|
||||
buf[0] = "XACBEDLH"[i];
|
||||
buf[1] = 0;
|
||||
}
|
||||
else
|
||||
sprintf (buf, "r%d", i);
|
||||
#define TRB(name, idx) TB (name, memory[REGISTER_ADDRESS + (idx)], old_regs[idx])
|
||||
TRB (buf, i ^ 0x18);
|
||||
}
|
||||
}
|
||||
if (memory[RL78_SFR_PSW] != old_psw)
|
||||
{
|
||||
printf ("PSW: \033[31m");
|
||||
psw_string (old_psw);
|
||||
printf (" \033[32m");
|
||||
psw_string (memory[RL78_SFR_PSW]);
|
||||
printf ("\033[0m ");
|
||||
old_psw = memory[RL78_SFR_PSW];
|
||||
any = 1;
|
||||
}
|
||||
TW ("SP", mem_get_hi (RL78_SFR_SP), old_sp);
|
||||
if (any)
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
static void
|
||||
trace_register_init (void)
|
||||
{
|
||||
memcpy (old_regs, memory + REGISTER_ADDRESS, 8 * 4);
|
||||
old_psw = memory[RL78_SFR_PSW];
|
||||
old_sp = mem_get_hi (RL78_SFR_SP);
|
||||
}
|
101
sim/rl78/cpu.h
Normal file
101
sim/rl78/cpu.h
Normal file
@ -0,0 +1,101 @@
|
||||
/* cpu.h --- declarations for the RL78 core.
|
||||
|
||||
Copyright (C) 2005, 2007, 2008, 2009, 2010, 2011
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifndef SIM_RL78_CPU_H_
|
||||
#define SIM_RL78_CPU_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include "opcode/rl78.h"
|
||||
|
||||
extern int verbose;
|
||||
extern int trace;
|
||||
|
||||
typedef uint8_t QI;
|
||||
typedef uint16_t HI;
|
||||
typedef uint32_t SI;
|
||||
|
||||
extern int rl78_in_gdb;
|
||||
|
||||
SI get_reg (RL78_Register);
|
||||
SI set_reg (RL78_Register, SI);
|
||||
|
||||
SI pc;
|
||||
|
||||
|
||||
extern const char * const reg_names[];
|
||||
|
||||
void init_cpu (void);
|
||||
void set_flags (int mask, int newbits);
|
||||
void set_c (int c);
|
||||
int get_c (void);
|
||||
|
||||
const char *bits (int v, int b);
|
||||
|
||||
int condition_true (RL78_Condition cond_id, int val);
|
||||
|
||||
/* Instruction step return codes.
|
||||
Suppose one of the decode_* functions below returns a value R:
|
||||
- If RL78_STEPPED (R), then the single-step completed normally.
|
||||
- If RL78_HIT_BREAK (R), then the program hit a breakpoint.
|
||||
- If RL78_EXITED (R), then the program has done an 'exit' system
|
||||
call, and the exit code is RL78_EXIT_STATUS (R).
|
||||
- If RL78_STOPPED (R), then a signal (number RL78_STOP_SIG (R)) was
|
||||
generated.
|
||||
|
||||
For building step return codes:
|
||||
- RL78_MAKE_STEPPED is the return code for finishing a normal step.
|
||||
- RL78_MAKE_HIT_BREAK is the return code for hitting a breakpoint.
|
||||
- RL78_MAKE_EXITED (C) is the return code for exiting with status C.
|
||||
- RL78_MAKE_STOPPED (S) is the return code for stopping on signal S. */
|
||||
#define RL78_MAKE_STEPPED() (1)
|
||||
#define RL78_MAKE_HIT_BREAK() (2)
|
||||
#define RL78_MAKE_EXITED(c) (((int) (c) << 8) + 3)
|
||||
#define RL78_MAKE_STOPPED(s) (((int) (s) << 8) + 4)
|
||||
|
||||
#define RL78_STEPPED(r) ((r) == RL78_MAKE_STEPPED ())
|
||||
#define RL78_HIT_BREAK(r) ((r) == RL78_MAKE_HIT_BREAK ())
|
||||
#define RL78_EXITED(r) (((r) & 0xff) == 3)
|
||||
#define RL78_EXIT_STATUS(r) ((r) >> 8)
|
||||
#define RL78_STOPPED(r) (((r) & 0xff) == 4)
|
||||
#define RL78_STOP_SIG(r) ((r) >> 8)
|
||||
|
||||
/* The step result for the current step. Global to allow
|
||||
communication between the stepping function and the system
|
||||
calls. */
|
||||
extern int step_result;
|
||||
|
||||
extern int decode_opcode (void);
|
||||
|
||||
extern int trace_register_words;
|
||||
extern void trace_register_changes (void);
|
||||
extern void generate_access_exception (void);
|
||||
extern jmp_buf decode_jmp_buf;
|
||||
|
||||
extern long long total_clocks;
|
||||
extern int pending_clocks;
|
||||
extern int timer_enabled;
|
||||
extern void dump_counts_per_insn (const char * filename);
|
||||
extern unsigned int counts_per_insn[0x100000];
|
||||
|
||||
#endif
|
158
sim/rl78/load.c
Normal file
158
sim/rl78/load.c
Normal file
@ -0,0 +1,158 @@
|
||||
/* load.c --- loading object files into the RL78 simulator.
|
||||
|
||||
Copyright (C) 2005, 2007, 2008, 2009, 2010, 2011
|
||||
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 <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libiberty.h"
|
||||
#include "bfd.h"
|
||||
#include "libbfd.h"
|
||||
#include "cpu.h"
|
||||
#include "mem.h"
|
||||
#include "load.h"
|
||||
#include "elf/internal.h"
|
||||
#include "elf/common.h"
|
||||
|
||||
/* Helper function for invoking a GDB-specified printf. */
|
||||
static void
|
||||
xprintf (host_callback *callback, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start (ap, fmt);
|
||||
|
||||
(*callback->vprintf_filtered) (callback, fmt, ap);
|
||||
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
/* Given a file offset, look up the section name. */
|
||||
static const char *
|
||||
find_section_name_by_offset (bfd *abfd, file_ptr filepos)
|
||||
{
|
||||
asection *s;
|
||||
|
||||
for (s = abfd->sections; s; s = s->next)
|
||||
if (s->filepos == filepos)
|
||||
return bfd_get_section_name (abfd, s);
|
||||
|
||||
return "(unknown)";
|
||||
}
|
||||
|
||||
void
|
||||
rl78_load (bfd *prog, host_callback *callbacks, const char * const simname)
|
||||
{
|
||||
Elf_Internal_Phdr * phdrs;
|
||||
long sizeof_phdrs;
|
||||
int num_headers;
|
||||
int i;
|
||||
int max_rom = 0;
|
||||
|
||||
init_cpu ();
|
||||
|
||||
/* Note we load by ELF program header not by BFD sections.
|
||||
This is because BFD sections get their information from
|
||||
the ELF section structure, which only includes a VMA value
|
||||
and not an LMA value. */
|
||||
sizeof_phdrs = bfd_get_elf_phdr_upper_bound (prog);
|
||||
if (sizeof_phdrs == 0)
|
||||
{
|
||||
fprintf (stderr, "%s: Failed to get size of program headers\n", simname);
|
||||
return;
|
||||
}
|
||||
phdrs = xmalloc (sizeof_phdrs);
|
||||
|
||||
num_headers = bfd_get_elf_phdrs (prog, phdrs);
|
||||
if (num_headers < 1)
|
||||
{
|
||||
fprintf (stderr, "%s: Failed to read program headers\n", simname);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_headers; i++)
|
||||
{
|
||||
Elf_Internal_Phdr * p = phdrs + i;
|
||||
char *buf;
|
||||
bfd_vma size;
|
||||
bfd_vma base;
|
||||
file_ptr offset;
|
||||
|
||||
size = p->p_filesz;
|
||||
if (size <= 0)
|
||||
continue;
|
||||
|
||||
base = p->p_paddr;
|
||||
if (verbose > 1)
|
||||
fprintf (stderr, "[load segment: lma=%08x vma=%08x size=%08x]\n",
|
||||
(int) base, (int) p->p_vaddr, (int) size);
|
||||
if (callbacks)
|
||||
xprintf (callbacks,
|
||||
"Loading section %s, size %#lx lma %08lx vma %08lx\n",
|
||||
find_section_name_by_offset (prog, p->p_offset),
|
||||
size, base, p->p_vaddr);
|
||||
|
||||
buf = xmalloc (size);
|
||||
|
||||
offset = p->p_offset;
|
||||
if (prog->iovec->bseek (prog, offset, SEEK_SET) != 0)
|
||||
{
|
||||
fprintf (stderr, "%s, Failed to seek to offset %lx\n", simname, (long) offset);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (prog->iovec->bread (prog, buf, size) != size)
|
||||
{
|
||||
fprintf (stderr, "%s: Failed to read %lx bytes\n", simname, size);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (base > 0xeffff || base + size > 0xeffff)
|
||||
{
|
||||
fprintf (stderr, "%s, Can't load image to RAM/SFR space: 0x%lx - 0x%lx\n",
|
||||
simname, base, base+size);
|
||||
continue;
|
||||
}
|
||||
if (max_rom < base + size)
|
||||
max_rom = base + size;
|
||||
|
||||
mem_put_blk (base, buf, size);
|
||||
free (buf);
|
||||
}
|
||||
|
||||
free (phdrs);
|
||||
|
||||
mem_rom_size (max_rom);
|
||||
|
||||
pc = prog->start_address;
|
||||
|
||||
if (strcmp (bfd_get_target (prog), "srec") == 0
|
||||
|| pc == 0)
|
||||
{
|
||||
pc = mem_get_hi (0);
|
||||
}
|
||||
|
||||
if (verbose > 1)
|
||||
fprintf (stderr, "[start pc=%08x]\n", (unsigned int) pc);
|
||||
}
|
30
sim/rl78/load.h
Normal file
30
sim/rl78/load.h
Normal file
@ -0,0 +1,30 @@
|
||||
/* load.h --- interface to loading object files into the RX simulator.
|
||||
|
||||
Copyright (C) 2008, 2009, 2010, 2011 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/>.
|
||||
*/
|
||||
|
||||
#ifndef SIM_RL78_LOAD_H_
|
||||
#define SIM_RL78_LOAD_H_
|
||||
|
||||
#include "bfd.h"
|
||||
#include "gdb/callback.h"
|
||||
|
||||
void rl78_load (bfd *, host_callback *callbacks, const char * const simname);
|
||||
|
||||
#endif
|
169
sim/rl78/main.c
Normal file
169
sim/rl78/main.c
Normal file
@ -0,0 +1,169 @@
|
||||
/* main.c --- main function for stand-alone RL78 simulator.
|
||||
|
||||
Copyright (C) 2011
|
||||
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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
|
||||
#include "libiberty.h"
|
||||
#include "bfd.h"
|
||||
|
||||
#include "cpu.h"
|
||||
#include "mem.h"
|
||||
#include "load.h"
|
||||
#include "trace.h"
|
||||
|
||||
static int disassemble = 0;
|
||||
static const char * dump_counts_filename = NULL;
|
||||
|
||||
static void
|
||||
done (int exit_code)
|
||||
{
|
||||
if (verbose)
|
||||
{
|
||||
printf ("Exit code: %d\n", exit_code);
|
||||
printf ("total clocks: %lld\n", total_clocks);
|
||||
}
|
||||
if (dump_counts_filename)
|
||||
dump_counts_per_insn (dump_counts_filename);
|
||||
exit (exit_code);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int o;
|
||||
int save_trace;
|
||||
bfd *prog;
|
||||
int rc;
|
||||
|
||||
xmalloc_set_program_name (argv[0]);
|
||||
|
||||
while ((o = getopt (argc, argv, "tvdr:D:")) != -1)
|
||||
{
|
||||
switch (o)
|
||||
{
|
||||
case 't':
|
||||
trace ++;
|
||||
break;
|
||||
case 'v':
|
||||
verbose ++;
|
||||
break;
|
||||
case 'd':
|
||||
disassemble ++;
|
||||
break;
|
||||
case 'r':
|
||||
mem_ram_size (atoi (optarg));
|
||||
break;
|
||||
case 'D':
|
||||
dump_counts_filename = optarg;
|
||||
break;
|
||||
case '?':
|
||||
{
|
||||
fprintf (stderr,
|
||||
"usage: run [options] program [arguments]\n");
|
||||
fprintf (stderr,
|
||||
"\t-v\t\t- increase verbosity.\n"
|
||||
"\t-t\t\t- trace.\n"
|
||||
"\t-d\t\t- disassemble.\n"
|
||||
"\t-r <bytes>\t- ram size.\n"
|
||||
"\t-D <filename>\t- dump cycle count histogram\n");
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prog = bfd_openr (argv[optind], 0);
|
||||
if (!prog)
|
||||
{
|
||||
fprintf (stderr, "Can't read %s\n", argv[optind]);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (!bfd_check_format (prog, bfd_object))
|
||||
{
|
||||
fprintf (stderr, "%s not a rl78 program\n", argv[optind]);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
init_cpu ();
|
||||
|
||||
rl78_in_gdb = 0;
|
||||
save_trace = trace;
|
||||
trace = 0;
|
||||
rl78_load (prog, 0, argv[0]);
|
||||
trace = save_trace;
|
||||
|
||||
sim_disasm_init (prog);
|
||||
|
||||
rc = setjmp (decode_jmp_buf);
|
||||
|
||||
if (rc == 0)
|
||||
{
|
||||
if (!trace && !disassemble)
|
||||
{
|
||||
/* This will longjmp to the above if an exception
|
||||
happens. */
|
||||
for (;;)
|
||||
decode_opcode ();
|
||||
}
|
||||
else
|
||||
while (1)
|
||||
{
|
||||
|
||||
if (trace)
|
||||
printf ("\n");
|
||||
|
||||
if (disassemble)
|
||||
sim_disasm_one ();
|
||||
|
||||
rc = decode_opcode ();
|
||||
|
||||
if (trace)
|
||||
trace_register_changes ();
|
||||
}
|
||||
}
|
||||
|
||||
if (RL78_HIT_BREAK (rc))
|
||||
done (1);
|
||||
else if (RL78_EXITED (rc))
|
||||
done (RL78_EXIT_STATUS (rc));
|
||||
else if (RL78_STOPPED (rc))
|
||||
{
|
||||
if (verbose)
|
||||
printf ("Stopped on signal %d\n", RL78_STOP_SIG (rc));
|
||||
exit (1);
|
||||
}
|
||||
done (0);
|
||||
exit (0);
|
||||
}
|
426
sim/rl78/mem.c
Normal file
426
sim/rl78/mem.c
Normal file
@ -0,0 +1,426 @@
|
||||
/* mem.c --- memory for RL78 simulator.
|
||||
|
||||
Copyright (C) 2011
|
||||
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 <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "opcode/rl78.h"
|
||||
#include "mem.h"
|
||||
#include "cpu.h"
|
||||
|
||||
#define ILLEGAL_OPCODE 0xff
|
||||
|
||||
int rom_limit = 0x100000;
|
||||
int ram_base = 0xf8000;
|
||||
unsigned char memory[MEM_SIZE];
|
||||
#define MASK 0xfffff
|
||||
|
||||
unsigned char initted[MEM_SIZE];
|
||||
int skip_init = 0;
|
||||
|
||||
#define tprintf if (trace) printf
|
||||
|
||||
void
|
||||
init_mem (void)
|
||||
{
|
||||
memset (memory, ILLEGAL_OPCODE, sizeof (memory));
|
||||
memset (memory + 0xf0000, 0x33, 0x10000);
|
||||
|
||||
memset (initted, 0, sizeof (initted));
|
||||
memset (initted + 0xffee0, 1, 0x00120);
|
||||
memset (initted + 0xf0000, 1, 0x01000);
|
||||
}
|
||||
|
||||
void
|
||||
mem_ram_size (int ram_bytes)
|
||||
{
|
||||
ram_base = 0x100000 - ram_bytes;
|
||||
}
|
||||
|
||||
void
|
||||
mem_rom_size (int rom_bytes)
|
||||
{
|
||||
rom_limit = rom_bytes;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* Note: the RL78 memory map has a few surprises. For starters, part
|
||||
of the first 64k is mapped to the last 64k, depending on an SFR bit
|
||||
and how much RAM the chip has. This is simulated here, as are a
|
||||
few peripherals. */
|
||||
|
||||
/* This is stdout. We only care about the data byte, not the upper byte. */
|
||||
#define SDR00 0xfff10
|
||||
#define SSR00 0xf0100
|
||||
#define TS0 0xf01b2
|
||||
|
||||
/* RL78/G13 multiply/divide peripheral. */
|
||||
#define MDUC 0xf00e8
|
||||
#define MDAL 0xffff0
|
||||
#define MDAH 0xffff2
|
||||
#define MDBL 0xffff4
|
||||
#define MDBH 0xffff6
|
||||
#define MDCL 0xf00e0
|
||||
#define MDCH 0xf00e2
|
||||
static long long mduc_clock = 0;
|
||||
static int mda_set = 0;
|
||||
#define MDA_SET 15
|
||||
|
||||
static int last_addr_was_mirror;
|
||||
|
||||
static int
|
||||
address_mapping (int address)
|
||||
{
|
||||
address &= MASK;
|
||||
if (address >= 0xf1000 && address < ram_base)
|
||||
{
|
||||
address &= 0xffff;
|
||||
tprintf ("&");
|
||||
if (memory[RL78_SFR_PMC] & 1)
|
||||
{
|
||||
tprintf ("|");
|
||||
address |= 0x10000;
|
||||
}
|
||||
last_addr_was_mirror = 1;
|
||||
}
|
||||
else
|
||||
last_addr_was_mirror = 0;
|
||||
|
||||
return address;
|
||||
}
|
||||
|
||||
static void
|
||||
mem_put_byte (int address, unsigned char value)
|
||||
{
|
||||
address = address_mapping (address);
|
||||
memory [address] = value;
|
||||
initted [address] = 1;
|
||||
if (address == SDR00)
|
||||
{
|
||||
putchar (value);
|
||||
fflush (stdout);
|
||||
}
|
||||
if (address == TS0)
|
||||
{
|
||||
if (timer_enabled == 2)
|
||||
{
|
||||
total_clocks = 0;
|
||||
pending_clocks = 0;
|
||||
memset (counts_per_insn, 0, sizeof (counts_per_insn));
|
||||
memory[0xf0180] = 0xff;
|
||||
memory[0xf0181] = 0xff;
|
||||
}
|
||||
if (value & 1)
|
||||
timer_enabled = 1;
|
||||
else
|
||||
timer_enabled = 0;
|
||||
}
|
||||
if (address == RL78_SFR_SP && value & 1)
|
||||
{
|
||||
printf ("Warning: SP value 0x%04x truncated at pc=0x%05x\n", value, pc);
|
||||
value &= ~1;
|
||||
}
|
||||
if (address == MDUC)
|
||||
{
|
||||
if ((value & 0x81) == 0x81)
|
||||
{
|
||||
/* division */
|
||||
mduc_clock = total_clocks;
|
||||
}
|
||||
}
|
||||
if ((address & ~3) == MDAL)
|
||||
{
|
||||
mda_set |= (1 << (address & 3));
|
||||
if (mda_set == MDA_SET)
|
||||
{
|
||||
long als, ahs;
|
||||
unsigned long alu, ahu;
|
||||
long rvs;
|
||||
long mdc;
|
||||
unsigned long rvu;
|
||||
mda_set = 0;
|
||||
switch (memory [MDUC] & 0xc8)
|
||||
{
|
||||
case 0x00:
|
||||
alu = mem_get_hi (MDAL);
|
||||
ahu = mem_get_hi (MDAH);
|
||||
rvu = alu * ahu;
|
||||
tprintf ("MDUC: %lu * %lu = %lu\n", alu, ahu, rvu);
|
||||
mem_put_si (MDBL, rvu);
|
||||
break;
|
||||
case 0x08:
|
||||
als = sign_ext (mem_get_hi (MDAL), 16);
|
||||
ahs = sign_ext (mem_get_hi (MDAH), 16);
|
||||
rvs = als * ahs;
|
||||
tprintf ("MDUC: %ld * %ld = %ld\n", als, ahs, rvs);
|
||||
mem_put_si (MDBL, rvs);
|
||||
break;
|
||||
case 0x40:
|
||||
alu = mem_get_hi (MDAL);
|
||||
ahu = mem_get_hi (MDAH);
|
||||
rvu = alu * ahu;
|
||||
mem_put_si (MDBL, rvu);
|
||||
mdc = mem_get_si (MDCL);
|
||||
tprintf ("MDUC: %lu * %lu + %lu = ", alu, ahu, mdc);
|
||||
mdc += (long) rvu;
|
||||
tprintf ("%lu\n", mdc);
|
||||
mem_put_si (MDCL, mdc);
|
||||
break;
|
||||
case 0x48:
|
||||
als = sign_ext (mem_get_hi (MDAL), 16);
|
||||
ahs = sign_ext (mem_get_hi (MDAH), 16);
|
||||
rvs = als * ahs;
|
||||
mem_put_si (MDBL, rvs);
|
||||
mdc = mem_get_si (MDCL);
|
||||
tprintf ("MDUC: %ld * %ld + %ld = ", als, ahs, mdc);
|
||||
tprintf ("%ld\n", mdc);
|
||||
mdc += rvs;
|
||||
mem_put_si (MDCL, mdc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern long long total_clocks;
|
||||
|
||||
static unsigned char
|
||||
mem_get_byte (int address)
|
||||
{
|
||||
address = address_mapping (address);
|
||||
switch (address)
|
||||
{
|
||||
case SSR00:
|
||||
case SSR00 + 1:
|
||||
return 0x00;
|
||||
case 0xf00f0:
|
||||
return 0;
|
||||
case 0xf0180:
|
||||
case 0xf0181:
|
||||
return memory[address];
|
||||
|
||||
case MDUC:
|
||||
{
|
||||
unsigned char mduc = memory [MDUC];
|
||||
if ((mduc & 0x81) == 0x81
|
||||
&& total_clocks > mduc_clock + 16)
|
||||
{
|
||||
unsigned long a, b, q, r;
|
||||
memory [MDUC] &= 0xfe;
|
||||
a = mem_get_si (MDAL);
|
||||
b = mem_get_si (MDAL);
|
||||
if (b == 0)
|
||||
{
|
||||
q = ~0;
|
||||
r = ~0;
|
||||
}
|
||||
else
|
||||
{
|
||||
q = a / b;
|
||||
r = a % b;
|
||||
}
|
||||
tprintf ("MDUC: %lu / %lu = q %lu, r %lu\n", a, b, q, r);
|
||||
mem_put_si (MDAL, q);
|
||||
mem_put_si (MDCL, r);
|
||||
}
|
||||
return memory[address];
|
||||
}
|
||||
case MDCL:
|
||||
case MDCL + 1:
|
||||
case MDCH:
|
||||
case MDCH + 1:
|
||||
return memory[address];
|
||||
}
|
||||
if (address < 0xf1000 && address >= 0xf0000)
|
||||
{
|
||||
#if 1
|
||||
/* Note: comment out this return to trap the invalid access
|
||||
instead of returning an "undefined" value. */
|
||||
return 0x11;
|
||||
#else
|
||||
fprintf (stderr, "SFR access error: addr 0x%05x pc 0x%05x\n", address, pc);
|
||||
exit (1);
|
||||
#endif
|
||||
}
|
||||
#if 0
|
||||
/* Uncomment this block if you want to trap on reads from unwritten memory. */
|
||||
if (!skip_init && !initted [address])
|
||||
{
|
||||
static int uninit_count = 0;
|
||||
fprintf (stderr, "\033[31mwarning :read from uninit addr %05x pc %05x\033[0m\n", address, pc);
|
||||
uninit_count ++;
|
||||
if (uninit_count > 5)
|
||||
exit (1);
|
||||
}
|
||||
#endif
|
||||
return memory [address];
|
||||
}
|
||||
|
||||
extern jmp_buf decode_jmp_buf;
|
||||
#define DO_RETURN(x) longjmp (decode_jmp_buf, x)
|
||||
|
||||
#define CHECK_ALIGNMENT(a,v,m) \
|
||||
if (a & m) { printf ("Misalignment addr 0x%05x val 0x%04x pc %05x\n", (int)a, (int)v, (int)pc); \
|
||||
DO_RETURN (RL78_MAKE_HIT_BREAK ()); }
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
#define SPECIAL_ADDR(a) (0xffff0 <= a || (0xffee0 <= a && a < 0xfff00))
|
||||
|
||||
void
|
||||
mem_put_qi (int address, unsigned char value)
|
||||
{
|
||||
if (!SPECIAL_ADDR (address))
|
||||
tprintf ("\033[34m([%05X]<-%02X)\033[0m", address, value);
|
||||
mem_put_byte (address, value);
|
||||
}
|
||||
|
||||
void
|
||||
mem_put_hi (int address, unsigned short value)
|
||||
{
|
||||
if (!SPECIAL_ADDR (address))
|
||||
tprintf ("\033[34m([%05X]<-%04X)\033[0m", address, value);
|
||||
CHECK_ALIGNMENT (address, value, 1);
|
||||
if (address > 0xffff8 && address != RL78_SFR_SP)
|
||||
{
|
||||
tprintf ("Word access to 0x%05x!!\n", address);
|
||||
DO_RETURN (RL78_MAKE_HIT_BREAK ());
|
||||
}
|
||||
mem_put_byte (address, value);
|
||||
mem_put_byte (address + 1, value >> 8);
|
||||
}
|
||||
|
||||
void
|
||||
mem_put_psi (int address, unsigned long value)
|
||||
{
|
||||
tprintf ("\033[34m([%05X]<-%06lX)\033[0m", address, value);
|
||||
mem_put_byte (address, value);
|
||||
mem_put_byte (address + 1, value >> 8);
|
||||
mem_put_byte (address + 2, value >> 16);
|
||||
}
|
||||
|
||||
void
|
||||
mem_put_si (int address, unsigned long value)
|
||||
{
|
||||
tprintf ("\033[34m([%05X]<-%08lX)\033[0m", address, value);
|
||||
CHECK_ALIGNMENT (address, value, 3);
|
||||
mem_put_byte (address, value);
|
||||
mem_put_byte (address + 1, value >> 8);
|
||||
mem_put_byte (address + 2, value >> 16);
|
||||
mem_put_byte (address + 3, value >> 24);
|
||||
}
|
||||
|
||||
void
|
||||
mem_put_blk (int address, const void *bufptr, int nbytes)
|
||||
{
|
||||
const unsigned char *bp = (unsigned char *)bufptr;
|
||||
while (nbytes --)
|
||||
mem_put_byte (address ++, *bp ++);
|
||||
}
|
||||
|
||||
unsigned char
|
||||
mem_get_pc (int address)
|
||||
{
|
||||
/* Catch obvious problems. */
|
||||
if (address >= rom_limit && address < 0xf0000)
|
||||
return 0xff;
|
||||
/* This does NOT go through the flash mirror area; you cannot
|
||||
execute out of the mirror. */
|
||||
return memory [address & MASK];
|
||||
}
|
||||
|
||||
unsigned char
|
||||
mem_get_qi (int address)
|
||||
{
|
||||
int v;
|
||||
v = mem_get_byte (address);
|
||||
if (!SPECIAL_ADDR (address))
|
||||
tprintf ("\033[35m([%05X]->%04X)\033[0m", address, v);
|
||||
if (last_addr_was_mirror)
|
||||
{
|
||||
pending_clocks += 3;
|
||||
tprintf ("ROM read\n");
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
unsigned short
|
||||
mem_get_hi (int address)
|
||||
{
|
||||
int v;
|
||||
v = mem_get_byte (address)
|
||||
| mem_get_byte (address + 1) * 256;
|
||||
CHECK_ALIGNMENT (address, v, 1);
|
||||
if (!SPECIAL_ADDR (address))
|
||||
tprintf ("\033[35m([%05X]->%04X)\033[0m", address, v);
|
||||
if (last_addr_was_mirror)
|
||||
{
|
||||
pending_clocks += 3;
|
||||
tprintf ("ROM read\n");
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
mem_get_psi (int address)
|
||||
{
|
||||
int v;
|
||||
v = mem_get_byte (address)
|
||||
| mem_get_byte (address + 1) * 256
|
||||
| mem_get_byte (address + 2) * 65536;
|
||||
tprintf ("\033[35m([%05X]->%04X)\033[0m", address, v);
|
||||
return v;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
mem_get_si (int address)
|
||||
{
|
||||
int v;
|
||||
v = mem_get_byte (address)
|
||||
| mem_get_byte (address + 1) * 256
|
||||
| mem_get_byte (address + 2) * 65536
|
||||
| mem_get_byte (address + 2) * 16777216;
|
||||
CHECK_ALIGNMENT (address, v, 3);
|
||||
tprintf ("(\033[35m[%05X]->%04X)\033[0m", address, v);
|
||||
return v;
|
||||
}
|
||||
|
||||
void
|
||||
mem_get_blk (int address, void *bufptr, int nbytes)
|
||||
{
|
||||
unsigned char *bp = (unsigned char *)bufptr;
|
||||
while (nbytes --)
|
||||
*bp ++ = mem_get_byte (address ++);
|
||||
}
|
||||
|
||||
int
|
||||
sign_ext (int v, int bits)
|
||||
{
|
||||
if (bits < 8 * sizeof (int))
|
||||
{
|
||||
v &= (1 << bits) - 1;
|
||||
if (v & (1 << (bits - 1)))
|
||||
v -= (1 << bits);
|
||||
}
|
||||
return v;
|
||||
}
|
55
sim/rl78/mem.h
Normal file
55
sim/rl78/mem.h
Normal file
@ -0,0 +1,55 @@
|
||||
/* mem.h --- interface to memory for RL78 simulator.
|
||||
|
||||
Copyright (C) 2011
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifndef SIM_RL78_MEM_H_
|
||||
#define SIM_RL78_MEM_H_
|
||||
|
||||
#define MEM_SIZE 0x100000
|
||||
|
||||
/* Only for cpu.c to use. */
|
||||
extern unsigned char memory[];
|
||||
|
||||
void init_mem (void);
|
||||
|
||||
/* Pass the amount of bytes, like 2560 for 2.5k */
|
||||
void mem_ram_size (int ram_bytes);
|
||||
void mem_rom_size (int rom_bytes);
|
||||
|
||||
void mem_put_qi (int address, unsigned char value);
|
||||
void mem_put_hi (int address, unsigned short value);
|
||||
void mem_put_psi (int address, unsigned long value);
|
||||
void mem_put_si (int address, unsigned long value);
|
||||
|
||||
void mem_put_blk (int address, const void *bufptr, int nbytes);
|
||||
|
||||
unsigned char mem_get_pc (int address);
|
||||
|
||||
unsigned char mem_get_qi (int address);
|
||||
unsigned short mem_get_hi (int address);
|
||||
unsigned long mem_get_psi (int address);
|
||||
unsigned long mem_get_si (int address);
|
||||
|
||||
void mem_get_blk (int address, void *bufptr, int nbytes);
|
||||
|
||||
int sign_ext (int v, int bits);
|
||||
|
||||
#endif
|
915
sim/rl78/rl78.c
Normal file
915
sim/rl78/rl78.c
Normal file
@ -0,0 +1,915 @@
|
||||
/* rl78.c --- opcode semantics for stand-alone RL78 simulator.
|
||||
|
||||
Copyright (C) 2008, 2009, 2010, 2011 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <setjmp.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "opcode/rl78.h"
|
||||
#include "cpu.h"
|
||||
#include "mem.h"
|
||||
|
||||
extern int skip_init;
|
||||
static int opcode_pc = 0;
|
||||
|
||||
jmp_buf decode_jmp_buf;
|
||||
#define DO_RETURN(x) longjmp (decode_jmp_buf, x)
|
||||
|
||||
#define tprintf if (trace) printf
|
||||
|
||||
#define WILD_JUMP_CHECK(new_pc) \
|
||||
do { \
|
||||
if (new_pc == 0 || new_pc > 0xfffff) \
|
||||
{ \
|
||||
pc = opcode_pc; \
|
||||
fprintf (stderr, "Wild jump to 0x%x from 0x%x!\n", new_pc, pc); \
|
||||
DO_RETURN (RL78_MAKE_HIT_BREAK ()); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
typedef struct {
|
||||
unsigned long dpc;
|
||||
} RL78_Data;
|
||||
|
||||
static int
|
||||
rl78_get_byte (void *vdata)
|
||||
{
|
||||
RL78_Data *rl78_data = (RL78_Data *)vdata;
|
||||
int rv = mem_get_pc (rl78_data->dpc);
|
||||
rl78_data->dpc ++;
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int
|
||||
op_addr (const RL78_Opcode_Operand *o, int for_data)
|
||||
{
|
||||
int v = o->addend;
|
||||
if (o->reg != RL78_Reg_None)
|
||||
v += get_reg (o->reg);
|
||||
if (o->reg2 != RL78_Reg_None)
|
||||
v += get_reg (o->reg2);
|
||||
if (o->use_es)
|
||||
v |= (get_reg (RL78_Reg_ES) & 0xf) << 16;
|
||||
else if (for_data)
|
||||
v |= 0xf0000;
|
||||
v &= 0xfffff;
|
||||
return v;
|
||||
}
|
||||
|
||||
static int
|
||||
get_op (const RL78_Opcode_Decoded *rd, int i, int for_data)
|
||||
{
|
||||
int v, r;
|
||||
const RL78_Opcode_Operand *o = rd->op + i;
|
||||
|
||||
switch (o->type)
|
||||
{
|
||||
case RL78_Operand_None:
|
||||
/* condition code does this. */
|
||||
v = 0;
|
||||
break;
|
||||
|
||||
case RL78_Operand_Immediate:
|
||||
tprintf (" #");
|
||||
v = o->addend;
|
||||
break;
|
||||
|
||||
case RL78_Operand_Register:
|
||||
tprintf (" %s=", reg_names[o->reg]);
|
||||
v = get_reg (o->reg);
|
||||
break;
|
||||
|
||||
case RL78_Operand_Bit:
|
||||
tprintf (" %s.%d=", reg_names[o->reg], o->bit_number);
|
||||
v = get_reg (o->reg);
|
||||
v = (v & (1 << o->bit_number)) ? 1 : 0;
|
||||
break;
|
||||
|
||||
case RL78_Operand_Indirect:
|
||||
v = op_addr (o, for_data);
|
||||
tprintf (" [0x%x]=", v);
|
||||
if (rd->size == RL78_Word)
|
||||
v = mem_get_hi (v);
|
||||
else
|
||||
v = mem_get_qi (v);
|
||||
break;
|
||||
|
||||
case RL78_Operand_BitIndirect:
|
||||
v = op_addr (o, for_data);
|
||||
tprintf (" [0x%x].%d=", v, o->bit_number);
|
||||
v = (mem_get_qi (v) & (1 << o->bit_number)) ? 1 : 0;
|
||||
break;
|
||||
|
||||
case RL78_Operand_PreDec:
|
||||
r = get_reg (o->reg);
|
||||
tprintf (" [--%s]", reg_names[o->reg]);
|
||||
if (rd->size == RL78_Word)
|
||||
{
|
||||
r -= 2;
|
||||
v = mem_get_hi (r | 0xf0000);
|
||||
}
|
||||
else
|
||||
{
|
||||
r -= 1;
|
||||
v = mem_get_qi (r | 0xf0000);
|
||||
}
|
||||
set_reg (o->reg, r);
|
||||
break;
|
||||
|
||||
case RL78_Operand_PostInc:
|
||||
tprintf (" [%s++]", reg_names[o->reg]);
|
||||
r = get_reg (o->reg);
|
||||
if (rd->size == RL78_Word)
|
||||
{
|
||||
v = mem_get_hi (r | 0xf0000);
|
||||
r += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
v = mem_get_qi (r | 0xf0000);
|
||||
r += 1;
|
||||
}
|
||||
set_reg (o->reg, r);
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
tprintf ("%d", v);
|
||||
return v;
|
||||
}
|
||||
|
||||
static void
|
||||
put_op (const RL78_Opcode_Decoded *rd, int i, int for_data, int v)
|
||||
{
|
||||
int r, a;
|
||||
const RL78_Opcode_Operand *o = rd->op + i;
|
||||
|
||||
tprintf (" -> ");
|
||||
|
||||
switch (o->type)
|
||||
{
|
||||
case RL78_Operand_Register:
|
||||
tprintf ("%s", reg_names[o->reg]);
|
||||
set_reg (o->reg, v);
|
||||
break;
|
||||
|
||||
case RL78_Operand_Bit:
|
||||
tprintf ("%s.%d", reg_names[o->reg], o->bit_number);
|
||||
r = get_reg (o->reg);
|
||||
if (v)
|
||||
r |= (1 << o->bit_number);
|
||||
else
|
||||
r &= ~(1 << o->bit_number);
|
||||
set_reg (o->reg, r);
|
||||
break;
|
||||
|
||||
case RL78_Operand_Indirect:
|
||||
r = op_addr (o, for_data);
|
||||
tprintf ("[0x%x]", r);
|
||||
if (rd->size == RL78_Word)
|
||||
mem_put_hi (r, v);
|
||||
else
|
||||
mem_put_qi (r, v);
|
||||
break;
|
||||
|
||||
case RL78_Operand_BitIndirect:
|
||||
a = op_addr (o, for_data);
|
||||
tprintf ("[0x%x].%d", a, o->bit_number);
|
||||
r = mem_get_qi (a);
|
||||
if (v)
|
||||
r |= (1 << o->bit_number);
|
||||
else
|
||||
r &= ~(1 << o->bit_number);
|
||||
mem_put_qi (a, r);
|
||||
break;
|
||||
|
||||
case RL78_Operand_PreDec:
|
||||
r = get_reg (o->reg);
|
||||
tprintf ("[--%s]", reg_names[o->reg]);
|
||||
if (rd->size == RL78_Word)
|
||||
{
|
||||
r -= 2;
|
||||
set_reg (o->reg, r);
|
||||
mem_put_hi (r | 0xf0000, v);
|
||||
}
|
||||
else
|
||||
{
|
||||
r -= 1;
|
||||
set_reg (o->reg, r);
|
||||
mem_put_qi (r | 0xf0000, v);
|
||||
}
|
||||
break;
|
||||
|
||||
case RL78_Operand_PostInc:
|
||||
tprintf ("[%s++]", reg_names[o->reg]);
|
||||
r = get_reg (o->reg);
|
||||
if (rd->size == RL78_Word)
|
||||
{
|
||||
mem_put_hi (r | 0xf0000, v);
|
||||
r += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
mem_put_qi (r | 0xf0000, v);
|
||||
r += 1;
|
||||
}
|
||||
set_reg (o->reg, r);
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
tprintf ("\n");
|
||||
}
|
||||
|
||||
static void
|
||||
op_flags (int before, int after, int mask, RL78_Size size)
|
||||
{
|
||||
int vmask, cmask, amask, avmask;
|
||||
|
||||
if (size == RL78_Word)
|
||||
{
|
||||
cmask = 0x10000;
|
||||
vmask = 0xffff;
|
||||
amask = 0x100;
|
||||
avmask = 0x0ff;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmask = 0x100;
|
||||
vmask = 0xff;
|
||||
amask = 0x10;
|
||||
avmask = 0x0f;
|
||||
}
|
||||
|
||||
int psw = get_reg (RL78_Reg_PSW);
|
||||
psw &= ~mask;
|
||||
|
||||
if (mask & RL78_PSW_CY)
|
||||
{
|
||||
if ((after & cmask) != (before & cmask))
|
||||
psw |= RL78_PSW_CY;
|
||||
}
|
||||
if (mask & RL78_PSW_AC)
|
||||
{
|
||||
if ((after & amask) != (before & amask)
|
||||
&& (after & avmask) < (before & avmask))
|
||||
psw |= RL78_PSW_AC;
|
||||
}
|
||||
if (mask & RL78_PSW_Z)
|
||||
{
|
||||
if (! (after & vmask))
|
||||
psw |= RL78_PSW_Z;
|
||||
}
|
||||
|
||||
set_reg (RL78_Reg_PSW, psw);
|
||||
}
|
||||
|
||||
#define FLAGS(before,after) if (opcode.flags) op_flags (before, after, opcode.flags, opcode.size)
|
||||
|
||||
#define PD(x) put_op (&opcode, 0, 1, x)
|
||||
#define PS(x) put_op (&opcode, 1, 1, x)
|
||||
#define GD() get_op (&opcode, 0, 1)
|
||||
#define GS() get_op (&opcode, 1, 1)
|
||||
|
||||
#define GPC() gpc (&opcode, 0)
|
||||
static int
|
||||
gpc (RL78_Opcode_Decoded *opcode, int idx)
|
||||
{
|
||||
int a = get_op (opcode, 0, 1);
|
||||
if (opcode->op[idx].type == RL78_Operand_Register)
|
||||
a =(a & 0x0ffff) | ((get_reg (RL78_Reg_CS) & 0x0f) << 16);
|
||||
else
|
||||
a &= 0xfffff;
|
||||
return a;
|
||||
}
|
||||
|
||||
static int
|
||||
get_carry (void)
|
||||
{
|
||||
return (get_reg (RL78_Reg_PSW) & RL78_PSW_CY) ? 1 : 0;
|
||||
}
|
||||
|
||||
static void
|
||||
set_carry (int c)
|
||||
{
|
||||
int p = get_reg (RL78_Reg_PSW);
|
||||
tprintf ("set_carry (%d)\n", c ? 1 : 0);
|
||||
if (c)
|
||||
p |= RL78_PSW_CY;
|
||||
else
|
||||
p &= ~RL78_PSW_CY;
|
||||
set_reg (RL78_Reg_PSW, p);
|
||||
}
|
||||
|
||||
/* We simulate timer TM00 in interval mode, no clearing, with
|
||||
interrupts. I.e. it's a cycle counter. */
|
||||
|
||||
unsigned int counts_per_insn[0x100000];
|
||||
|
||||
int pending_clocks = 0;
|
||||
long long total_clocks = 0;
|
||||
|
||||
#define TCR0 0xf0180
|
||||
#define MK1 0xfffe6
|
||||
static void
|
||||
process_clock_tick (void)
|
||||
{
|
||||
unsigned short cnt;
|
||||
unsigned short ivect;
|
||||
unsigned short mask;
|
||||
unsigned char psw;
|
||||
int save_trace;
|
||||
|
||||
save_trace = trace;
|
||||
trace = 0;
|
||||
|
||||
pending_clocks ++;
|
||||
|
||||
counts_per_insn[opcode_pc] += pending_clocks;
|
||||
total_clocks += pending_clocks;
|
||||
|
||||
while (pending_clocks)
|
||||
{
|
||||
pending_clocks --;
|
||||
cnt = mem_get_hi (TCR0);
|
||||
cnt --;
|
||||
mem_put_hi (TCR0, cnt);
|
||||
if (cnt != 0xffff)
|
||||
continue;
|
||||
|
||||
/* overflow. */
|
||||
psw = get_reg (RL78_Reg_PSW);
|
||||
ivect = mem_get_hi (0x0002c);
|
||||
mask = mem_get_hi (MK1);
|
||||
|
||||
if ((psw & RL78_PSW_IE)
|
||||
&& (ivect != 0)
|
||||
&& !(mask & 0x0010))
|
||||
{
|
||||
unsigned short sp = get_reg (RL78_Reg_SP);
|
||||
set_reg (RL78_Reg_SP, sp - 4);
|
||||
sp --;
|
||||
mem_put_qi (sp | 0xf0000, psw);
|
||||
sp -= 3;
|
||||
mem_put_psi (sp | 0xf0000, pc);
|
||||
psw &= ~RL78_PSW_IE;
|
||||
set_reg (RL78_Reg_PSW, psw);
|
||||
pc = ivect;
|
||||
/* Spec says 9-14 clocks */
|
||||
pending_clocks += 9;
|
||||
}
|
||||
}
|
||||
|
||||
trace = save_trace;
|
||||
}
|
||||
|
||||
void
|
||||
dump_counts_per_insn (const char * filename)
|
||||
{
|
||||
int i;
|
||||
FILE *f;
|
||||
f = fopen (filename, "w");
|
||||
if (!f)
|
||||
{
|
||||
perror (filename);
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < 0x100000; i ++)
|
||||
{
|
||||
if (counts_per_insn[i])
|
||||
fprintf (f, "%05x %d\n", i, counts_per_insn[i]);
|
||||
}
|
||||
fclose (f);
|
||||
}
|
||||
|
||||
static void
|
||||
CLOCKS (int n)
|
||||
{
|
||||
pending_clocks += n - 1;
|
||||
}
|
||||
|
||||
int
|
||||
decode_opcode (void)
|
||||
{
|
||||
RL78_Data rl78_data;
|
||||
RL78_Opcode_Decoded opcode;
|
||||
int opcode_size;
|
||||
int a, b, v, v2;
|
||||
unsigned int u, u2;
|
||||
int obits;
|
||||
|
||||
rl78_data.dpc = pc;
|
||||
opcode_size = rl78_decode_opcode (pc, &opcode,
|
||||
rl78_get_byte, &rl78_data);
|
||||
|
||||
opcode_pc = pc;
|
||||
pc += opcode_size;
|
||||
|
||||
trace_register_words = opcode.size == RL78_Word ? 1 : 0;
|
||||
|
||||
/* Used by shfit/rotate instructions */
|
||||
obits = opcode.size == RL78_Word ? 16 : 8;
|
||||
|
||||
switch (opcode.id)
|
||||
{
|
||||
case RLO_add:
|
||||
tprintf ("ADD: ");
|
||||
a = GS ();
|
||||
b = GD ();
|
||||
v = a + b;
|
||||
FLAGS (b, v);
|
||||
PD (v);
|
||||
if (opcode.op[0].type == RL78_Operand_Indirect)
|
||||
CLOCKS (2);
|
||||
break;
|
||||
|
||||
case RLO_addc:
|
||||
tprintf ("ADDC: ");
|
||||
a = GS ();
|
||||
b = GD ();
|
||||
v = a + b + get_carry ();
|
||||
FLAGS (b, v);
|
||||
PD (v);
|
||||
if (opcode.op[0].type == RL78_Operand_Indirect)
|
||||
CLOCKS (2);
|
||||
break;
|
||||
|
||||
case RLO_and:
|
||||
tprintf ("AND: ");
|
||||
a = GS ();
|
||||
b = GD ();
|
||||
v = a & b;
|
||||
FLAGS (b, v);
|
||||
PD (v);
|
||||
if (opcode.op[0].type == RL78_Operand_Indirect)
|
||||
CLOCKS (2);
|
||||
break;
|
||||
|
||||
case RLO_branch_cond:
|
||||
case RLO_branch_cond_clear:
|
||||
tprintf ("BRANCH_COND: ");
|
||||
if (!condition_true (opcode.op[1].condition, GS ()))
|
||||
{
|
||||
tprintf (" false\n");
|
||||
if (opcode.op[1].condition == RL78_Condition_T
|
||||
|| opcode.op[1].condition == RL78_Condition_F)
|
||||
CLOCKS (3);
|
||||
else
|
||||
CLOCKS (2);
|
||||
break;
|
||||
}
|
||||
if (opcode.id == RLO_branch_cond_clear)
|
||||
PS (0);
|
||||
tprintf (" ");
|
||||
if (opcode.op[1].condition == RL78_Condition_T
|
||||
|| opcode.op[1].condition == RL78_Condition_F)
|
||||
CLOCKS (3); /* note: adds two clocks, total 5 clocks */
|
||||
else
|
||||
CLOCKS (2); /* note: adds one clock, total 4 clocks */
|
||||
case RLO_branch:
|
||||
tprintf ("BRANCH: ");
|
||||
v = GPC ();
|
||||
WILD_JUMP_CHECK (v);
|
||||
pc = v;
|
||||
tprintf (" => 0x%05x\n", pc);
|
||||
CLOCKS (3);
|
||||
break;
|
||||
|
||||
case RLO_break:
|
||||
tprintf ("BRK: ");
|
||||
CLOCKS (5);
|
||||
if (rl78_in_gdb)
|
||||
DO_RETURN (RL78_MAKE_HIT_BREAK ());
|
||||
else
|
||||
DO_RETURN (RL78_MAKE_EXITED (1));
|
||||
break;
|
||||
|
||||
case RLO_call:
|
||||
tprintf ("CALL: ");
|
||||
a = get_reg (RL78_Reg_SP);
|
||||
set_reg (RL78_Reg_SP, a - 4);
|
||||
mem_put_psi ((a - 4) | 0xf0000, pc);
|
||||
v = GPC ();
|
||||
WILD_JUMP_CHECK (v);
|
||||
pc = v;
|
||||
#if 0
|
||||
/* Enable this code to dump the arguments for each call. */
|
||||
if (trace)
|
||||
{
|
||||
int i;
|
||||
skip_init ++;
|
||||
for (i = 0; i < 8; i ++)
|
||||
printf (" %02x", mem_get_qi (0xf0000 | (a + i)) & 0xff);
|
||||
skip_init --;
|
||||
}
|
||||
#endif
|
||||
tprintf ("\n");
|
||||
CLOCKS (3);
|
||||
break;
|
||||
|
||||
case RLO_cmp:
|
||||
tprintf ("CMP: ");
|
||||
a = GD ();
|
||||
b = GS ();
|
||||
v = a - b;
|
||||
FLAGS (b, v);
|
||||
tprintf (" (%d)\n", v);
|
||||
break;
|
||||
|
||||
case RLO_divhu:
|
||||
a = get_reg (RL78_Reg_AX);
|
||||
b = get_reg (RL78_Reg_DE);
|
||||
tprintf (" %d / %d = ", a, b);
|
||||
if (b == 0)
|
||||
{
|
||||
tprintf ("%d rem %d\n", 0xffff, a);
|
||||
set_reg (RL78_Reg_AX, 0xffff);
|
||||
set_reg (RL78_Reg_DE, a);
|
||||
}
|
||||
else
|
||||
{
|
||||
v = a / b;
|
||||
a = a % b;
|
||||
tprintf ("%d rem %d\n", v, a);
|
||||
set_reg (RL78_Reg_AX, v);
|
||||
set_reg (RL78_Reg_DE, a);
|
||||
}
|
||||
CLOCKS (9);
|
||||
break;
|
||||
|
||||
case RLO_divwu:
|
||||
{
|
||||
unsigned long bcax, hlde, quot, rem;
|
||||
bcax = get_reg (RL78_Reg_AX) + 65536 * get_reg (RL78_Reg_BC);
|
||||
hlde = get_reg (RL78_Reg_DE) + 65536 * get_reg (RL78_Reg_HL);
|
||||
|
||||
tprintf (" %lu / %lu = ", bcax, hlde);
|
||||
if (hlde == 0)
|
||||
{
|
||||
tprintf ("%lu rem %lu\n", 0xffffLU, bcax);
|
||||
set_reg (RL78_Reg_AX, 0xffffLU);
|
||||
set_reg (RL78_Reg_BC, 0xffffLU);
|
||||
set_reg (RL78_Reg_DE, bcax);
|
||||
set_reg (RL78_Reg_HL, bcax >> 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
quot = bcax / hlde;
|
||||
rem = bcax % hlde;
|
||||
tprintf ("%lu rem %lu\n", quot, rem);
|
||||
set_reg (RL78_Reg_AX, quot);
|
||||
set_reg (RL78_Reg_BC, quot >> 16);
|
||||
set_reg (RL78_Reg_DE, rem);
|
||||
set_reg (RL78_Reg_HL, rem >> 16);
|
||||
}
|
||||
}
|
||||
CLOCKS (17);
|
||||
break;
|
||||
|
||||
case RLO_halt:
|
||||
tprintf ("HALT.\n");
|
||||
DO_RETURN (RL78_MAKE_EXITED (get_reg (RL78_Reg_A)));
|
||||
|
||||
case RLO_mov:
|
||||
tprintf ("MOV: ");
|
||||
a = GS ();
|
||||
FLAGS (a, a);
|
||||
PD (a);
|
||||
break;
|
||||
|
||||
#define MACR 0xffff0
|
||||
case RLO_mach:
|
||||
tprintf ("MACH:");
|
||||
a = sign_ext (get_reg (RL78_Reg_AX), 16);
|
||||
b = sign_ext (get_reg (RL78_Reg_BC), 16);
|
||||
v = sign_ext (mem_get_si (MACR), 32);
|
||||
tprintf ("%08x %d + %d * %d = ", v, v, a, b);
|
||||
v2 = sign_ext (v + a * b, 32);
|
||||
tprintf ("%08x %d\n", v2, v2);
|
||||
mem_put_si (MACR, v2);
|
||||
a = get_reg (RL78_Reg_PSW);
|
||||
v ^= v2;
|
||||
if (v & (1<<31))
|
||||
a |= RL78_PSW_CY;
|
||||
else
|
||||
a &= ~RL78_PSW_CY;
|
||||
if (v2 & (1 << 31))
|
||||
a |= RL78_PSW_AC;
|
||||
else
|
||||
a &= ~RL78_PSW_AC;
|
||||
set_reg (RL78_Reg_PSW, a);
|
||||
CLOCKS (3);
|
||||
break;
|
||||
|
||||
case RLO_machu:
|
||||
tprintf ("MACHU:");
|
||||
a = get_reg (RL78_Reg_AX);
|
||||
b = get_reg (RL78_Reg_BC);
|
||||
u = mem_get_si (MACR);
|
||||
tprintf ("%08x %u + %u * %u = ", u, u, a, b);
|
||||
u2 = (u + (unsigned)a * (unsigned)b) & 0xffffffffUL;
|
||||
tprintf ("%08x %u\n", u2, u2);
|
||||
mem_put_si (MACR, u2);
|
||||
a = get_reg (RL78_Reg_PSW);
|
||||
if (u2 < u)
|
||||
a |= RL78_PSW_CY;
|
||||
else
|
||||
a &= ~RL78_PSW_CY;
|
||||
a &= ~RL78_PSW_AC;
|
||||
set_reg (RL78_Reg_PSW, a);
|
||||
CLOCKS (3);
|
||||
break;
|
||||
|
||||
case RLO_mulu:
|
||||
tprintf ("MULU:");
|
||||
a = get_reg (RL78_Reg_A);
|
||||
b = get_reg (RL78_Reg_X);
|
||||
v = a * b;
|
||||
tprintf (" %d * %d = %d\n", a, b, v);
|
||||
set_reg (RL78_Reg_AX, v);
|
||||
break;
|
||||
|
||||
case RLO_mulh:
|
||||
tprintf ("MUL:");
|
||||
a = sign_ext (get_reg (RL78_Reg_AX), 16);
|
||||
b = sign_ext (get_reg (RL78_Reg_BC), 16);
|
||||
v = a * b;
|
||||
tprintf (" %d * %d = %d\n", a, b, v);
|
||||
set_reg (RL78_Reg_BC, v >> 16);
|
||||
set_reg (RL78_Reg_AX, v);
|
||||
CLOCKS (2);
|
||||
break;
|
||||
|
||||
case RLO_mulhu:
|
||||
tprintf ("MULHU:");
|
||||
a = get_reg (RL78_Reg_AX);
|
||||
b = get_reg (RL78_Reg_BC);
|
||||
v = a * b;
|
||||
tprintf (" %d * %d = %d\n", a, b, v);
|
||||
set_reg (RL78_Reg_BC, v >> 16);
|
||||
set_reg (RL78_Reg_AX, v);
|
||||
CLOCKS (2);
|
||||
break;
|
||||
|
||||
case RLO_nop:
|
||||
tprintf ("NOP.\n");
|
||||
break;
|
||||
|
||||
case RLO_or:
|
||||
tprintf ("OR:");
|
||||
a = GS ();
|
||||
b = GD ();
|
||||
v = a | b;
|
||||
FLAGS (b, v);
|
||||
PD (v);
|
||||
if (opcode.op[0].type == RL78_Operand_Indirect)
|
||||
CLOCKS (2);
|
||||
break;
|
||||
|
||||
case RLO_ret:
|
||||
tprintf ("RET: ");
|
||||
a = get_reg (RL78_Reg_SP);
|
||||
v = mem_get_psi (a | 0xf0000);
|
||||
WILD_JUMP_CHECK (v);
|
||||
pc = v;
|
||||
set_reg (RL78_Reg_SP, a + 4);
|
||||
#if 0
|
||||
/* Enable this code to dump the return values for each return. */
|
||||
if (trace)
|
||||
{
|
||||
int i;
|
||||
skip_init ++;
|
||||
for (i = 0; i < 8; i ++)
|
||||
printf (" %02x", mem_get_qi (0xffef0 + i) & 0xff);
|
||||
skip_init --;
|
||||
}
|
||||
#endif
|
||||
tprintf ("\n");
|
||||
CLOCKS (6);
|
||||
break;
|
||||
|
||||
case RLO_reti:
|
||||
tprintf ("RETI: ");
|
||||
a = get_reg (RL78_Reg_SP);
|
||||
v = mem_get_psi (a | 0xf0000);
|
||||
WILD_JUMP_CHECK (v);
|
||||
pc = v;
|
||||
b = mem_get_qi ((a + 3) | 0xf0000);
|
||||
set_reg (RL78_Reg_PSW, b);
|
||||
set_reg (RL78_Reg_SP, a + 4);
|
||||
tprintf ("\n");
|
||||
break;
|
||||
|
||||
case RLO_rol:
|
||||
tprintf ("ROL:"); /* d <<= s */
|
||||
a = GS ();
|
||||
b = GD ();
|
||||
v = b;
|
||||
while (a --)
|
||||
{
|
||||
v = b << 1;
|
||||
v |= (b >> (obits - 1)) & 1;
|
||||
set_carry ((b >> (obits - 1)) & 1);
|
||||
b = v;
|
||||
}
|
||||
PD (v);
|
||||
break;
|
||||
|
||||
case RLO_rolc:
|
||||
tprintf ("ROLC:"); /* d <<= s */
|
||||
a = GS ();
|
||||
b = GD ();
|
||||
v = b;
|
||||
while (a --)
|
||||
{
|
||||
v = b << 1;
|
||||
v |= get_carry ();
|
||||
set_carry ((b >> (obits - 1)) & 1);
|
||||
b = v;
|
||||
}
|
||||
PD (v);
|
||||
break;
|
||||
|
||||
case RLO_ror:
|
||||
tprintf ("ROR:"); /* d >>= s */
|
||||
a = GS ();
|
||||
b = GD ();
|
||||
v = b;
|
||||
while (a --)
|
||||
{
|
||||
v = b >> 1;
|
||||
v |= (b & 1) << (obits - 1);
|
||||
set_carry (b & 1);
|
||||
b = v;
|
||||
}
|
||||
PD (v);
|
||||
break;
|
||||
|
||||
case RLO_rorc:
|
||||
tprintf ("RORC:"); /* d >>= s */
|
||||
a = GS ();
|
||||
b = GD ();
|
||||
v = b;
|
||||
while (a --)
|
||||
{
|
||||
v = b >> 1;
|
||||
v |= (get_carry () << (obits - 1));
|
||||
set_carry (b & 1);
|
||||
b = v;
|
||||
}
|
||||
PD (v);
|
||||
break;
|
||||
|
||||
case RLO_sar:
|
||||
tprintf ("SAR:"); /* d >>= s */
|
||||
a = GS ();
|
||||
b = GD ();
|
||||
v = b;
|
||||
while (a --)
|
||||
{
|
||||
v = b >> 1;
|
||||
v |= b & (1 << (obits - 1));
|
||||
set_carry (b & 1);
|
||||
b = v;
|
||||
}
|
||||
PD (v);
|
||||
break;
|
||||
|
||||
case RLO_sel:
|
||||
tprintf ("SEL:");
|
||||
a = GS ();
|
||||
b = get_reg (RL78_Reg_PSW);
|
||||
b &= ~(RL78_PSW_RBS1 | RL78_PSW_RBS0);
|
||||
if (a & 1)
|
||||
b |= RL78_PSW_RBS0;
|
||||
if (a & 2)
|
||||
b |= RL78_PSW_RBS1;
|
||||
set_reg (RL78_Reg_PSW, b);
|
||||
tprintf ("\n");
|
||||
break;
|
||||
|
||||
case RLO_shl:
|
||||
tprintf ("SHL%d:", obits); /* d <<= s */
|
||||
a = GS ();
|
||||
b = GD ();
|
||||
v = b;
|
||||
while (a --)
|
||||
{
|
||||
v = b << 1;
|
||||
tprintf ("b = 0x%x & 0x%x\n", b, 1<<(obits - 1));
|
||||
set_carry (b & (1<<(obits - 1)));
|
||||
b = v;
|
||||
}
|
||||
PD (v);
|
||||
break;
|
||||
|
||||
case RLO_shr:
|
||||
tprintf ("SHR:"); /* d >>= s */
|
||||
a = GS ();
|
||||
b = GD ();
|
||||
v = b;
|
||||
while (a --)
|
||||
{
|
||||
v = b >> 1;
|
||||
set_carry (b & 1);
|
||||
b = v;
|
||||
}
|
||||
PD (v);
|
||||
break;
|
||||
|
||||
case RLO_skip:
|
||||
tprintf ("SKIP: ");
|
||||
if (!condition_true (opcode.op[1].condition, GS ()))
|
||||
{
|
||||
tprintf (" false\n");
|
||||
break;
|
||||
}
|
||||
|
||||
rl78_data.dpc = pc;
|
||||
opcode_size = rl78_decode_opcode (pc, &opcode,
|
||||
rl78_get_byte, &rl78_data);
|
||||
pc += opcode_size;
|
||||
tprintf (" skipped: %s\n", opcode.syntax);
|
||||
break;
|
||||
|
||||
case RLO_stop:
|
||||
tprintf ("STOP.\n");
|
||||
DO_RETURN (RL78_MAKE_EXITED (get_reg (RL78_Reg_A)));
|
||||
DO_RETURN (RL78_MAKE_HIT_BREAK ());
|
||||
|
||||
case RLO_sub:
|
||||
tprintf ("SUB: ");
|
||||
a = GS ();
|
||||
b = GD ();
|
||||
v = b - a;
|
||||
FLAGS (b, v);
|
||||
PD (v);
|
||||
tprintf ("%d (0x%x) - %d (0x%x) = %d (0x%x)\n", b, b, a, a, v, v);
|
||||
if (opcode.op[0].type == RL78_Operand_Indirect)
|
||||
CLOCKS (2);
|
||||
break;
|
||||
|
||||
case RLO_subc:
|
||||
tprintf ("SUBC: ");
|
||||
a = GS ();
|
||||
b = GD ();
|
||||
v = b - a - get_carry ();
|
||||
FLAGS (b, v);
|
||||
PD (v);
|
||||
if (opcode.op[0].type == RL78_Operand_Indirect)
|
||||
CLOCKS (2);
|
||||
break;
|
||||
|
||||
case RLO_xch:
|
||||
tprintf ("XCH: ");
|
||||
a = GS ();
|
||||
b = GD ();
|
||||
PD (a);
|
||||
PS (b);
|
||||
break;
|
||||
|
||||
case RLO_xor:
|
||||
tprintf ("XOR:");
|
||||
a = GS ();
|
||||
b = GD ();
|
||||
v = a ^ b;
|
||||
FLAGS (b, v);
|
||||
PD (v);
|
||||
if (opcode.op[0].type == RL78_Operand_Indirect)
|
||||
CLOCKS (2);
|
||||
break;
|
||||
|
||||
default:
|
||||
tprintf ("Unknown opcode?\n");
|
||||
DO_RETURN (RL78_MAKE_HIT_BREAK ());
|
||||
}
|
||||
|
||||
if (timer_enabled)
|
||||
process_clock_tick ();
|
||||
|
||||
return RL78_MAKE_STEPPED ();
|
||||
}
|
343
sim/rl78/trace.c
Normal file
343
sim/rl78/trace.c
Normal file
@ -0,0 +1,343 @@
|
||||
/* trace.c --- tracing output for the RL78 simulator.
|
||||
|
||||
Copyright (C) 2005, 2007, 2008, 2009, 2010, 2011
|
||||
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 <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "libiberty.h"
|
||||
#include "bfd.h"
|
||||
#include "dis-asm.h"
|
||||
|
||||
#include "cpu.h"
|
||||
#include "mem.h"
|
||||
#include "load.h"
|
||||
|
||||
static int
|
||||
sim_dis_read (bfd_vma memaddr, bfd_byte * ptr, unsigned int length,
|
||||
struct disassemble_info *info)
|
||||
{
|
||||
mem_get_blk (memaddr, ptr, length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Filter out (in place) symbols that are useless for disassembly.
|
||||
COUNT is the number of elements in SYMBOLS.
|
||||
Return the number of useful symbols. */
|
||||
|
||||
static long
|
||||
remove_useless_symbols (asymbol ** symbols, long count)
|
||||
{
|
||||
register asymbol **in_ptr = symbols, **out_ptr = symbols;
|
||||
|
||||
while (-- count >= 0)
|
||||
{
|
||||
asymbol *sym = *in_ptr ++;
|
||||
|
||||
if (strstr (sym->name, "gcc2_compiled"))
|
||||
continue;
|
||||
if (sym->name == NULL || sym->name[0] == '\0')
|
||||
continue;
|
||||
if (sym->flags & (BSF_DEBUGGING))
|
||||
continue;
|
||||
if (bfd_is_und_section (sym->section)
|
||||
|| bfd_is_com_section (sym->section))
|
||||
continue;
|
||||
|
||||
*out_ptr++ = sym;
|
||||
}
|
||||
return out_ptr - symbols;
|
||||
}
|
||||
|
||||
static int
|
||||
compare_symbols (const PTR ap, const PTR bp)
|
||||
{
|
||||
const asymbol *a = *(const asymbol **) ap;
|
||||
const asymbol *b = *(const asymbol **) bp;
|
||||
|
||||
if (bfd_asymbol_value (a) > bfd_asymbol_value (b))
|
||||
return 1;
|
||||
else if (bfd_asymbol_value (a) < bfd_asymbol_value (b))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char opbuf[1000];
|
||||
|
||||
static int
|
||||
op_printf (char *buf, char *fmt, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list ap;
|
||||
|
||||
va_start (ap, fmt);
|
||||
ret = vsprintf (opbuf + strlen (opbuf), fmt, ap);
|
||||
va_end (ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bfd * current_bfd = NULL;
|
||||
static asymbol ** symtab = NULL;
|
||||
static int symcount = 0;
|
||||
static asection * code_section = NULL;
|
||||
static bfd_vma code_base = 0;
|
||||
static struct disassemble_info info;
|
||||
|
||||
void
|
||||
sim_disasm_init (bfd *prog)
|
||||
{
|
||||
current_bfd = prog;
|
||||
}
|
||||
|
||||
typedef struct Files
|
||||
{
|
||||
struct Files *next;
|
||||
char *filename;
|
||||
int nlines;
|
||||
char **lines;
|
||||
char *data;
|
||||
} Files;
|
||||
Files *files = 0;
|
||||
|
||||
static char *
|
||||
load_file_and_line (const char *filename, int lineno)
|
||||
{
|
||||
Files *f;
|
||||
for (f = files; f; f = f->next)
|
||||
if (strcmp (f->filename, filename) == 0)
|
||||
break;
|
||||
if (!f)
|
||||
{
|
||||
int i;
|
||||
struct stat s;
|
||||
const char *found_filename, *slash;
|
||||
|
||||
found_filename = filename;
|
||||
while (1)
|
||||
{
|
||||
if (stat (found_filename, &s) == 0)
|
||||
break;
|
||||
slash = strchr (found_filename, '/');
|
||||
if (!slash)
|
||||
return "";
|
||||
found_filename = slash + 1;
|
||||
}
|
||||
|
||||
f = (Files *) xmalloc (sizeof (Files));
|
||||
f->next = files;
|
||||
files = f;
|
||||
f->filename = xstrdup (filename);
|
||||
f->data = (char *) xmalloc (s.st_size + 2);
|
||||
FILE *file = fopen (found_filename, "rb");
|
||||
fread (f->data, 1, s.st_size, file);
|
||||
f->data[s.st_size] = 0;
|
||||
fclose (file);
|
||||
|
||||
f->nlines = 1;
|
||||
for (i = 0; i < s.st_size; i ++)
|
||||
if (f->data[i] == '\n')
|
||||
f->nlines ++;
|
||||
f->lines = (char **) xmalloc (f->nlines * sizeof (char *));
|
||||
f->lines[0] = f->data;
|
||||
f->nlines = 1;
|
||||
for (i = 0; i < s.st_size; i ++)
|
||||
if (f->data[i] == '\n')
|
||||
{
|
||||
f->lines[f->nlines] = f->data + i + 1;
|
||||
while (*f->lines[f->nlines] == ' '
|
||||
|| *f->lines[f->nlines] == '\t')
|
||||
f->lines[f->nlines] ++;
|
||||
f->nlines ++;
|
||||
f->data[i] = 0;
|
||||
}
|
||||
}
|
||||
if (lineno < 1 || lineno > f->nlines)
|
||||
return "";
|
||||
return f->lines[lineno - 1];
|
||||
}
|
||||
|
||||
int
|
||||
sim_get_current_source_location (const char ** pfilename,
|
||||
const char ** pfunctionname,
|
||||
unsigned int * plineno)
|
||||
{
|
||||
static int initted = 0;
|
||||
int mypc = pc;
|
||||
|
||||
if (current_bfd == NULL)
|
||||
return 0;
|
||||
|
||||
if (!initted)
|
||||
{
|
||||
int storage;
|
||||
asection * s;
|
||||
|
||||
initted = 1;
|
||||
memset (& info, 0, sizeof (info));
|
||||
INIT_DISASSEMBLE_INFO (info, stdout, op_printf);
|
||||
info.read_memory_func = sim_dis_read;
|
||||
info.arch = bfd_get_arch (current_bfd);
|
||||
info.mach = bfd_get_mach (current_bfd);
|
||||
if (info.mach == 0)
|
||||
info.arch = bfd_arch_rl78;
|
||||
|
||||
disassemble_init_for_target (& info);
|
||||
|
||||
storage = bfd_get_symtab_upper_bound (current_bfd);
|
||||
if (storage > 0)
|
||||
{
|
||||
symtab = (asymbol **) xmalloc (storage);
|
||||
symcount = bfd_canonicalize_symtab (current_bfd, symtab);
|
||||
symcount = remove_useless_symbols (symtab, symcount);
|
||||
qsort (symtab, symcount, sizeof (asymbol *), compare_symbols);
|
||||
}
|
||||
|
||||
for (s = current_bfd->sections; s; s = s->next)
|
||||
{
|
||||
if (s->flags & SEC_CODE || code_section == 0)
|
||||
{
|
||||
code_section = s;
|
||||
code_base = bfd_section_lma (current_bfd, s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*pfilename = *pfunctionname = NULL;
|
||||
*plineno = 0;
|
||||
|
||||
bfd_find_nearest_line
|
||||
(current_bfd, code_section, symtab, mypc - code_base,
|
||||
pfilename, pfunctionname, plineno);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
sim_disasm_one (void)
|
||||
{
|
||||
static int last_sym = -1;
|
||||
static const char * prev_filename = "";
|
||||
static int prev_lineno = 0;
|
||||
const char * filename;
|
||||
const char * functionname;
|
||||
unsigned int lineno;
|
||||
int sym, bestaddr;
|
||||
int min, max, i;
|
||||
int save_trace = trace;
|
||||
int mypc = pc;
|
||||
|
||||
if (! sim_get_current_source_location (& filename, & functionname, & lineno))
|
||||
return;
|
||||
|
||||
trace = 0;
|
||||
|
||||
if (filename && functionname && lineno)
|
||||
{
|
||||
if (lineno != prev_lineno || strcmp (prev_filename, filename))
|
||||
{
|
||||
char * the_line = load_file_and_line (filename, lineno);
|
||||
const char * slash = strrchr (filename, '/');
|
||||
|
||||
if (!slash)
|
||||
slash = filename;
|
||||
else
|
||||
slash ++;
|
||||
printf
|
||||
("========================================"
|
||||
"=====================================\n");
|
||||
printf ("\033[37;41m %s:%d: \033[33;40m %s\033[K\033[0m\n",
|
||||
slash, lineno, the_line);
|
||||
}
|
||||
prev_lineno = lineno;
|
||||
prev_filename = filename;
|
||||
}
|
||||
|
||||
min = -1;
|
||||
max = symcount;
|
||||
while (min < max - 1)
|
||||
{
|
||||
bfd_vma sa;
|
||||
|
||||
sym = (min + max) / 2;
|
||||
sa = bfd_asymbol_value (symtab[sym]);
|
||||
/*printf ("checking %4d %08x %s\n",
|
||||
sym, sa, bfd_asymbol_name (symtab[sym])); */
|
||||
if (sa > mypc)
|
||||
max = sym;
|
||||
else if (sa < mypc)
|
||||
min = sym;
|
||||
else
|
||||
{
|
||||
min = sym;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (min != -1 && min != last_sym)
|
||||
{
|
||||
bestaddr = bfd_asymbol_value (symtab[min]);
|
||||
printf ("\033[43;30m%s", bfd_asymbol_name (symtab[min]));
|
||||
if (bestaddr != mypc)
|
||||
printf ("+%d", mypc - bestaddr);
|
||||
printf (":\t\t\t\033[0m\n");
|
||||
last_sym = min;
|
||||
#if 0
|
||||
if (trace == 1)
|
||||
if (strcmp (bfd_asymbol_name (symtab[min]), "abort") == 0
|
||||
|| strcmp (bfd_asymbol_name (symtab[min]), "exit") == 0)
|
||||
trace = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define TCR0 0xf0180
|
||||
|
||||
opbuf[0] = 0;
|
||||
#ifdef CYCLE_ACCURATE
|
||||
printf ("\033[33m %04u %06x: ", (int)(regs.cycle_count % 10000), mypc);
|
||||
#else
|
||||
printf ("\033[33m %08llx %06x: ", total_clocks, mypc);
|
||||
#endif
|
||||
|
||||
max = print_insn_rl78 (mypc, & info);
|
||||
|
||||
for (i = 0; i < max; i ++)
|
||||
printf ("%02x", mem_get_qi (mypc + i));
|
||||
|
||||
do
|
||||
{
|
||||
printf (" ");
|
||||
i ++;
|
||||
}
|
||||
while (i < 6);
|
||||
|
||||
printf ("%-16s ", opbuf);
|
||||
|
||||
printf ("\033[0m\n");
|
||||
trace = save_trace;
|
||||
}
|
29
sim/rl78/trace.h
Normal file
29
sim/rl78/trace.h
Normal file
@ -0,0 +1,29 @@
|
||||
/* trace.h --- interface to tracing output for the RX simulator.
|
||||
|
||||
Copyright (C) 2005, 2007, 2008, 2009, 2010, 2011
|
||||
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/>. */
|
||||
|
||||
#ifndef SIM_RL78_TRACE_H_
|
||||
#define SIM_RL78_TRACE_H_
|
||||
|
||||
extern void sim_disasm_init (bfd *);
|
||||
extern void sim_disasm_one (void);
|
||||
extern int sim_get_current_source_location (const char **, const char **, unsigned int *);
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user