OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [or1ksim/] [cpu/] [or32/] [execute.c] - Diff between revs 19 and 82

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 19 Rev 82
/* execute.c -- OR1K architecture dependent simulation
/* execute.c -- OR1K architecture dependent simulation
 
 
   Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
   Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
   Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org
   Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org
   Copyright (C) 2008 Embecosm Limited
   Copyright (C) 2008 Embecosm Limited
 
 
   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
 
   This file is part of OpenRISC 1000 Architectural Simulator.
   This file is part of OpenRISC 1000 Architectural Simulator.
 
 
   This program is free software; you can redistribute it and/or modify it
   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
   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)
   Software Foundation; either version 3 of the License, or (at your option)
   any later version.
   any later version.
 
 
   This program is distributed in the hope that it will be useful, but WITHOUT
   This program is distributed in the hope that it will be useful, but WITHOUT
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   more details.
   more details.
 
 
   You should have received a copy of the GNU General Public License along
   You should have received a copy of the GNU General Public License along
   with this program.  If not, see <http://www.gnu.org/licenses/>. */
   with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 
/* This program is commented throughout in a fashion suitable for processing
/* This program is commented throughout in a fashion suitable for processing
   with Doxygen. */
   with Doxygen. */
 
 
 
 
/* Most of the OR1K simulation is done in here.
/* Most of the OR1K simulation is done in here.
 
 
   When SIMPLE_EXECUTION is defined below a file insnset.c is included!
   When SIMPLE_EXECUTION is defined below a file insnset.c is included!
*/
*/
 
 
/* Autoconf and/or portability configuration */
/* Autoconf and/or portability configuration */
#include "config.h"
#include "config.h"
#include "port.h"
#include "port.h"
 
 
/* System includes */
/* System includes */
#include <stdlib.h>
#include <stdlib.h>
 
 
/* Package includes */
/* Package includes */
#include "execute.h"
#include "execute.h"
#include "toplevel-support.h"
#include "toplevel-support.h"
#include "except.h"
#include "except.h"
#include "labels.h"
#include "labels.h"
#include "gdbcomm.h"
#include "gdbcomm.h"
#include "sched.h"
#include "sched.h"
#include "stats.h"
#include "stats.h"
#include "opcode/or32.h"
#include "opcode/or32.h"
#include "dmmu.h"
#include "dmmu.h"
#include "immu.h"
#include "immu.h"
#include "sim-cmd.h"
#include "sim-cmd.h"
#include "vapi.h"
#include "vapi.h"
#include "debug-unit.h"
#include "debug-unit.h"
#include "branch-predict.h"
#include "branch-predict.h"
#include "support/simprintf.h"
 
#include "sprs.h"
#include "sprs.h"
#include "rsp-server.h"
#include "rsp-server.h"
 
 
 
 
/* Includes and macros for simple execution */
/* Includes and macros for simple execution */
#if SIMPLE_EXECUTION
#if SIMPLE_EXECUTION
 
 
#define SET_PARAM0(val) set_operand(0, val, current->insn_index, current->insn)
#define SET_PARAM0(val) set_operand(0, val, current->insn_index, current->insn)
 
 
#define PARAM0 eval_operand(0, current->insn_index, current->insn)
#define PARAM0 eval_operand(0, current->insn_index, current->insn)
#define PARAM1 eval_operand(1, current->insn_index, current->insn)
#define PARAM1 eval_operand(1, current->insn_index, current->insn)
#define PARAM2 eval_operand(2, current->insn_index, current->insn)
#define PARAM2 eval_operand(2, current->insn_index, current->insn)
 
 
#define INSTRUCTION(name) void name (struct iqueue_entry *current)
#define INSTRUCTION(name) void name (struct iqueue_entry *current)
 
 
#endif  /* SIMPLE_EXECUTION */
#endif  /* SIMPLE_EXECUTION */
 
 
 
 
/*! Current cpu state. Globally available. */
/*! Current cpu state. Globally available. */
struct cpu_state  cpu_state;
struct cpu_state  cpu_state;
 
 
/*! Temporary program counter. Globally available */
/*! Temporary program counter. Globally available */
oraddr_t  pcnext;
oraddr_t  pcnext;
 
 
/*! Num cycles waiting for stores to complete. Globally available */
/*! Num cycles waiting for stores to complete. Globally available */
int  sbuf_wait_cyc = 0;
int  sbuf_wait_cyc = 0;
 
 
/*! Number of total store cycles. Globally available */
/*! Number of total store cycles. Globally available */
int  sbuf_total_cyc = 0;
int  sbuf_total_cyc = 0;
 
 
/*! Whether we are doing statistical analysis. Globally available */
/*! Whether we are doing statistical analysis. Globally available */
int  do_stats = 0;
int  do_stats = 0;
 
 
/*! History of execution. Globally available */
/*! History of execution. Globally available */
struct hist_exec *hist_exec_tail = NULL;
struct hist_exec *hist_exec_tail = NULL;
 
 
/* Benchmark multi issue execution. This file only */
/* Benchmark multi issue execution. This file only */
static int  multissue[20];
static int  multissue[20];
static int  issued_per_cycle = 4;
static int  issued_per_cycle = 4;
 
 
/* Store buffer analysis - stores are accumulated and commited when IO is
/* Store buffer analysis - stores are accumulated and commited when IO is
   idle. This file only */
   idle. This file only */
static int  sbuf_head              = 0;
static int  sbuf_head              = 0;
static int  sbuf_tail              = 0;
static int  sbuf_tail              = 0;
static int  sbuf_count             = 0;
static int  sbuf_count             = 0;
#if !(DYNAMIC_EXECUTION)
#if !(DYNAMIC_EXECUTION)
static int  sbuf_buf[MAX_SBUF_LEN] = { 0 };
static int  sbuf_buf[MAX_SBUF_LEN] = { 0 };
#endif
#endif
 
 
static int sbuf_prev_cycles = 0;
static int sbuf_prev_cycles = 0;
 
 
/* Variables used throughout this file to share information */
/* Variables used throughout this file to share information */
static int  breakpoint;
static int  breakpoint;
static int  next_delay_insn;
static int  next_delay_insn;
 
 
/* Forward declaration of static functions */
/* Forward declaration of static functions */
#if !(DYNAMIC_EXECUTION)
#if !(DYNAMIC_EXECUTION)
static void decode_execute (struct iqueue_entry *current);
static void decode_execute (struct iqueue_entry *current);
#endif
#endif
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Get an actual value of a specific register
/*!Get an actual value of a specific register
 
 
   Implementation specific. Abort if we are given a duff register. Only used
   Implementation specific. Abort if we are given a duff register. Only used
   externally to support simprintf().
   externally to support simprintf(), which is now obsolete.
 
 
   @param[in] regno  The register of interest
   @param[in] regno  The register of interest
 
 
   @return  The value of the register                                        */
   @return  The value of the register                                        */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
uorreg_t
uorreg_t
evalsim_reg (unsigned int  regno)
evalsim_reg (unsigned int  regno)
{
{
  if (regno < MAX_GPRS)
  if (regno < MAX_GPRS)
    {
    {
#if RAW_RANGE_STATS
#if RAW_RANGE_STATS
      int delta = (runtime.sim.cycles - raw_stats.reg[regno]);
      int delta = (runtime.sim.cycles - raw_stats.reg[regno]);
 
 
      if ((unsigned long) delta < (unsigned long) RAW_RANGE)
      if ((unsigned long) delta < (unsigned long) RAW_RANGE)
        {
        {
          raw_stats.range[delta]++;
          raw_stats.range[delta]++;
        }
        }
#endif /* RAW_RANGE */
#endif /* RAW_RANGE */
 
 
      return cpu_state.reg[regno];
      return cpu_state.reg[regno];
    }
    }
  else
  else
    {
    {
      PRINTF ("\nABORT: read out of registers\n");
      PRINTF ("\nABORT: read out of registers\n");
      sim_done ();
      sim_done ();
      return 0;
      return 0;
    }
    }
}       /* evalsim_reg() */
}       /* evalsim_reg() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Set a specific register with value
/*!Set a specific register with value
 
 
   Implementation specific. Abort if we are given a duff register.
   Implementation specific. Abort if we are given a duff register.
 
 
   @param[in] regno  The register of interest
   @param[in] regno  The register of interest
   @param[in] value  The value to be set                                     */
   @param[in] value  The value to be set                                     */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
