322 lines
6.3 KiB
Text
322 lines
6.3 KiB
Text
|
# This shell script emits C code. -*- C -*-
|
||
|
# Main loop and support routines for the M32R.
|
||
|
# Copyright (C) 1996, 1997 Free Software Foundation, Inc.
|
||
|
# Contributed by Cygnus Support.
|
||
|
#
|
||
|
# This file is part of GDB, the GNU debugger.
|
||
|
#
|
||
|
# This program is free software; you can redistribute it and/or modify
|
||
|
# it under the terms of the GNU General Public License as published by
|
||
|
# the Free Software Foundation; either version 2, or (at your option)
|
||
|
# any later version.
|
||
|
#
|
||
|
# This program is distributed in the hope that it will be useful,
|
||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
# GNU General Public License for more details.
|
||
|
#
|
||
|
# You should have received a copy of the GNU General Public License along
|
||
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||
|
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||
|
|
||
|
# Syntax:
|
||
|
# /bin/sh mainloop.in {init|normal|fast|support}
|
||
|
|
||
|
# ??? There's lots of conditional compilation here.
|
||
|
# After a few more ports are done, revisit.
|
||
|
|
||
|
case "x$1" in
|
||
|
|
||
|
xinit)
|
||
|
|
||
|
cat <<EOF
|
||
|
#if defined (WITH_SCACHE) && defined (USE_SEM_SWITCH) && defined (__GNUC__)
|
||
|
{
|
||
|
static decode_init_p = 0;
|
||
|
if (! decode_init_p)
|
||
|
{
|
||
|
/* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
|
||
|
#define DEFINE_LABELS
|
||
|
#include "sem-switch.c"
|
||
|
decode_init_p = 1;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
EOF
|
||
|
|
||
|
;;
|
||
|
|
||
|
xnormal | xfast)
|
||
|
|
||
|
cat <<EOF
|
||
|
|
||
|
#if WITH_SCACHE
|
||
|
|
||
|
{
|
||
|
int hash;
|
||
|
SCACHE *sc;
|
||
|
|
||
|
/* First step: look up current insn in hash table. */
|
||
|
hash = SCACHE_HASH_PC (sd, PC);
|
||
|
sc = CPU_SCACHE_CACHE (current_cpu) + hash;
|
||
|
|
||
|
/* If the entry isn't the one we want (cache miss),
|
||
|
fetch and decode the instruction. */
|
||
|
if (sc->argbuf.addr != PC)
|
||
|
{
|
||
|
PCADDR pc = PC;
|
||
|
insn_t insn;
|
||
|
|
||
|
#if ! FAST
|
||
|
PROFILE_COUNT_SCACHE_MISS (current_cpu);
|
||
|
#endif
|
||
|
|
||
|
/* This only occurs when single stepping.
|
||
|
The test is unnecessary otherwise, but the cost is teensy,
|
||
|
compared with decoding/extraction. */
|
||
|
if (pc & 3)
|
||
|
{
|
||
|
insn = GETMEMUHI (current_cpu, pc);
|
||
|
do_extract_insn16 (current_cpu, pc, insn & 0x7fff, sc, FAST);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
insn = GETMEMUSI (current_cpu, pc);
|
||
|
|
||
|
if (insn & 0x80000000)
|
||
|
{
|
||
|
do_extract_insn32 (current_cpu, pc, insn, sc, FAST);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* 2 16 bit insns. Ignore parallel case for now
|
||
|
(2nd always nop). Decode both as we know there's room.
|
||
|
??? Could do a test for an unconditional branch in the
|
||
|
left slot if one wanted to. */
|
||
|
do_extract_insn16 (current_cpu, pc, insn >> 16, sc, FAST);
|
||
|
do_extract_insn16 (current_cpu, pc + 2, insn & 0x7fff, sc + 1, FAST);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#if ! FAST
|
||
|
else
|
||
|
{
|
||
|
PROFILE_COUNT_SCACHE_HIT (current_cpu);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if 0 /*FIXME:wip*/
|
||
|
|
||
|
/* Run until we get a cache miss. */
|
||
|
do
|
||
|
{
|
||
|
#if ! FAST
|
||
|
TRACE_INSN_INIT (current_cpu);
|
||
|
TRACE_INSN (current_cpu, sc->argbuf.opcode, &sc->argbuf, sc->argbuf.addr);
|
||
|
#endif
|
||
|
|
||
|
sc = (*sc->semantic.sem_fn) (current_cpu, sc);
|
||
|
|
||
|
#if ! FAST
|
||
|
TRACE_INSN_FINI (current_cpu);
|
||
|
#endif
|
||
|
}
|
||
|
while (sc->argbuf.addr == PC);
|
||
|
|
||
|
#if ! FAST
|
||
|
PROFILE_COUNT_INSN (current_cpu, pc, CGEN_INSN_INDEX (sc->argbuf.opcode));
|
||
|
#endif
|
||
|
|
||
|
#else /* !wip */
|
||
|
|
||
|
#if ! FAST
|
||
|
TRACE_INSN_INIT (current_cpu);
|
||
|
TRACE_INSN (current_cpu, sc->argbuf.opcode, &sc->argbuf, sc->argbuf.addr);
|
||
|
#endif
|
||
|
|
||
|
#if FAST && defined (USE_SEM_SWITCH)
|
||
|
#define DEFINE_SWITCH
|
||
|
#include "sem-switch.c"
|
||
|
#else
|
||
|
PC = (*sc->semantic.sem_fn) (current_cpu, sc);
|
||
|
#endif
|
||
|
|
||
|
#if ! FAST
|
||
|
TRACE_INSN_FINI (current_cpu);
|
||
|
|
||
|
PROFILE_COUNT_INSN (current_cpu, pc, CGEN_INSN_INDEX (sc->argbuf.opcode));
|
||
|
#endif
|
||
|
|
||
|
#endif /* !wip */
|
||
|
}
|
||
|
|
||
|
#else /* ! WITH_SCACHE */
|
||
|
|
||
|
{
|
||
|
insn_t insn;
|
||
|
|
||
|
if (PC & 3)
|
||
|
{
|
||
|
insn = GETMEMUHI (current_cpu, PC);
|
||
|
PC = do_insn16 (current_cpu, PC, insn & 0x7fff);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
insn = GETMEMUSI (current_cpu, PC);
|
||
|
|
||
|
if (insn & 0x80000000)
|
||
|
{
|
||
|
/* 32 bit insn */
|
||
|
PC = do_insn32 (current_cpu, PC, insn);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* 2 16 bit insns. Ignore parallel case for now
|
||
|
(2nd always nop). */
|
||
|
|
||
|
PCADDR oldpc = PC;
|
||
|
PC = do_insn16 (current_cpu, PC, insn >> 16);
|
||
|
if (PC == oldpc + 2)
|
||
|
{
|
||
|
PC = do_insn16 (current_cpu, PC, insn & 0x7fff);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif /* ! WITH_SCACHE */
|
||
|
|
||
|
EOF
|
||
|
|
||
|
;;
|
||
|
|
||
|
xsupport)
|
||
|
|
||
|
cat <<EOF
|
||
|
|
||
|
#if WITH_SCACHE
|
||
|
|
||
|
#ifdef __GNUC__
|
||
|
#define DO_INLINE inline
|
||
|
#else
|
||
|
#define DO_INLINE
|
||
|
#endif
|
||
|
|
||
|
/* FAST is optimized out by GCC. */
|
||
|
|
||
|
static DO_INLINE void
|
||
|
do_extract_insn16 (SIM_CPU *cpu, PCADDR pc, insn_t insn,
|
||
|
SCACHE *sc, int fast)
|
||
|
{
|
||
|
DECODE *d = decode (insn);
|
||
|
(*d->extract) (cpu, pc, insn, &sc->argbuf);
|
||
|
if (fast)
|
||
|
{
|
||
|
#ifdef USE_SEM_SWITCH
|
||
|
#ifdef __GNUC__
|
||
|
sc->semantic.sem_case = d->semantic_lab;
|
||
|
#else
|
||
|
sc->semantic.sem_case = d->insn_type;
|
||
|
#endif
|
||
|
#else
|
||
|
sc->semantic.sem_fn = d->semantic_fast;
|
||
|
#endif
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sc->semantic.sem_fn = d->semantic_fast;
|
||
|
sc->argbuf.opcode = d->opcode;
|
||
|
}
|
||
|
sc->next = pc + 2;
|
||
|
}
|
||
|
|
||
|
static DO_INLINE void
|
||
|
do_extract_insn32 (SIM_CPU *cpu, PCADDR pc, insn_t insn,
|
||
|
SCACHE *sc, int fast)
|
||
|
{
|
||
|
/* 32 bit insn */
|
||
|
DECODE *d = decode (insn >> 16);
|
||
|
(*d->extract) (cpu, pc, insn, &sc->argbuf);
|
||
|
if (fast)
|
||
|
{
|
||
|
#ifdef USE_SEM_SWITCH
|
||
|
#ifdef __GNUC__
|
||
|
sc->semantic.sem_case = d->semantic_lab;
|
||
|
#else
|
||
|
sc->semantic.sem_case = d->insn_type;
|
||
|
#endif
|
||
|
#else
|
||
|
sc->semantic.sem_fn = d->semantic_fast;
|
||
|
#endif
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sc->semantic.sem_fn = d->semantic_fast;
|
||
|
sc->argbuf.opcode = d->opcode;
|
||
|
}
|
||
|
sc->next = pc + 4;
|
||
|
}
|
||
|
|
||
|
#endif /* WITH_SCACHE */
|
||
|
|
||
|
static PCADDR
|
||
|
do_insn16 (cpu, pc, insn)
|
||
|
SIM_CPU *cpu;
|
||
|
PCADDR pc;
|
||
|
insn_t insn;
|
||
|
{
|
||
|
DECODE *d;
|
||
|
ARGBUF argbuf;
|
||
|
|
||
|
d = decode (insn);
|
||
|
(*d->extract) (cpu, pc, insn, &argbuf);
|
||
|
argbuf.opcode = d->opcode;
|
||
|
|
||
|
TRACE_INSN_INIT (cpu);
|
||
|
TRACE_INSN (cpu, d->opcode, &argbuf, pc);
|
||
|
|
||
|
pc = (*d->semantic) (cpu, &argbuf);
|
||
|
|
||
|
TRACE_INSN_FINI (cpu);
|
||
|
|
||
|
PROFILE_COUNT_INSN (cpu, pc, d->insn_type);
|
||
|
|
||
|
return pc;
|
||
|
}
|
||
|
|
||
|
static PCADDR
|
||
|
do_insn32 (cpu, pc, insn)
|
||
|
SIM_CPU *cpu;
|
||
|
PCADDR pc;
|
||
|
insn_t insn;
|
||
|
{
|
||
|
DECODE *d;
|
||
|
ARGBUF argbuf;
|
||
|
|
||
|
d = decode (insn >> 16);
|
||
|
(*d->extract) (cpu, pc, insn, &argbuf);
|
||
|
argbuf.opcode = d->opcode;
|
||
|
|
||
|
TRACE_INSN_INIT (cpu);
|
||
|
TRACE_INSN (cpu, d->opcode, &argbuf, pc);
|
||
|
|
||
|
pc = (*d->semantic) (cpu, &argbuf);
|
||
|
|
||
|
TRACE_INSN_FINI (cpu);
|
||
|
|
||
|
PROFILE_COUNT_INSN (cpu, pc, d->insn_type);
|
||
|
|
||
|
return pc;
|
||
|
}
|
||
|
|
||
|
EOF
|
||
|
|
||
|
;;
|
||
|
|
||
|
*)
|
||
|
echo "Invalid argument to mainloop.in: $1" >&2
|
||
|
exit 1
|
||
|
;;
|
||
|
|
||
|
esac
|