From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 24951 invoked by alias); 17 Nov 2011 21:34:15 -0000 Received: (qmail 23563 invoked by uid 22791); 17 Nov 2011 21:34:07 -0000 X-SWARE-Spam-Status: No, hits=-2.8 required=5.0 tests=AWL,BAYES_00,KAM_MX3,RCVD_IN_DNSWL_HI,RP_MATCHES_RCVD,SPF_HELO_PASS,TW_CP,TW_GJ,TW_TJ,TW_XF,TW_YP,URIBL_BLACK X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 17 Nov 2011 21:33:38 +0000 Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id pAHLXZ38005097 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Thu, 17 Nov 2011 16:33:35 -0500 Received: from greed.delorie.com ([10.3.113.11]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id pAHLXXM0005671 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Thu, 17 Nov 2011 16:33:34 -0500 Received: from greed.delorie.com (greed.delorie.com [127.0.0.1]) by greed.delorie.com (8.14.4/8.14.4) with ESMTP id pAHLXXS1008695; Thu, 17 Nov 2011 16:33:33 -0500 Received: (from dj@localhost) by greed.delorie.com (8.14.4/8.14.4/Submit) id pAHLXWBV008694; Thu, 17 Nov 2011 16:33:32 -0500 Date: Thu, 17 Nov 2011 21:34:00 -0000 Message-Id: <201111172133.pAHLXWBV008694@greed.delorie.com> From: DJ Delorie To: Mike Frysinger CC: gdb-patches@sourceware.org In-reply-to: <201111171452.49448.vapier@gentoo.org> (message from Mike Frysinger on Thu, 17 Nov 2011 14:52:48 -0500) Subject: Re: [sim] new port: Renesas RL78 References: <201111160606.pAG66U4p017015@greed.delorie.com> <201111171439.01278.vapier@gentoo.org> <201111171947.pAHJlsYD005315@greed.delorie.com> <201111171452.49448.vapier@gentoo.org> X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2011-11/txt/msg00488.txt.bz2 I think I got all the spacing issues... assuming I didn't miss a regex or something. Index: sim/configure.tgt =================================================================== RCS file: /cvs/src/src/sim/configure.tgt,v retrieving revision 1.4 diff -p -U5 -r1.4 sim/configure.tgt --- sim/configure.tgt 4 Jun 2011 17:44:20 -0000 1.4 +++ sim/configure.tgt 17 Nov 2011 21:31:46 -0000 @@ -84,10 +84,13 @@ case "${target}" in ;; moxie-*-*) SIM_ARCH(moxie) sim_testsuite=yes ;; + rl78-*-*) + SIM_ARCH(rl78) + ;; rx-*-*) SIM_ARCH(rx) ;; sh64*-*-*) SIM_ARCH(sh64) Index: sim/rl78/Makefile.in =================================================================== RCS file: sim/rl78/Makefile.in diff -N sim/rl78/Makefile.in --- sim/rl78/Makefile.in 1 Jan 1970 00:00:00 -0000 +++ sim/rl78/Makefile.in 17 Nov 2011 21:31:47 -0000 @@ -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 Index: sim/rl78/config.in =================================================================== RCS file: sim/rl78/config.in diff -N sim/rl78/config.in --- sim/rl78/config.in 1 Jan 1970 00:00:00 -0000 +++ sim/rl78/config.in 17 Nov 2011 21:31:47 -0000 @@ -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 header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ERRNO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FPU_CONTROL_H + +/* Define to 1 if you have the 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 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 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 header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_RESOURCE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the 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 header file. */ +#undef HAVE_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the 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 Index: sim/rl78/configure.ac =================================================================== RCS file: sim/rl78/configure.ac diff -N sim/rl78/configure.ac --- sim/rl78/configure.ac 1 Jan 1970 00:00:00 -0000 +++ sim/rl78/configure.ac 17 Nov 2011 21:31:48 -0000 @@ -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 . +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 Index: sim/rl78/cpu.c =================================================================== RCS file: sim/rl78/cpu.c diff -N sim/rl78/cpu.c --- sim/rl78/cpu.c 1 Jan 1970 00:00:00 -0000 +++ sim/rl78/cpu.c 17 Nov 2011 21:31:48 -0000 @@ -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 . +*/ + +#include "config.h" +#include +#include +#include + +#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); +} Index: sim/rl78/cpu.h =================================================================== RCS file: sim/rl78/cpu.h diff -N sim/rl78/cpu.h --- sim/rl78/cpu.h 1 Jan 1970 00:00:00 -0000 +++ sim/rl78/cpu.h 17 Nov 2011 21:31:48 -0000 @@ -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 . +*/ + +#ifndef SIM_RL78_CPU_H_ +#define SIM_RL78_CPU_H_ + +#include +#include + +#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 Index: sim/rl78/load.c =================================================================== RCS file: sim/rl78/load.c diff -N sim/rl78/load.c --- sim/rl78/load.c 1 Jan 1970 00:00:00 -0000 +++ sim/rl78/load.c 17 Nov 2011 21:31:48 -0000 @@ -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 . +*/ + + +#include "config.h" +#include +#include +#include + +#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); +} Index: sim/rl78/load.h =================================================================== RCS file: sim/rl78/load.h diff -N sim/rl78/load.h --- sim/rl78/load.h 1 Jan 1970 00:00:00 -0000 +++ sim/rl78/load.h 17 Nov 2011 21:31:48 -0000 @@ -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 . +*/ + +#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 Index: sim/rl78/main.c =================================================================== RCS file: sim/rl78/main.c diff -N sim/rl78/main.c --- sim/rl78/main.c 1 Jan 1970 00:00:00 -0000 +++ sim/rl78/main.c 17 Nov 2011 21:31:48 -0000 @@ -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 . +*/ + + +#include "config.h" +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include +#ifdef HAVE_GETOPT_H +#include +#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 \t- ram size.\n" + "\t-D \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); +} Index: sim/rl78/mem.c =================================================================== RCS file: sim/rl78/mem.c diff -N sim/rl78/mem.c --- sim/rl78/mem.c 1 Jan 1970 00:00:00 -0000 +++ sim/rl78/mem.c 17 Nov 2011 21:31:48 -0000 @@ -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 . +*/ + +#include "config.h" +#include +#include +#include + +#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; +} Index: sim/rl78/mem.h =================================================================== RCS file: sim/rl78/mem.h diff -N sim/rl78/mem.h --- sim/rl78/mem.h 1 Jan 1970 00:00:00 -0000 +++ sim/rl78/mem.h 17 Nov 2011 21:31:48 -0000 @@ -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 . +*/ + +#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 Index: sim/rl78/rl78.c =================================================================== RCS file: sim/rl78/rl78.c diff -N sim/rl78/rl78.c --- sim/rl78/rl78.c 1 Jan 1970 00:00:00 -0000 +++ sim/rl78/rl78.c 17 Nov 2011 21:31:48 -0000 @@ -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 . +*/ + +#include "config.h" +#include +#include +#include +#include +#include +#include + +#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 (); +} Index: sim/rl78/trace.c =================================================================== RCS file: sim/rl78/trace.c diff -N sim/rl78/trace.c --- sim/rl78/trace.c 1 Jan 1970 00:00:00 -0000 +++ sim/rl78/trace.c 17 Nov 2011 21:31:48 -0000 @@ -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 . +*/ + + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include + +#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; +} Index: sim/rl78/trace.h =================================================================== RCS file: sim/rl78/trace.h diff -N sim/rl78/trace.h --- sim/rl78/trace.h 1 Jan 1970 00:00:00 -0000 +++ sim/rl78/trace.h 17 Nov 2011 21:31:48 -0000 @@ -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 . */ + +#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