void
void
setsim_reg (unsigned int  regno,
setsim_reg (unsigned int  regno,
            uorreg_t      value)
            uorreg_t      value)
{
{
  if (regno == 0)                /* gpr0 is always zero */
  if (regno == 0)                /* gpr0 is always zero */
    {
    {
      value = 0;
      value = 0;
    }
    }
 
 
  if (regno < MAX_GPRS)
  if (regno < MAX_GPRS)
    {
    {
      cpu_state.reg[regno] = value;
      cpu_state.reg[regno] = value;
    }
    }
  else
  else
    {
    {
      PRINTF ("\nABORT: write out of registers\n");
      PRINTF ("\nABORT: write out of registers\n");
      sim_done ();
      sim_done ();
    }
    }
 
 
#if RAW_RANGE_STATS
#if RAW_RANGE_STATS
  raw_stats.reg[regno] = runtime.sim.cycles;
  raw_stats.reg[regno] = runtime.sim.cycles;
#endif /* RAW_RANGE */
#endif /* RAW_RANGE */
 
 
}       /* setsim_reg() */
}       /* setsim_reg() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Evaluates source operand operand
/*!Evaluates source operand operand
 
 
   Implementation specific. Declared global, although this is only actually
   Implementation specific. Declared global, although this is only actually
   required for DYNAMIC_EXECUTION,
   required for DYNAMIC_EXECUTION,
 
 
   @param[in] insn  The instruction
   @param[in] insn  The instruction
   @param[in] opd   The operand
   @param[in] opd   The operand
 
 
   @return  The value of the source operand                                  */
   @return  The value of the source operand                                  */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
uorreg_t
uorreg_t
eval_operand_val (uint32_t               insn,
eval_operand_val (uint32_t               insn,
                  struct insn_op_struct *opd)
                  struct insn_op_struct *opd)
{
{
  unsigned long  operand = 0;
  unsigned long  operand = 0;
  unsigned long  sbit;
  unsigned long  sbit;
  unsigned int   nbits = 0;
  unsigned int   nbits = 0;
 
 
  while (1)
  while (1)
    {
    {
      operand |=
      operand |=
        ((insn >> (opd->type & OPTYPE_SHR)) & ((1 << opd->data) - 1)) <<
        ((insn >> (opd->type & OPTYPE_SHR)) & ((1 << opd->data) - 1)) <<
        nbits;
        nbits;
      nbits += opd->data;
      nbits += opd->data;
 
 
      if (opd->type & OPTYPE_OP)
      if (opd->type & OPTYPE_OP)
        {
        {
          break;
          break;
        }
        }
 
 
      opd++;
      opd++;
    }
    }
 
 
  if (opd->type & OPTYPE_SIG)
  if (opd->type & OPTYPE_SIG)
    {
    {
      sbit = (opd->type & OPTYPE_SBIT) >> OPTYPE_SBIT_SHR;
      sbit = (opd->type & OPTYPE_SBIT) >> OPTYPE_SBIT_SHR;
 
 
      if (operand & (1 << sbit))
      if (operand & (1 << sbit))
        {
        {
          operand |= ~REG_C (0) << sbit;
          operand |= ~REG_C (0) << sbit;
        }
        }
    }
    }
 
 
  return operand;
  return operand;
 
 
}       /* eval_operand_val() */
}       /* eval_operand_val() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Does source operand depend on computation of dest operand?
/*!Does source operand depend on computation of dest operand?
 
 
      Cycle t                 Cycle t+1
      Cycle t                 Cycle t+1
  dst: irrelevant         src: immediate                  always 0
  dst: irrelevant         src: immediate                  always 0
  dst: reg1 direct        src: reg2 direct                0 if reg1 != reg2
  dst: reg1 direct        src: reg2 direct                0 if reg1 != reg2
  dst: reg1 disp          src: reg2 direct                always 0
  dst: reg1 disp          src: reg2 direct                always 0
  dst: reg1 direct        src: reg2 disp                  0 if reg1 != reg2
  dst: reg1 direct        src: reg2 disp                  0 if reg1 != reg2
  dst: reg1 disp          src: reg2 disp                  always 1 (store must
  dst: reg1 disp          src: reg2 disp                  always 1 (store must
                                                          finish before load)
                                                          finish before load)
  dst: flag               src: flag                       always 1
  dst: flag               src: flag                       always 1
 
 
  @param[in] prev  Previous instruction
  @param[in] prev  Previous instruction
  @param[in] next  Next instruction
  @param[in] next  Next instruction
 
 
  @return  Non-zero if yes.                                                  */
  @return  Non-zero if yes.                                                  */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static int
static int
check_depend (struct iqueue_entry *prev,
check_depend (struct iqueue_entry *prev,
              struct iqueue_entry *next)
              struct iqueue_entry *next)
{
{
  /* Find destination type. */
  /* Find destination type. */
  unsigned long          type = 0;
  unsigned long          type = 0;
  int                    prev_dis;
  int                    prev_dis;
  int                    next_dis;
  int                    next_dis;
  orreg_t                prev_reg_val = 0;
  orreg_t                prev_reg_val = 0;
  struct insn_op_struct *opd;
  struct insn_op_struct *opd;
 
 
  if (or32_opcodes[prev->insn_index].flags & OR32_W_FLAG
  if (or32_opcodes[prev->insn_index].flags & OR32_W_FLAG
      && or32_opcodes[next->insn_index].flags & OR32_R_FLAG)
      && or32_opcodes[next->insn_index].flags & OR32_R_FLAG)
    {
    {
      return  1;
      return  1;
    }
    }
 
 
  opd      = op_start[prev->insn_index];
  opd      = op_start[prev->insn_index];
  prev_dis = 0;
  prev_dis = 0;
 
 
  while (1)
  while (1)
    {
    {
      if (opd->type & OPTYPE_DIS)
      if (opd->type & OPTYPE_DIS)
        {
        {
          prev_dis = 1;
          prev_dis = 1;
        }
        }
 
 
      if (opd->type & OPTYPE_DST)
      if (opd->type & OPTYPE_DST)
        {
        {
          type = opd->type;
          type = opd->type;
 
 
          if (prev_dis)
          if (prev_dis)
            {
            {
              type |= OPTYPE_DIS;
              type |= OPTYPE_DIS;
            }
            }
 
 
          /* Destination is always a register */
          /* Destination is always a register */
          prev_reg_val = eval_operand_val (prev->insn, opd);
          prev_reg_val = eval_operand_val (prev->insn, opd);
          break;
          break;
        }
        }
 
 
      if (opd->type & OPTYPE_LAST)
      if (opd->type & OPTYPE_LAST)
        {
        {
          return 0;              /* Doesn't have a destination operand */
          return 0;              /* Doesn't have a destination operand */
        }
        }
 
 
      if (opd->type & OPTYPE_OP)
      if (opd->type & OPTYPE_OP)
        {
        {
          prev_dis = 0;
          prev_dis = 0;
        }
        }
 
 
      opd++;
      opd++;
    }
    }
 
 
  /* We search all source operands - if we find confict => return 1 */
  /* We search all source operands - if we find confict => return 1 */
  opd      = op_start[next->insn_index];
  opd      = op_start[next->insn_index];
  next_dis = 0;
  next_dis = 0;
 
 
  while (1)
  while (1)
    {
    {
      if (opd->type & OPTYPE_DIS)
      if (opd->type & OPTYPE_DIS)
        {
        {
          next_dis = 1;
          next_dis = 1;
        }
        }
 
 
      /* This instruction sequence also depends on order of execution:
      /* This instruction sequence also depends on order of execution:
           l.lw r1, k(r1)
           l.lw r1, k(r1)
           l.sw k(r1), r4
           l.sw k(r1), r4
         Here r1 is a destination in l.sw */
         Here r1 is a destination in l.sw */
 
 
      /* FIXME: This situation is not handeld here when r1 == r2:
      /* FIXME: This situation is not handeld here when r1 == r2:
           l.sw k(r1), r4
           l.sw k(r1), r4
           l.lw r3, k(r2) */
           l.lw r3, k(r2) */
      if (!(opd->type & OPTYPE_DST) || (next_dis && (opd->type & OPTYPE_DST)))
      if (!(opd->type & OPTYPE_DST) || (next_dis && (opd->type & OPTYPE_DST)))
        {
        {
          if (opd->type & OPTYPE_REG)
          if (opd->type & OPTYPE_REG)
            {
            {
              if (eval_operand_val (next->insn, opd) == prev_reg_val)
              if (eval_operand_val (next->insn, opd) == prev_reg_val)
                {
                {
                  return 1;
                  return 1;
                }
                }
            }
            }
        }
        }
 
 
      if (opd->type & OPTYPE_LAST)
      if (opd->type & OPTYPE_LAST)
        {
        {
          break;
          break;
        }
        }
 
 
      opd++;
      opd++;
    }
    }
 
 
  return  0;
  return  0;
 
 
}       /* check_depend() */
}       /* check_depend() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Should instruction NOT be executed?
/*!Should instruction NOT be executed?
 
 
   Modified by CZ 26/05/01 for new mode execution.
   Modified by CZ 26/05/01 for new mode execution.
 
 
   @return  Nonzero if instruction should NOT be executed                    */
   @return  Nonzero if instruction should NOT be executed                    */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static int
