# 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