static int
fetch ()
fetch ()
{
{
  static int break_just_hit = 0;
  static int break_just_hit = 0;
 
 
  if (NULL != breakpoints)
  if (NULL != breakpoints)
    {
    {
      /* MM: Check for breakpoint.  This has to be done in fetch cycle,
      /* MM: Check for breakpoint.  This has to be done in fetch cycle,
         because of peripheria.
         because of peripheria.
         MM1709: if we cannot access the memory entry, we could not set the
         MM1709: if we cannot access the memory entry, we could not set the
         breakpoint earlier, so just check the breakpoint list.  */
         breakpoint earlier, so just check the breakpoint list.  */
      if (has_breakpoint (peek_into_itlb (cpu_state.pc)) && !break_just_hit)
      if (has_breakpoint (peek_into_itlb (cpu_state.pc)) && !break_just_hit)
        {
        {
          break_just_hit = 1;
          break_just_hit = 1;
          return 1;             /* Breakpoint set. */
          return 1;             /* Breakpoint set. */
        }
        }
      break_just_hit = 0;
      break_just_hit = 0;
    }
    }
 
 
  breakpoint                 = 0;
  breakpoint                 = 0;
  cpu_state.iqueue.insn_addr = cpu_state.pc;
  cpu_state.iqueue.insn_addr = cpu_state.pc;
  cpu_state.iqueue.insn      = eval_insn (cpu_state.pc, &breakpoint);
  cpu_state.iqueue.insn      = eval_insn (cpu_state.pc, &breakpoint);
 
 
  /* Fetch instruction. */
  /* Fetch instruction. */
  if (!except_pending)
  if (!except_pending)
    {
    {
      runtime.cpu.instructions++;
      runtime.cpu.instructions++;
    }
    }
 
 
  /* update_pc will be called after execution */
  /* update_pc will be called after execution */
  return 0;
  return 0;
 
 
}       /* fetch() */
}       /* fetch() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!This code actually updates the PC value                                   */
/*!This code actually updates the PC value                                   */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
update_pc ()
update_pc ()
{
{
  cpu_state.delay_insn    = next_delay_insn;
  cpu_state.delay_insn    = next_delay_insn;
  cpu_state.sprs[SPR_PPC] = cpu_state.pc;       /* Store value for later */
  cpu_state.sprs[SPR_PPC] = cpu_state.pc;       /* Store value for later */
  cpu_state.pc            = pcnext;
  cpu_state.pc            = pcnext;
  pcnext                  = cpu_state.delay_insn ? cpu_state.pc_delay :
  pcnext                  = cpu_state.delay_insn ? cpu_state.pc_delay :
                                                   pcnext + 4;
                                                   pcnext + 4;
}       /* update_pc() */
}       /* update_pc() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Perform analysis of the instruction being executed
/*!Perform analysis of the instruction being executed
 
 
   This could be static for SIMPLE_EXECUTION, but made global for general use.
   This could be static for SIMPLE_EXECUTION, but made global for general use.
 
 
   @param[in] current  The instruction being executed                        */
   @param[in] current  The instruction being executed                        */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
void
void
analysis (struct iqueue_entry *current)
analysis (struct iqueue_entry *current)
{
{
  if (config.cpu.dependstats)
  if (config.cpu.dependstats)
    {
    {
      /* Dynamic, dependency stats. */
      /* Dynamic, dependency stats. */
      adddstats (cpu_state.icomplet.insn_index, current->insn_index, 1,
      adddstats (cpu_state.icomplet.insn_index, current->insn_index, 1,
                 check_depend (&cpu_state.icomplet, current));
                 check_depend (&cpu_state.icomplet, current));
 
 
      /* Dynamic, functional units stats. */
      /* Dynamic, functional units stats. */
      addfstats (or32_opcodes[cpu_state.icomplet.insn_index].func_unit,
      addfstats (or32_opcodes[cpu_state.icomplet.insn_index].func_unit,
                 or32_opcodes[current->insn_index].func_unit, 1,
                 or32_opcodes[current->insn_index].func_unit, 1,
                 check_depend (&cpu_state.icomplet, current));
                 check_depend (&cpu_state.icomplet, current));
 
 
      /* Dynamic, single stats. */
      /* Dynamic, single stats. */
      addsstats (current->insn_index, 1);
      addsstats (current->insn_index, 1);
    }
    }
 
 
  if (config.cpu.superscalar)
  if (config.cpu.superscalar)
    {
    {
      if ((or32_opcodes[current->insn_index].func_unit == it_branch) ||
      if ((or32_opcodes[current->insn_index].func_unit == it_branch) ||
          (or32_opcodes[current->insn_index].func_unit == it_jump))
          (or32_opcodes[current->insn_index].func_unit == it_jump))
        runtime.sim.storecycles += 0;
        runtime.sim.storecycles += 0;
 
 
      if (or32_opcodes[current->insn_index].func_unit == it_store)
      if (or32_opcodes[current->insn_index].func_unit == it_store)
        runtime.sim.storecycles += 1;
        runtime.sim.storecycles += 1;
 
 
      if (or32_opcodes[current->insn_index].func_unit == it_load)
      if (or32_opcodes[current->insn_index].func_unit == it_load)
        runtime.sim.loadcycles += 1;
        runtime.sim.loadcycles += 1;
 
 
      /* Pseudo multiple issue benchmark */
      /* Pseudo multiple issue benchmark */
      if ((multissue[or32_opcodes[current->insn_index].func_unit] < 1) ||
      if ((multissue[or32_opcodes[current->insn_index].func_unit] < 1) ||
          (check_depend (&cpu_state.icomplet, current))
          (check_depend (&cpu_state.icomplet, current))
          || (issued_per_cycle < 1))
          || (issued_per_cycle < 1))
        {
        {
          int i;
          int i;
          for (i = 0; i < 20; i++)
          for (i = 0; i < 20; i++)
            multissue[i] = 2;
            multissue[i] = 2;
          issued_per_cycle = 2;
          issued_per_cycle = 2;
          runtime.cpu.supercycles++;
          runtime.cpu.supercycles++;
          if (check_depend (&cpu_state.icomplet, current))
          if (check_depend (&cpu_state.icomplet, current))
            runtime.cpu.hazardwait++;
            runtime.cpu.hazardwait++;
          multissue[it_unknown] = 2;
          multissue[it_unknown] = 2;
          multissue[it_shift] = 2;
          multissue[it_shift] = 2;
          multissue[it_compare] = 1;
          multissue[it_compare] = 1;
          multissue[it_branch] = 1;
          multissue[it_branch] = 1;
          multissue[it_jump] = 1;
          multissue[it_jump] = 1;
          multissue[it_extend] = 2;
          multissue[it_extend] = 2;
          multissue[it_nop] = 2;
          multissue[it_nop] = 2;
          multissue[it_move] = 2;
          multissue[it_move] = 2;
          multissue[it_movimm] = 2;
          multissue[it_movimm] = 2;
          multissue[it_arith] = 2;
          multissue[it_arith] = 2;
          multissue[it_store] = 2;
          multissue[it_store] = 2;
          multissue[it_load] = 2;
          multissue[it_load] = 2;
        }
        }
      multissue[or32_opcodes[current->insn_index].func_unit]--;
      multissue[or32_opcodes[current->insn_index].func_unit]--;
      issued_per_cycle--;
      issued_per_cycle--;
    }
    }
 
 
  if (config.cpu.dependstats)
  if (config.cpu.dependstats)
    /* Instruction waits in completition buffer until retired. */
    /* Instruction waits in completition buffer until retired. */
    memcpy (&cpu_state.icomplet, current, sizeof (struct iqueue_entry));
    memcpy (&cpu_state.icomplet, current, sizeof (struct iqueue_entry));
 
 
  if (config.sim.history)
  if (config.sim.history)
    {
    {
      /* History of execution */
      /* History of execution */
      hist_exec_tail = hist_exec_tail->next;
      hist_exec_tail = hist_exec_tail->next;
      hist_exec_tail->addr = cpu_state.icomplet.insn_addr;
      hist_exec_tail->addr = cpu_state.icomplet.insn_addr;
    }
    }
 
 
  if (config.sim.exe_log)
  if (config.sim.exe_log)
    dump_exe_log ();
    dump_exe_log ();
 
 
}       /* analysis() */
}       /* analysis() */
 
 
 
 
#if !(DYNAMIC_EXECUTION)
#if !(DYNAMIC_EXECUTION)
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Store buffer analysis for store instructions
/*!Store buffer analysis for store instructions
 
 
   Stores are accumulated and commited when IO is idle
   Stores are accumulated and commited when IO is idle
 
 
   @param[in] cyc  Number of cycles being analysed                           */
   @param[in] cyc  Number of cycles being analysed                           */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
sbuf_store (int cyc)
sbuf_store (int cyc)
{
{
  int delta = runtime.sim.cycles - sbuf_prev_cycles;
  int delta = runtime.sim.cycles - sbuf_prev_cycles;
 
 
  sbuf_total_cyc   += cyc;
  sbuf_total_cyc   += cyc;
  sbuf_prev_cycles  = runtime.sim.cycles;
  sbuf_prev_cycles  = runtime.sim.cycles;
 
 
  /* Take stores from buffer, that occured meanwhile */
  /* Take stores from buffer, that occured meanwhile */
  while (sbuf_count && delta >= sbuf_buf[sbuf_tail])
  while (sbuf_count && delta >= sbuf_buf[sbuf_tail])
    {
    {
      delta     -= sbuf_buf[sbuf_tail];
      delta     -= sbuf_buf[sbuf_tail];
      sbuf_tail  = (sbuf_tail + 1) % MAX_SBUF_LEN;
      sbuf_tail  = (sbuf_tail + 1) % MAX_SBUF_LEN;
      sbuf_count--;
      sbuf_count--;
    }
    }
 
 
  if (sbuf_count)
  if (sbuf_count)
    {
    {
      sbuf_buf[sbuf_tail] -= delta;
      sbuf_buf[sbuf_tail] -= delta;
    }
    }
 
 
  /* Store buffer is full, take one out */
  /* Store buffer is full, take one out */
  if (sbuf_count >= config.cpu.sbuf_len)
  if (sbuf_count >= config.cpu.sbuf_len)
    {
    {
      sbuf_wait_cyc          += sbuf_buf[sbuf_tail];
      sbuf_wait_cyc          += sbuf_buf[sbuf_tail];
      runtime.sim.mem_cycles += sbuf_buf[sbuf_tail];
      runtime.sim.mem_cycles += sbuf_buf[sbuf_tail];
      sbuf_prev_cycles       += sbuf_buf[sbuf_tail];
      sbuf_prev_cycles       += sbuf_buf[sbuf_tail];
      sbuf_tail               = (sbuf_tail + 1) % MAX_SBUF_LEN;
      sbuf_tail               = (sbuf_tail + 1) % MAX_SBUF_LEN;
      sbuf_count--;
      sbuf_count--;
    }
    }
 
 
  /* Put newest store in the buffer */
  /* Put newest store in the buffer */
  sbuf_buf[sbuf_head] = cyc;
  sbuf_buf[sbuf_head] = cyc;
  sbuf_head           = (sbuf_head + 1) % MAX_SBUF_LEN;
  sbuf_head           = (sbuf_head + 1) % MAX_SBUF_LEN;
  sbuf_count++;
  sbuf_count++;
 
 
}       /* sbuf_store() */
}       /* sbuf_store() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Store buffer analysis for load instructions
/*!Store buffer analysis for load instructions
 
 
   Previous stores should commit, before any load                            */
   Previous stores should commit, before any load                            */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
sbuf_load ()
sbuf_load ()
{
{
  int delta = runtime.sim.cycles - sbuf_prev_cycles;
  int delta = runtime.sim.cycles - sbuf_prev_cycles;
  sbuf_prev_cycles = runtime.sim.cycles;
  sbuf_prev_cycles = runtime.sim.cycles;
 
 
  /* Take stores from buffer, that occured meanwhile */
  /* Take stores from buffer, that occured meanwhile */
  while (sbuf_count && delta >= sbuf_buf[sbuf_tail])
  while (sbuf_count && delta >= sbuf_buf[sbuf_tail])
    {
    {
      delta     -= sbuf_buf[sbuf_tail];
      delta     -= sbuf_buf[sbuf_tail];
      sbuf_tail  = (sbuf_tail + 1) % MAX_SBUF_LEN;
      sbuf_tail  = (sbuf_tail + 1) % MAX_SBUF_LEN;
      sbuf_count--;
      sbuf_count--;
    }
    }
 
 
  if (sbuf_count)
  if (sbuf_count)
    {
    {
      sbuf_buf[sbuf_tail] -= delta;
      sbuf_buf[sbuf_tail] -= delta;
    }
    }
 
 
  /* Wait for all stores to complete */
  /* Wait for all stores to complete */
  while (sbuf_count > 0)
  while (sbuf_count > 0)
    {
    {
      sbuf_wait_cyc          += sbuf_buf[sbuf_tail];
      sbuf_wait_cyc          += sbuf_buf[sbuf_tail];
      runtime.sim.mem_cycles += sbuf_buf[sbuf_tail];
      runtime.sim.mem_cycles += sbuf_buf[sbuf_tail];
      sbuf_prev_cycles       += sbuf_buf[sbuf_tail];
      sbuf_prev_cycles       += sbuf_buf[sbuf_tail];
      sbuf_tail               = (sbuf_tail + 1) % MAX_SBUF_LEN;
      sbuf_tail               = (sbuf_tail + 1) % MAX_SBUF_LEN;
      sbuf_count--;
      sbuf_count--;
    }
    }
}       /* sbuf_load() */
}       /* sbuf_load() */
 
 
#endif  /* !DYNAMIC_EXECUTION */
#endif  /* !DYNAMIC_EXECUTION */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Outputs dissasembled instruction                                          */
/*!Outputs dissasembled instruction                                          */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
void
void
dump_exe_log ()
dump_exe_log ()
{
{
  oraddr_t      insn_addr = cpu_state.iqueue.insn_addr;
  oraddr_t      insn_addr = cpu_state.iqueue.insn_addr;
  unsigned int  i;
  unsigned int  i;
  unsigned int  j;
  unsigned int  j;
  uorreg_t      operand;
  uorreg_t      operand;
 
 
  if (insn_addr == 0xffffffff)
  if (insn_addr == 0xffffffff)
    {
    {
      return;
      return;
    }
    }
 
 
  if ((config.sim.exe_log_start <= runtime.cpu.instructions) &&
  if ((config.sim.exe_log_start <= runtime.cpu.instructions) &&
      ((config.sim.exe_log_end <= 0) ||
      ((config.sim.exe_log_end <= 0) ||
       (runtime.cpu.instructions <= config.sim.exe_log_end)))
       (runtime.cpu.instructions <= config.sim.exe_log_end)))
    {
    {
      struct label_entry *entry;
      struct label_entry *entry;
 
 
      if (config.sim.exe_log_marker &&
      if (config.sim.exe_log_marker &&
          !(runtime.cpu.instructions % config.sim.exe_log_marker))
          !(runtime.cpu.instructions % config.sim.exe_log_marker))
        {
        {
          fprintf (runtime.sim.fexe_log,
          fprintf (runtime.sim.fexe_log,
                   "--------------------- %8lli instruction "
                   "--------------------- %8lli instruction "
                   "---------------------\n",
                   "---------------------\n",
                   runtime.cpu.instructions);
                   runtime.cpu.instructions);
        }
        }
 
 
      switch (config.sim.exe_log_type)
      switch (config.sim.exe_log_type)
        {
        {
        case EXE_LOG_HARDWARE:
        case EXE_LOG_HARDWARE:
          fprintf (runtime.sim.fexe_log,
          fprintf (runtime.sim.fexe_log,
                   "\nEXECUTED(%11llu): %" PRIxADDR ":  ",
                   "\nEXECUTED(%11llu): %" PRIxADDR ":  ",
                   runtime.cpu.instructions, insn_addr);
                   runtime.cpu.instructions, insn_addr);
          fprintf (runtime.sim.fexe_log, "%.2x%.2x",
          fprintf (runtime.sim.fexe_log, "%.2x%.2x",
                   eval_direct8 (insn_addr, 0, 0),
                   eval_direct8 (insn_addr, 0, 0),
                   eval_direct8 (insn_addr + 1, 0, 0));
                   eval_direct8 (insn_addr + 1, 0, 0));
          fprintf (runtime.sim.fexe_log, "%.2x%.2x",
          fprintf (runtime.sim.fexe_log, "%.2x%.2x",
                   eval_direct8 (insn_addr + 2, 0, 0),
                   eval_direct8 (insn_addr + 2, 0, 0),
                   eval_direct8 (insn_addr + 3, 0, 0));
                   eval_direct8 (insn_addr + 3, 0, 0));
 
 
          for (i = 0; i < MAX_GPRS; i++)
          for (i = 0; i < MAX_GPRS; i++)
            {
            {
              if (i % 4 == 0)
              if (i % 4 == 0)
                {
                {
                  fprintf (runtime.sim.fexe_log, "\n");
                  fprintf (runtime.sim.fexe_log, "\n");
                }
                }
 
 
              fprintf (runtime.sim.fexe_log, "GPR%2u: %" PRIxREG "  ", i,
              fprintf (runtime.sim.fexe_log, "GPR%2u: %" PRIxREG "  ", i,
                       cpu_state.reg[i]);
                       cpu_state.reg[i]);
            }
            }
 
 
          fprintf (runtime.sim.fexe_log, "\n");
          fprintf (runtime.sim.fexe_log, "\n");
          fprintf (runtime.sim.fexe_log, "SR   : %.8" PRIx32 "  ",
          fprintf (runtime.sim.fexe_log, "SR   : %.8" PRIx32 "  ",
                   cpu_state.sprs[SPR_SR]);
                   cpu_state.sprs[SPR_SR]);
          fprintf (runtime.sim.fexe_log, "EPCR0: %" PRIxADDR "  ",
          fprintf (runtime.sim.fexe_log, "EPCR0: %" PRIxADDR "  ",
                   cpu_state.sprs[SPR_EPCR_BASE]);
                   cpu_state.sprs[SPR_EPCR_BASE]);
          fprintf (runtime.sim.fexe_log, "EEAR0: %" PRIxADDR "  ",
          fprintf (runtime.sim.fexe_log, "EEAR0: %" PRIxADDR "  ",
                   cpu_state.sprs[SPR_EEAR_BASE]);
                   cpu_state.sprs[SPR_EEAR_BASE]);
          fprintf (runtime.sim.fexe_log, "ESR0 : %.8" PRIx32 "\n",
          fprintf (runtime.sim.fexe_log, "ESR0 : %.8" PRIx32 "\n",
                   cpu_state.sprs[SPR_ESR_BASE]);
                   cpu_state.sprs[SPR_ESR_BASE]);
          break;
          break;
 
 
        case EXE_LOG_SIMPLE:
        case EXE_LOG_SIMPLE:
        case EXE_LOG_SOFTWARE:
        case EXE_LOG_SOFTWARE:
          disassemble_index (cpu_state.iqueue.insn,
          disassemble_index (cpu_state.iqueue.insn,
                             cpu_state.iqueue.insn_index);
                             cpu_state.iqueue.insn_index);
 
 
          entry = get_label (insn_addr);
          entry = get_label (insn_addr);
          if (entry)
          if (entry)
            {
            {
              fprintf (runtime.sim.fexe_log, "%s:\n", entry->name);
              fprintf (runtime.sim.fexe_log, "%s:\n", entry->name);
            }
            }
 
 
          if (config.sim.exe_log_type == EXE_LOG_SOFTWARE)
          if (config.sim.exe_log_type == EXE_LOG_SOFTWARE)
            {
            {
              struct insn_op_struct *opd =
              struct insn_op_struct *opd =
                op_start[cpu_state.iqueue.insn_index];
                op_start[cpu_state.iqueue.insn_index];
 
 
              j = 0;
              j = 0;
              while (1)
              while (1)
                {
                {
                  operand = eval_operand_val (cpu_state.iqueue.insn, opd);
                  operand = eval_operand_val (cpu_state.iqueue.insn, opd);
                  while (!(opd->type & OPTYPE_OP))
                  while (!(opd->type & OPTYPE_OP))
                    {
                    {
                      opd++;
                      opd++;
                    }
                    }
                  if (opd->type & OPTYPE_DIS)
                  if (opd->type & OPTYPE_DIS)
                    {
                    {
                      fprintf (runtime.sim.fexe_log,
                      fprintf (runtime.sim.fexe_log,
                               "EA =%" PRIxADDR " PA =%" PRIxADDR " ",
                               "EA =%" PRIxADDR " PA =%" PRIxADDR " ",
                               cpu_state.insn_ea,
                               cpu_state.insn_ea,
                               peek_into_dtlb (cpu_state.insn_ea, 0, 0));
                               peek_into_dtlb (cpu_state.insn_ea, 0, 0));
                      opd++;    /* Skip of register operand */
                      opd++;    /* Skip of register operand */
                      j++;
                      j++;
                    }
                    }
                  else if ((opd->type & OPTYPE_REG) && operand)
                  else if ((opd->type & OPTYPE_REG) && operand)
                    {
                    {
                      fprintf (runtime.sim.fexe_log, "r%-2i=%" PRIxREG " ",
                      fprintf (runtime.sim.fexe_log, "r%-2i=%" PRIxREG " ",
                               (int) operand, evalsim_reg (operand));
                               (int) operand, evalsim_reg (operand));
                    }
                    }
                  else
                  else
                    {
                    {
                      fprintf (runtime.sim.fexe_log, "             ");
                      fprintf (runtime.sim.fexe_log, "             ");
                    }
                    }
                  j++;
                  j++;
                  if (opd->type & OPTYPE_LAST)
                  if (opd->type & OPTYPE_LAST)
                    {
                    {
                      break;
                      break;
                    }
                    }
                  opd++;
                  opd++;
                }
                }
              if (or32_opcodes[cpu_state.iqueue.insn_index].flags & OR32_R_FLAG)
              if (or32_opcodes[cpu_state.iqueue.insn_index].flags & OR32_R_FLAG)
                {
                {
                  fprintf (runtime.sim.fexe_log, "SR =%" PRIxREG " ",
                  fprintf (runtime.sim.fexe_log, "SR =%" PRIxREG " ",
                           cpu_state.sprs[SPR_SR]);
                           cpu_state.sprs[SPR_SR]);
                  j++;
                  j++;
                }
                }
              while (j < 3)
              while (j < 3)
                {
                {
                  fprintf (runtime.sim.fexe_log, "             ");
                  fprintf (runtime.sim.fexe_log, "             ");
                  j++;
                  j++;
                }
                }
            }
            }
          fprintf (runtime.sim.fexe_log, "%" PRIxADDR " ", insn_addr);
          fprintf (runtime.sim.fexe_log, "%" PRIxADDR " ", insn_addr);
          fprintf (runtime.sim.fexe_log, "%s\n", disassembled);
          fprintf (runtime.sim.fexe_log, "%s\n", disassembled);
        }
        }
    }
    }
}       /* dump_exe_log() */
}       /* dump_exe_log() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Dump registers
/*!Dump registers
 
 
   Supports the CLI 'r' and 't' commands                                     */
   Supports the CLI 'r' and 't' commands                                     */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
void
void
dumpreg ()
dumpreg ()
{
{
  int       i;
  int       i;
  oraddr_t  physical_pc;
  oraddr_t  physical_pc;
 
 
  if ((physical_pc = peek_into_itlb (cpu_state.iqueue.insn_addr)))
  if ((physical_pc = peek_into_itlb (cpu_state.iqueue.insn_addr)))
    {
    {
      disassemble_memory (physical_pc, physical_pc + 4, 0);
      disassemble_memory (physical_pc, physical_pc + 4, 0);
    }
    }
  else
  else
    {
    {
      PRINTF ("INTERNAL SIMULATOR ERROR:\n");
      PRINTF ("INTERNAL SIMULATOR ERROR:\n");
      PRINTF ("no translation for currently executed instruction\n");
      PRINTF ("no translation for currently executed instruction\n");
    }
    }
 
 
  // generate_time_pretty (temp, runtime.sim.cycles * config.sim.clkcycle_ps);
  // generate_time_pretty (temp, runtime.sim.cycles * config.sim.clkcycle_ps);
  PRINTF (" (executed) [cycle %lld, #%lld]\n", runtime.sim.cycles,
  PRINTF (" (executed) [cycle %lld, #%lld]\n", runtime.sim.cycles,
          runtime.cpu.instructions);
          runtime.cpu.instructions);
  if (config.cpu.superscalar)
  if (config.cpu.superscalar)
    {
    {
      PRINTF ("Superscalar CYCLES: %u", runtime.cpu.supercycles);
      PRINTF ("Superscalar CYCLES: %u", runtime.cpu.supercycles);
    }
    }
  if (config.cpu.hazards)
  if (config.cpu.hazards)
    {
    {
      PRINTF ("  HAZARDWAIT: %u\n", runtime.cpu.hazardwait);
      PRINTF ("  HAZARDWAIT: %u\n", runtime.cpu.hazardwait);
    }
    }
  else if (config.cpu.superscalar)
  else if (config.cpu.superscalar)
    {
    {
      PRINTF ("\n");
      PRINTF ("\n");
    }
    }
 
 
  if ((physical_pc = peek_into_itlb (cpu_state.pc)))
  if ((physical_pc = peek_into_itlb (cpu_state.pc)))
    {
    {
      disassemble_memory (physical_pc, physical_pc + 4, 0);
      disassemble_memory (physical_pc, physical_pc + 4, 0);
    }
    }
  else
  else
    {
    {
      PRINTF ("%" PRIxADDR ": : xxxxxxxx  ITLB miss follows", cpu_state.pc);
      PRINTF ("%" PRIxADDR ": : xxxxxxxx  ITLB miss follows", cpu_state.pc);
    }
    }
 
 
  PRINTF (" (next insn) %s", (cpu_state.delay_insn ? "(delay insn)" : ""));
  PRINTF (" (next insn) %s", (cpu_state.delay_insn ? "(delay insn)" : ""));
 
 
  for (i = 0; i < MAX_GPRS; i++)
  for (i = 0; i < MAX_GPRS; i++)
    {
    {
      if (i % 4 == 0)
      if (i % 4 == 0)
        {
        {
          PRINTF ("\n");
          PRINTF ("\n");
        }
        }
 
 
      PRINTF ("GPR%.2u: %" PRIxREG "  ", i, evalsim_reg (i));
      PRINTF ("GPR%.2u: %" PRIxREG "  ", i, evalsim_reg (i));
    }
    }
 
 
  PRINTF ("flag: %u\n", cpu_state.sprs[SPR_SR] & SPR_SR_F ? 1 : 0);
  PRINTF ("flag: %u\n", cpu_state.sprs[SPR_SR] & SPR_SR_F ? 1 : 0);
 
 
}       /* dumpreg() */
}       /* dumpreg() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Wrapper around real decode_execute function
/*!Wrapper around real decode_execute function
 
 
   Some statistics here only
   Some statistics here only
 
 
   @param[in] current  Instruction being executed                            */
   @param[in] current  Instruction being executed                            */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
decode_execute_wrapper (struct iqueue_entry *current)
decode_execute_wrapper (struct iqueue_entry *current)
{
{
  breakpoint = 0;
  breakpoint = 0;
 
 
#ifndef HAVE_EXECUTION
#ifndef HAVE_EXECUTION
#error HAVE_EXECUTION has to be defined in order to execute programs.
#error HAVE_EXECUTION has to be defined in order to execute programs.
#endif
#endif
 
 
  /* FIXME: Most of this file is not needed with DYNAMIC_EXECUTION */
  /* FIXME: Most of this file is not needed with DYNAMIC_EXECUTION */
#if !(DYNAMIC_EXECUTION)
#if !(DYNAMIC_EXECUTION)
  decode_execute (current);
  decode_execute (current);
#endif
#endif
 
 
#if SET_OV_FLAG
#if SET_OV_FLAG
  /* Check for range exception */
  /* Check for range exception */
  if ((cpu_state.sprs[SPR_SR] & SPR_SR_OVE) &&
  if ((cpu_state.sprs[SPR_SR] & SPR_SR_OVE) &&
      (cpu_state.sprs[SPR_SR] & SPR_SR_OV))
      (cpu_state.sprs[SPR_SR] & SPR_SR_OV))
    {
    {
      except_handle (EXCEPT_RANGE, cpu_state.sprs[SPR_EEAR_BASE]);
      except_handle (EXCEPT_RANGE, cpu_state.sprs[SPR_EEAR_BASE]);
    }
    }
#endif
#endif
 
 
  if (breakpoint)
  if (breakpoint)
    {
    {
      except_handle (EXCEPT_TRAP, cpu_state.sprs[SPR_EEAR_BASE]);
      except_handle (EXCEPT_TRAP, cpu_state.sprs[SPR_EEAR_BASE]);
    }
    }
}       /* decode_execute_wrapper() */
}       /* decode_execute_wrapper() */
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Reset the CPU                                                             */
/*!Reset the CPU                                                             */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
void
void
cpu_reset ()
cpu_reset ()
{
{
  int               i;
  int               i;
  struct hist_exec *hist_exec_head = NULL;
  struct hist_exec *hist_exec_head = NULL;
  struct hist_exec *hist_exec_new;
  struct hist_exec *hist_exec_new;
 
 
  runtime.sim.cycles       = 0;
  runtime.sim.cycles       = 0;
  runtime.sim.loadcycles   = 0;
  runtime.sim.loadcycles   = 0;
  runtime.sim.storecycles  = 0;
  runtime.sim.storecycles  = 0;
  runtime.cpu.instructions = 0;
  runtime.cpu.instructions = 0;
  runtime.cpu.supercycles  = 0;
  runtime.cpu.supercycles  = 0;
  runtime.cpu.hazardwait   = 0;
  runtime.cpu.hazardwait   = 0;
 
 
  for (i = 0; i < MAX_GPRS; i++)
  for (i = 0; i < MAX_GPRS; i++)
    {
    {
      setsim_reg (i, 0);
      setsim_reg (i, 0);
    }
    }
 
 
  memset (&cpu_state.iqueue,   0, sizeof (cpu_state.iqueue));
  memset (&cpu_state.iqueue,   0, sizeof (cpu_state.iqueue));
  memset (&cpu_state.icomplet, 0, sizeof (cpu_state.icomplet));
  memset (&cpu_state.icomplet, 0, sizeof (cpu_state.icomplet));
 
 
  sbuf_head        = 0;
  sbuf_head        = 0;
  sbuf_tail        = 0;
  sbuf_tail        = 0;
  sbuf_count       = 0;
  sbuf_count       = 0;
  sbuf_prev_cycles = 0;
  sbuf_prev_cycles = 0;
 
 
  /* Initialise execution history circular buffer */
  /* Initialise execution history circular buffer */
  for (i = 0; i < HISTEXEC_LEN; i++)
  for (i = 0; i < HISTEXEC_LEN; i++)
    {
    {
      hist_exec_new = malloc (sizeof (struct hist_exec));
      hist_exec_new = malloc (sizeof (struct hist_exec));
 
 
      if (!hist_exec_new)
      if (!hist_exec_new)
        {
        {
          fprintf (stderr, "Out-of-memory\n");
          fprintf (stderr, "Out-of-memory\n");
          exit (1);
          exit (1);
        }
        }
 
 
      if (!hist_exec_head)
      if (!hist_exec_head)
        {
        {
          hist_exec_head = hist_exec_new;
          hist_exec_head = hist_exec_new;
        }
        }
      else
      else
        {
        {
          hist_exec_tail->next = hist_exec_new;
          hist_exec_tail->next = hist_exec_new;
        }
        }
 
 
      hist_exec_new->prev = hist_exec_tail;
      hist_exec_new->prev = hist_exec_tail;
      hist_exec_tail = hist_exec_new;
      hist_exec_tail = hist_exec_new;
    }
    }
 
 
  /* Make hist_exec_tail->next point to hist_exec_head */
  /* Make hist_exec_tail->next point to hist_exec_head */
  hist_exec_tail->next = hist_exec_head;
  hist_exec_tail->next = hist_exec_head;
  hist_exec_head->prev = hist_exec_tail;
  hist_exec_head->prev = hist_exec_tail;
 
 
  /* MM1409: All progs should start at reset vector entry! This sorted out by
  /* MM1409: All progs should start at reset vector entry! This sorted out by
     setting the cpu_state.pc field below. Not clear this is very good code! */
     setting the cpu_state.pc field below. Not clear this is very good code! */
 
 
  /* Patches suggested by Shinji Wakatsuki, so that the vector address takes
  /* Patches suggested by Shinji Wakatsuki, so that the vector address takes
     notice of the Exception Prefix High bit of the Supervision register */
     notice of the Exception Prefix High bit of the Supervision register */
  pcnext = (cpu_state.sprs[SPR_SR] & SPR_SR_EPH ? 0xf0000000 : 0x00000000);
  pcnext = (cpu_state.sprs[SPR_SR] & SPR_SR_EPH ? 0xf0000000 : 0x00000000);
 
 
  if (config.sim.verbose)
  if (config.sim.verbose)
    {
    {
      PRINTF ("Starting at 0x%" PRIxADDR "\n", pcnext);
      PRINTF ("Starting at 0x%" PRIxADDR "\n", pcnext);
    }
    }
 
 
  cpu_state.pc  = pcnext;
  cpu_state.pc  = pcnext;
  pcnext       += 4;
  pcnext       += 4;
 
 
  /* MM1409: All programs should set their stack pointer!  */
  /* MM1409: All programs should set their stack pointer!  */
#if !(DYNAMIC_EXECUTION)
#if !(DYNAMIC_EXECUTION)
  except_handle (EXCEPT_RESET, 0);
  except_handle (EXCEPT_RESET, 0);
  update_pc ();
  update_pc ();
#endif
#endif
 
 
  except_pending = 0;
  except_pending = 0;
  cpu_state.pc   = cpu_state.sprs[SPR_SR] & SPR_SR_EPH ?
  cpu_state.pc   = cpu_state.sprs[SPR_SR] & SPR_SR_EPH ?
    0xf0000000 + EXCEPT_RESET : EXCEPT_RESET;
    0xf0000000 + EXCEPT_RESET : EXCEPT_RESET;
 
 
}       /* cpu_reset() */
}       /* cpu_reset() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Simulates one CPU clock cycle
/*!Simulates one CPU clock cycle
 
 
  @return  non-zero if a breakpoint is hit, zero otherwise.                  */
  @return  non-zero if a breakpoint is hit, zero otherwise.                  */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
int
int
cpu_clock ()
cpu_clock ()
{
{
  except_pending  = 0;
  except_pending  = 0;
  next_delay_insn = 0;
  next_delay_insn = 0;
 
 
  if (fetch ())
  if (fetch ())
    {
    {
      PRINTF ("Breakpoint hit.\n");
      PRINTF ("Breakpoint hit.\n");
      return  1;
      return  1;
    }
    }
 
 
  if (except_pending)
  if (except_pending)
    {
    {
      update_pc ();
      update_pc ();
      except_pending = 0;
      except_pending = 0;
      return  0;
      return  0;
    }
    }
 
 
  if (breakpoint)
  if (breakpoint)
    {
    {
      except_handle (EXCEPT_TRAP, cpu_state.sprs[SPR_EEAR_BASE]);
      except_handle (EXCEPT_TRAP, cpu_state.sprs[SPR_EEAR_BASE]);
      update_pc ();
      update_pc ();
      except_pending = 0;
      except_pending = 0;
      return  0;
      return  0;
    }
    }
 
 
  decode_execute_wrapper (&cpu_state.iqueue);
  decode_execute_wrapper (&cpu_state.iqueue);
  update_pc ();
  update_pc ();
  return  0;
  return  0;
 
 
}       /* cpu_clock() */
}       /* cpu_clock() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!If decoding cannot be found, call this function                           */
/*!If decoding cannot be found, call this function                           */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
#if SIMPLE_EXECUTION
#if SIMPLE_EXECUTION
void
void
l_invalid (struct iqueue_entry *current)
l_invalid (struct iqueue_entry *current)
{
{
#else
#else
void
void
l_invalid ()
l_invalid ()
{
{
#endif
#endif
  except_handle (EXCEPT_ILLEGAL, cpu_state.iqueue.insn_addr);
  except_handle (EXCEPT_ILLEGAL, cpu_state.iqueue.insn_addr);
 
 
}       /* l_invalid() */
}       /* l_invalid() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!The main execution loop                                                   */
/*!The main execution loop                                                   */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
void
void
exec_main ()
exec_main ()
{
{
  long long time_start;
  long long time_start;
 
 
  while (1)
  while (1)
    {
    {
      time_start = runtime.sim.cycles;
      time_start = runtime.sim.cycles;
      if (config.debug.enabled)
      if (config.debug.enabled)
        {
        {
          while (runtime.cpu.stalled)
          while (runtime.cpu.stalled)
            {
            {
              if (config.debug.rsp_enabled)
              if (config.debug.rsp_enabled)
                {
                {
                  handle_rsp ();
                  handle_rsp ();
                }
                }
              else if (config.debug.gdb_enabled)
              else if (config.debug.gdb_enabled)
                {
                {
                  block_jtag ();
                  block_jtag ();
                  handle_server_socket (FALSE);
                  handle_server_socket (FALSE);
                }
                }
              else
              else
                {
                {
                  fprintf (stderr, "ERROR: CPU stalled and GDB connection not "
                  fprintf (stderr, "ERROR: CPU stalled and GDB connection not "
                           "enabled: Invoking CLI and terminating.\n");
                           "enabled: Invoking CLI and terminating.\n");
                  /* Dump the user into interactive mode.  From there he or
                  /* Dump the user into interactive mode.  From there he or
                     she can decide what to do. */
                     she can decide what to do. */
                  handle_sim_command ();
                  handle_sim_command ();
                  sim_done ();
                  sim_done ();
                }
                }
              if (runtime.sim.iprompt)
              if (runtime.sim.iprompt)
                handle_sim_command ();
                handle_sim_command ();
            }
            }
        }
        }
 
 
      /* Each cycle has counter of mem_cycles; this value is joined with cycles
      /* Each cycle has counter of mem_cycles; this value is joined with cycles
         at the end of the cycle; no sim originated memory accesses should be
         at the end of the cycle; no sim originated memory accesses should be
         performed inbetween. */
         performed inbetween. */
      runtime.sim.mem_cycles = 0;
      runtime.sim.mem_cycles = 0;
 
 
      if (!config.pm.enabled ||
      if (!config.pm.enabled ||
          !(config.pm.enabled &
          !(config.pm.enabled &
            (cpu_state.sprs[SPR_PMR] & (SPR_PMR_DME | SPR_PMR_SME))))
            (cpu_state.sprs[SPR_PMR] & (SPR_PMR_DME | SPR_PMR_SME))))
        {
        {
          if (cpu_clock ())
          if (cpu_clock ())
            {
            {
              /* A breakpoint has been hit, drop to interactive mode */
              /* A breakpoint has been hit, drop to interactive mode */
              handle_sim_command ();
              handle_sim_command ();
            }
            }
        }
        }
 
 
      if (config.vapi.enabled && runtime.vapi.enabled)
      if (config.vapi.enabled && runtime.vapi.enabled)
        {
        {
          vapi_check ();
          vapi_check ();
        }
        }
 
 
      if (config.debug.gdb_enabled)
      if (config.debug.gdb_enabled)
        {
        {
          handle_server_socket (FALSE); /* block & check_stdin = false */
          handle_server_socket (FALSE); /* block & check_stdin = false */
        }
        }
 
 
      if (config.debug.enabled)
      if (config.debug.enabled)
        {
        {
          if (cpu_state.sprs[SPR_DMR1] & SPR_DMR1_ST)
          if (cpu_state.sprs[SPR_DMR1] & SPR_DMR1_ST)
            {
            {
              set_stall_state (1);
              set_stall_state (1);
 
 
              if (config.debug.rsp_enabled)
              if (config.debug.rsp_enabled)
                {
                {
                  rsp_exception (EXCEPT_TRAP);
                  rsp_exception (EXCEPT_TRAP);
                }
                }
            }
            }
        }
        }
 
 
      runtime.sim.cycles        += runtime.sim.mem_cycles;
      runtime.sim.cycles        += runtime.sim.mem_cycles;
      scheduler.job_queue->time -= runtime.sim.cycles - time_start;
      scheduler.job_queue->time -= runtime.sim.cycles - time_start;
 
 
      if (scheduler.job_queue->time <= 0)
      if (scheduler.job_queue->time <= 0)
        {
        {
          do_scheduler ();
          do_scheduler ();
        }
        }
    }
    }
}       /* exec_main() */
}       /* exec_main() */
 
 
#if COMPLEX_EXECUTION
#if COMPLEX_EXECUTION
 
 
/* Include generated/built in decode_execute function */
/* Include generated/built in decode_execute function */
#include "execgen.c"
#include "execgen.c"
 
 
#elif SIMPLE_EXECUTION
#elif SIMPLE_EXECUTION
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Evaluates source operand
/*!Evaluates source operand
 
 
   Implementation specific.
   Implementation specific.
 
 
   @param[in] op_no       The operand
   @param[in] op_no       The operand
   @param[in] insn_index  Address of the instruction
   @param[in] insn_index  Address of the instruction
   @param[in] insn        The instruction
   @param[in] insn        The instruction
 
 
   @return  The value of the operand                                         */
   @return  The value of the operand                                         */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static uorreg_t
static uorreg_t
eval_operand (int            op_no,
eval_operand (int            op_no,
              unsigned long  insn_index,
              unsigned long  insn_index,
              uint32_t       insn)
              uint32_t       insn)
{
{
  struct insn_op_struct *opd = op_start[insn_index];
  struct insn_op_struct *opd = op_start[insn_index];
  uorreg_t               ret;
  uorreg_t               ret;
 
 
  while (op_no)
  while (op_no)
    {
    {
      if (opd->type & OPTYPE_LAST)
      if (opd->type & OPTYPE_LAST)
        {
        {
          fprintf (stderr,
          fprintf (stderr,
                   "Instruction requested more operands than it has\n");
                   "Instruction requested more operands than it has\n");
          exit (1);
          exit (1);
        }
        }
 
 
      if ((opd->type & OPTYPE_OP) && !(opd->type & OPTYPE_DIS))
      if ((opd->type & OPTYPE_OP) && !(opd->type & OPTYPE_DIS))
        {
        {
          op_no--;
          op_no--;
        }
        }
 
 
      opd++;
      opd++;
    }
    }
 
 
  if (opd->type & OPTYPE_DIS)
  if (opd->type & OPTYPE_DIS)
    {
    {
      ret = eval_operand_val (insn, opd);
      ret = eval_operand_val (insn, opd);
 
 
      while (!(opd->type & OPTYPE_OP))
      while (!(opd->type & OPTYPE_OP))
        {
        {
          opd++;
          opd++;
        }
        }
 
 
      opd++;
      opd++;
      ret               += evalsim_reg (eval_operand_val (insn, opd));
      ret               += evalsim_reg (eval_operand_val (insn, opd));
      cpu_state.insn_ea  = ret;
      cpu_state.insn_ea  = ret;
 
 
      return  ret;
      return  ret;
    }
    }
 
 
  if (opd->type & OPTYPE_REG)
  if (opd->type & OPTYPE_REG)
    {
    {
      return  evalsim_reg (eval_operand_val (insn, opd));
      return  evalsim_reg (eval_operand_val (insn, opd));
    }
    }
 
 
  return  eval_operand_val (insn, opd);
  return  eval_operand_val (insn, opd);
 
 
}       /* eval_operand() */
}       /* eval_operand() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Set destination operand (register direct) with value.
/*!Set destination operand (register direct) with value.
 
 
   Implementation specific.
   Implementation specific.
 
 
   @param[in] op_no       The operand
   @param[in] op_no       The operand
   @param[in] value       The value to set
   @param[in] value       The value to set
   @param[in] insn_index  Address of the instruction
   @param[in] insn_index  Address of the instruction
   @param[in] insn        The instruction                                    */
   @param[in] insn        The instruction                                    */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
set_operand (int            op_no,
set_operand (int            op_no,
             orreg_t        value,
             orreg_t        value,
             unsigned long  insn_index,
             unsigned long  insn_index,
             uint32_t       insn)
             uint32_t       insn)
{
{
  struct insn_op_struct *opd = op_start[insn_index];
  struct insn_op_struct *opd = op_start[insn_index];
 
 
  while (op_no)
  while (op_no)
    {
    {
      if (opd->type & OPTYPE_LAST)
      if (opd->type & OPTYPE_LAST)
        {
        {
          fprintf (stderr,
          fprintf (stderr,
                   "Instruction requested more operands than it has\n");
                   "Instruction requested more operands than it has\n");
          exit (1);
          exit (1);
        }
        }
 
 
      if ((opd->type & OPTYPE_OP) && !(opd->type & OPTYPE_DIS))
      if ((opd->type & OPTYPE_OP) && !(opd->type & OPTYPE_DIS))
        {
        {
          op_no--;
          op_no--;
        }
        }
 
 
      opd++;
      opd++;
    }
    }
 
 
  if (!(opd->type & OPTYPE_REG))
  if (!(opd->type & OPTYPE_REG))
    {
    {
      fprintf (stderr, "Trying to set a non-register operand\n");
      fprintf (stderr, "Trying to set a non-register operand\n");
      exit (1);
      exit (1);
    }
    }
 
 
  setsim_reg (eval_operand_val (insn, opd), value);
  setsim_reg (eval_operand_val (insn, opd), value);
 
 
}       /* set_operand() */
}       /* set_operand() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Simple and rather slow decoding function
/*!Simple and rather slow decoding function
 
 
   Based on built automata.
   Based on built automata.
 
 
   @param[in] current  The current instruction to execute                    */
   @param[in] current  The current instruction to execute                    */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
decode_execute (struct iqueue_entry *current)
decode_execute (struct iqueue_entry *current)
{
{
  int insn_index;
  int insn_index;
 
 
  current->insn_index = insn_index = insn_decode (current->insn);
  current->insn_index = insn_index = insn_decode (current->insn);
 
 
  if (insn_index < 0)
  if (insn_index < 0)
    {
    {
      l_invalid (current);
      l_invalid (current);
    }
    }
  else
  else
    {
    {
      or32_opcodes[insn_index].exec (current);
      or32_opcodes[insn_index].exec (current);
    }
    }
 
 
  if (do_stats)
  if (do_stats)
    analysis (&cpu_state.iqueue);
    analysis (&cpu_state.iqueue);
}
}
 
 
#include "insnset.c"
#include "insnset.c"
 
 
#elif defined(DYNAMIC_EXECUTION)
#elif defined(DYNAMIC_EXECUTION)
 
 
#else
#else
# error "Must define SIMPLE_EXECUTION, COMPLEX_EXECUTION or DYNAMIC_EXECUTION"
# error "Must define SIMPLE_EXECUTION, COMPLEX_EXECUTION or DYNAMIC_EXECUTION"
#endif
#endif
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.