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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [or1ksim/] [libtoplevel.c] - Diff between revs 230 and 236

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

Rev 230 Rev 236
/* libtoplevel.c -- Top level simulator library source file
/* libtoplevel.c -- Top level simulator library source file
 
 
   Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
   Copyright (C) 1999 Damjan Lampret, lampret@opencores.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. */
 
 
 
 
/* Autoconf and/or portability configuration */
/* Autoconf and/or portability configuration */
#include "config.h"
#include "config.h"
 
 
/* System includes */
/* System includes */
#include <stdlib.h>
#include <stdlib.h>
#include <unistd.h>
#include <unistd.h>
#include <signal.h>
#include <signal.h>
 
 
/* Package includes */
/* Package includes */
#include "or1ksim.h"
#include "or1ksim.h"
#include "sim-config.h"
#include "sim-config.h"
#include "toplevel-support.h"
#include "toplevel-support.h"
#include "debug-unit.h"
#include "debug-unit.h"
#include "sched.h"
#include "sched.h"
#include "execute.h"
#include "execute.h"
#include "pic.h"
#include "pic.h"
#include "jtag.h"
#include "jtag.h"
#include "spr-defs.h"
#include "spr-defs.h"
#include "sprs.h"
#include "sprs.h"
 
 
 
 
/* Indices of GDB registers that are not GPRs. Must match GDB settings! */
/* Indices of GDB registers that are not GPRs. Must match GDB settings! */
#define MAX_GPRS    32                  /*!< Maximum GPRs */
#define MAX_GPRS    32                  /*!< Maximum GPRs */
#define PPC_REGNUM  (MAX_GPRS + 0)      /*!< Previous PC */
#define PPC_REGNUM  (MAX_GPRS + 0)      /*!< Previous PC */
#define NPC_REGNUM  (MAX_GPRS + 1)      /*!< Next PC */
#define NPC_REGNUM  (MAX_GPRS + 1)      /*!< Next PC */
#define SR_REGNUM   (MAX_GPRS + 2)      /*!< Supervision Register */
#define SR_REGNUM   (MAX_GPRS + 2)      /*!< Supervision Register */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Initialize the simulator.
/*!Initialize the simulator.
 
 
   The user can pass in any arguments acceptable to the standalone
   The user can pass in any arguments acceptable to the standalone
   simulator. Not all make any sense in a library environment.
   simulator. Not all make any sense in a library environment.
 
 
   @param[in] argc         Size of argument vector
   @param[in] argc         Size of argument vector
   @param[in] argv         Argument vector
   @param[in] argv         Argument vector
   @param[in] class_ptr    Pointer to a C++ class instance (for use when
   @param[in] class_ptr    Pointer to a C++ class instance (for use when
                           called by C++)
                           called by C++)
   @param[in] upr          Upcall routine for reads
   @param[in] upr          Upcall routine for reads
   @param[in] upw          Upcall routine for writes
   @param[in] upw          Upcall routine for writes
 
 
   @return  0 on success and an error code on failure                        */
   @return  0 on success and an error code on failure                        */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
int
int
or1ksim_init (int         argc,
or1ksim_init (int         argc,
              char       *argv[],
              char       *argv[],
              void       *class_ptr,
              void       *class_ptr,
              int       (*upr) (void              *class_ptr,
              int       (*upr) (void              *class_ptr,
                                unsigned long int  addr,
                                unsigned long int  addr,
                                unsigned char      mask[],
                                unsigned char      mask[],
                                unsigned char      rdata[],
                                unsigned char      rdata[],
                                int                data_len),
                                int                data_len),
              int       (*upw) (void              *class_ptr,
              int       (*upw) (void              *class_ptr,
                                unsigned long int  addr,
                                unsigned long int  addr,
                                unsigned char      mask[],
                                unsigned char      mask[],
                                unsigned char      wdata[],
                                unsigned char      wdata[],
                                int                data_len))
                                int                data_len))
{
{
  /* Initialization copied from existing main() */
  /* Initialization copied from existing main() */
  srand (getpid ());
  srand (getpid ());
  init_defconfig ();
  init_defconfig ();
  reg_config_secs ();
  reg_config_secs ();
 
 
  if (parse_args (argc, argv))
  if (parse_args (argc, argv))
    {
    {
      return OR1KSIM_RC_BADINIT;
      return OR1KSIM_RC_BADINIT;
    }
    }
 
 
  config.sim.is_library = 1;    /* Library operation */
  config.sim.is_library = 1;    /* Library operation */
  config.sim.profile    = 0;     /* No profiling */
  config.sim.profile    = 0;     /* No profiling */
  config.sim.mprofile   = 0;
  config.sim.mprofile   = 0;
 
 
  config.ext.class_ptr  = class_ptr;    /* SystemC linkage */
  config.ext.class_ptr  = class_ptr;    /* SystemC linkage */
  config.ext.read_up    = upr;
  config.ext.read_up    = upr;
  config.ext.write_up   = upw;
  config.ext.write_up   = upw;
 
 
  print_config ();              /* Will go eventually */
  print_config ();              /* Will go eventually */
  signal (SIGINT, ctrl_c);      /* Not sure we want this really */
  signal (SIGINT, ctrl_c);      /* Not sure we want this really */
 
 
  runtime.sim.hush = 1;         /* Not sure if this is needed */
  runtime.sim.hush = 1;         /* Not sure if this is needed */
  do_stats = config.cpu.superscalar ||
  do_stats = config.cpu.superscalar ||
             config.cpu.dependstats ||
             config.cpu.dependstats ||
             config.sim.history     ||
             config.sim.history     ||
             config.sim.exe_log;
             config.sim.exe_log;
 
 
  sim_init ();
  sim_init ();
 
 
  runtime.sim.ext_int_set = 0;   /* No interrupts pending to be set */
  runtime.sim.ext_int_set = 0;   /* No interrupts pending to be set */
  runtime.sim.ext_int_clr = 0;   /* No interrupts pending to be cleared */
  runtime.sim.ext_int_clr = 0;   /* No interrupts pending to be cleared */
 
 
  return OR1KSIM_RC_OK;
  return OR1KSIM_RC_OK;
 
 
}       /* or1ksim_init () */
}       /* or1ksim_init () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Run the simulator
/*!Run the simulator
 
 
   The argument is a time in seconds, which is converted to a number of
   The argument is a time in seconds, which is converted to a number of
   cycles, if positive. A negative value means "run for ever".
   cycles, if positive. A negative value means "run for ever".
 
 
   With the JTAG interface, it is possible to stall the processor between
   With the JTAG interface, it is possible to stall the processor between
   calls of this function (but not during upcalls). In which case we return
   calls of this function (but not during upcalls). In which case we return
   immediately.
   immediately.
 
 
   @todo Is it possible (or desirable) to permit JTAG activity during upcalls,
   @todo Is it possible (or desirable) to permit JTAG activity during upcalls,
         in which case we could stall mid-run.
         in which case we could stall mid-run.
 
 
   @todo Should the JTAG functionality require enabling?
   @todo Should the JTAG functionality require enabling?
 
 
   The semantics are that the duration for which the run may occur may be
   The semantics are that the duration for which the run may occur may be
   changed mid-run by a call to or1ksim_reset_duration(). This is to allow for
   changed mid-run by a call to or1ksim_reset_duration(). This is to allow for
   the upcalls to generic components adding time, and reducing the time
   the upcalls to generic components adding time, and reducing the time
   permitted for ISS execution before synchronization of the parent SystemC
   permitted for ISS execution before synchronization of the parent SystemC
   wrapper.
   wrapper.
 
 
   This is over-ridden if the call was for a negative duration, which means
   This is over-ridden if the call was for a negative duration, which means
   run forever!
   run forever!
 
 
   Uses a simplified version of the old main program loop. Returns success if
   Uses a simplified version of the old main program loop. Returns success if
   the requested number of cycles were run and an error code otherwise.
   the requested number of cycles were run and an error code otherwise.
 
 
   @param[in] duration  Time to execute for (seconds)
   @param[in] duration  Time to execute for (seconds)
 
 
   @return  OR1KSIM_RC_OK if we run to completion, OR1KSIM_RC_BRKPT if we hit
   @return  OR1KSIM_RC_OK if we run to completion, OR1KSIM_RC_BRKPT if we hit
            a breakpoint (not clear how this can be set without CLI access)  */
            a breakpoint (not clear how this can be set without CLI access)  */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
int
int
or1ksim_run (double duration)
or1ksim_run (double duration)
{
{
  const int  num_ints = sizeof (runtime.sim.ext_int_set) * 8;
  const int  num_ints = sizeof (runtime.sim.ext_int_set) * 8;
 
 
  /* If we are stalled we can't do anything. We treat this as hitting a
  /* If we are stalled we can't do anything. We treat this as hitting a
     breakpoint or halting. */
     breakpoint or halting. */
  if(runtime.cpu.stalled)
  if(runtime.cpu.stalled)
    {
    {
      return runtime.cpu.halted ? OR1KSIM_RC_HALTED : OR1KSIM_RC_BRKPT;
      return runtime.cpu.halted ? OR1KSIM_RC_HALTED : OR1KSIM_RC_BRKPT;
    }
    }
 
 
  /* Reset the duration */
  /* Reset the duration */
  or1ksim_reset_duration (duration);
  or1ksim_reset_duration (duration);
 
 
  /* Loop until we have done enough cycles (or forever if we had a negative
  /* Loop until we have done enough cycles (or forever if we had a negative
     duration) */
     duration) */
  while (duration < 0.0 || (runtime.sim.cycles < runtime.sim.end_cycles))
  while (duration < 0.0 || (runtime.sim.cycles < runtime.sim.end_cycles))
    {
    {
      long long int time_start = runtime.sim.cycles;
      long long int time_start = runtime.sim.cycles;
      int i;                    /* Interrupt # */
      int i;                    /* Interrupt # */
 
 
      /* 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 in between. */
       * performed in between. */
      runtime.sim.mem_cycles = 0;
      runtime.sim.mem_cycles = 0;
 
 
      if (cpu_clock ())
      if (cpu_clock ())
        {
        {
          /* This is probably wrong. This is an Or1ksim breakpoint, not a GNU
          /* This is probably wrong. This is an Or1ksim breakpoint, not a GNU
             one. */
             one. */
          return runtime.cpu.halted ? OR1KSIM_RC_HALTED : OR1KSIM_RC_BRKPT;
          return runtime.cpu.halted ? OR1KSIM_RC_HALTED : OR1KSIM_RC_BRKPT;
        }
        }
 
 
 
      /* If we were single stepping, stall immediately. */
 
      if (cpu_state.sprs[SPR_DMR1] & SPR_DMR1_ST)
 
        {
 
          set_stall_state (1);
 
        }
 
 
      /* If we are stalled we can't do anything. We treat this as hitting a
      /* If we are stalled we can't do anything. We treat this as hitting a
         breakpoint or halting. */
         breakpoint or halting. */
      if(runtime.cpu.stalled)
      if(runtime.cpu.stalled)
        {
        {
          return runtime.cpu.halted ? OR1KSIM_RC_HALTED : OR1KSIM_RC_BRKPT;
          return runtime.cpu.halted ? OR1KSIM_RC_HALTED : OR1KSIM_RC_BRKPT;
        }
        }
 
 
      runtime.sim.cycles += runtime.sim.mem_cycles;
      runtime.sim.cycles += runtime.sim.mem_cycles;
 
 
      /* Take any external interrupts. Outer test is for the common case for
      /* Take any external interrupts. Outer test is for the common case for
         efficiency. */
         efficiency. */
      if (0 != runtime.sim.ext_int_set)
      if (0 != runtime.sim.ext_int_set)
        {
        {
          for (i = 0; i < num_ints; i++)
          for (i = 0; i < num_ints; i++)
            {
            {
              if (0x1 == ((runtime.sim.ext_int_set >> i) & 0x1))
              if (0x1 == ((runtime.sim.ext_int_set >> i) & 0x1))
                {
                {
                  report_interrupt (i);
                  report_interrupt (i);
                  runtime.sim.ext_int_set &= ~(1 << i); /* Clear req flag */
                  runtime.sim.ext_int_set &= ~(1 << i); /* Clear req flag */
                }
                }
            }
            }
        }
        }
 
 
      /* Clear any interrupts as requested. For edge triggered interrupts this
      /* Clear any interrupts as requested. For edge triggered interrupts this
         will happen in the same cycle. For level triggered, it must be an
         will happen in the same cycle. For level triggered, it must be an
         explicit call. */
         explicit call. */
      if (0 != runtime.sim.ext_int_clr)
      if (0 != runtime.sim.ext_int_clr)
        {
        {
          for (i = 0; i < num_ints; i++)
          for (i = 0; i < num_ints; i++)
            {
            {
              /* Only clear interrupts that have been explicitly cleared */
              /* Only clear interrupts that have been explicitly cleared */
              if(0x1 == ((runtime.sim.ext_int_clr >> i) & 0x1))
              if(0x1 == ((runtime.sim.ext_int_clr >> i) & 0x1))
                {
                {
                  clear_interrupt(i);
                  clear_interrupt(i);
                  runtime.sim.ext_int_clr &= ~(1 << i); /* Clear clr flag */
                  runtime.sim.ext_int_clr &= ~(1 << i); /* Clear clr flag */
                }
                }
            }
            }
        }
        }
 
 
      /* Update the scheduler queue */
      /* Update the scheduler queue */
      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 ();
        }
        }
    }
    }
 
 
  return  OR1KSIM_RC_OK;
  return  OR1KSIM_RC_OK;
 
 
}       /* or1ksim_run () */
}       /* or1ksim_run () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Reset the run-time simulation end point
/*!Reset the run-time simulation end point
 
 
  Reset the time for which the simulation should run to the specified duration
  Reset the time for which the simulation should run to the specified duration
  from NOW (i.e. NOT from when the run started).
  from NOW (i.e. NOT from when the run started).
 
 
  @param[in] duration  Time to run for in seconds                            */
  @param[in] duration  Time to run for in seconds                            */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
void
void
or1ksim_reset_duration (double duration)
or1ksim_reset_duration (double duration)
{
{
  runtime.sim.end_cycles =
  runtime.sim.end_cycles =
    runtime.sim.cycles +
    runtime.sim.cycles +
    (long long int) (duration * 1.0e12 / (double) config.sim.clkcycle_ps);
    (long long int) (duration * 1.0e12 / (double) config.sim.clkcycle_ps);
 
 
}       /* or1ksim_reset_duration () */
}       /* or1ksim_reset_duration () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Return time executed so far
/*!Return time executed so far
 
 
   Internal utility to return the time executed so far. Note that this is a
   Internal utility to return the time executed so far. Note that this is a
   re-entrant routine.
   re-entrant routine.
 
 
   @return  Time executed so far in seconds                                  */
   @return  Time executed so far in seconds                                  */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static double
static double
internal_or1ksim_time ()
internal_or1ksim_time ()
{
{
  return (double) runtime.sim.cycles * (double) config.sim.clkcycle_ps /
  return (double) runtime.sim.cycles * (double) config.sim.clkcycle_ps /
    1.0e12;
    1.0e12;
 
 
}       // or1ksim_cycle_count()
}       // or1ksim_cycle_count()
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Mark a time point in the simulation
/*!Mark a time point in the simulation
 
 
   Sets the internal parameter recording this point in the simulation        */
   Sets the internal parameter recording this point in the simulation        */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
void
void
or1ksim_set_time_point ()
or1ksim_set_time_point ()
{
{
  runtime.sim.time_point = internal_or1ksim_time ();
  runtime.sim.time_point = internal_or1ksim_time ();
 
 
}       /* or1ksim_set_time_point () */
}       /* or1ksim_set_time_point () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Return the time since the time point was set
/*!Return the time since the time point was set
 
 
  Get the value from the internal parameter                                  */
  Get the value from the internal parameter                                  */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
double
double
or1ksim_get_time_period ()
or1ksim_get_time_period ()
{
{
  return internal_or1ksim_time () - runtime.sim.time_point;
  return internal_or1ksim_time () - runtime.sim.time_point;
 
 
}       /* or1ksim_get_time_period () */
}       /* or1ksim_get_time_period () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Return the endianism of the model
/*!Return the endianism of the model
 
 
   Note that this is a re-entrant routine.
   Note that this is a re-entrant routine.
 
 
   @return 1 if the model is little endian, 0 otherwise.                     */
   @return 1 if the model is little endian, 0 otherwise.                     */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
int
int
or1ksim_is_le ()
or1ksim_is_le ()
{
{
#ifdef OR32_BIG_ENDIAN
#ifdef OR32_BIG_ENDIAN
  return 0;
  return 0;
#else
#else
  return 1;
  return 1;
#endif
#endif
 
 
}       /* or1ksim_is_le () */
}       /* or1ksim_is_le () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Return the clock rate
/*!Return the clock rate
 
 
   Value is part of the configuration
   Value is part of the configuration
 
 
   @return  Clock rate in Hz.                                                */
   @return  Clock rate in Hz.                                                */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
unsigned long int
unsigned long int
or1ksim_clock_rate ()
or1ksim_clock_rate ()
{
{
  return (unsigned long int) (1000000000000ULL /
  return (unsigned long int) (1000000000000ULL /
                              (unsigned long long int) (config.sim.
                              (unsigned long long int) (config.sim.
                                                        clkcycle_ps));
                                                        clkcycle_ps));
}       /* or1ksim_clock_rate () */
}       /* or1ksim_clock_rate () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Trigger an edge triggered interrupt
/*!Trigger an edge triggered interrupt
 
 
   This function is appropriate for edge triggered interrupts, which are taken
   This function is appropriate for edge triggered interrupts, which are taken
   and then immediately cleared.
   and then immediately cleared.
 
 
   @note There is no check that the specified interrupt number is reasonable
   @note There is no check that the specified interrupt number is reasonable
   (i.e. <= 31).
   (i.e. <= 31).
 
 
   @param[in] i  The interrupt number                                        */
   @param[in] i  The interrupt number                                        */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
void
void
or1ksim_interrupt (int i)
or1ksim_interrupt (int i)
{
{
  if (!config.pic.edge_trigger)
  if (!config.pic.edge_trigger)
    {
    {
      fprintf (stderr, "Warning: or1ksim_interrupt should not be used for "
      fprintf (stderr, "Warning: or1ksim_interrupt should not be used for "
               "level triggered interrupts. Ignored\n");
               "level triggered interrupts. Ignored\n");
    }
    }
  else
  else
    {
    {
      runtime.sim.ext_int_set |= 1 << i;        // Better not be > 31!
      runtime.sim.ext_int_set |= 1 << i;        // Better not be > 31!
      runtime.sim.ext_int_clr |= 1 << i;        // Better not be > 31!
      runtime.sim.ext_int_clr |= 1 << i;        // Better not be > 31!
    }
    }
}       /* or1ksim_interrupt () */
}       /* or1ksim_interrupt () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Set a level triggered interrupt
/*!Set a level triggered interrupt
 
 
   This function is appropriate for level triggered interrupts, which must be
   This function is appropriate for level triggered interrupts, which must be
   explicitly cleared in a separate call.
   explicitly cleared in a separate call.
 
 
   @note There is no check that the specified interrupt number is reasonable
   @note There is no check that the specified interrupt number is reasonable
   (i.e. <= 31).
   (i.e. <= 31).
 
 
   @param[in] i  The interrupt number to set                                 */
   @param[in] i  The interrupt number to set                                 */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
void
void
or1ksim_interrupt_set (int i)
or1ksim_interrupt_set (int i)
{
{
  if (config.pic.edge_trigger)
  if (config.pic.edge_trigger)
    {
    {
      fprintf (stderr, "Warning: or1ksim_interrupt_set should not be used for "
      fprintf (stderr, "Warning: or1ksim_interrupt_set should not be used for "
               "edge triggered interrupts. Ignored\n");
               "edge triggered interrupts. Ignored\n");
    }
    }
  else
  else
    {
    {
      runtime.sim.ext_int_set |= 1 << i;        // Better not be > 31!
      runtime.sim.ext_int_set |= 1 << i;        // Better not be > 31!
    }
    }
}       /* or1ksim_interrupt () */
}       /* or1ksim_interrupt () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Clear a level triggered interrupt
/*!Clear a level triggered interrupt
 
 
   This function is appropriate for level triggered interrupts, which must be
   This function is appropriate for level triggered interrupts, which must be
   explicitly set first in a separate call.
   explicitly set first in a separate call.
 
 
   @note There is no check that the specified interrupt number is reasonable
   @note There is no check that the specified interrupt number is reasonable
   (i.e. <= 31).
   (i.e. <= 31).
 
 
   @param[in] i  The interrupt number to clear                               */
   @param[in] i  The interrupt number to clear                               */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
void
void
or1ksim_interrupt_clear (int i)
or1ksim_interrupt_clear (int i)
{
{
  if (config.pic.edge_trigger)
  if (config.pic.edge_trigger)
    {
    {
      fprintf (stderr, "Warning: or1ksim_interrupt_clear should not be used "
      fprintf (stderr, "Warning: or1ksim_interrupt_clear should not be used "
               "for edge triggered interrupts. Ignored\n");
               "for edge triggered interrupts. Ignored\n");
    }
    }
  else
  else
    {
    {
      runtime.sim.ext_int_clr |= 1 << i;        // Better not be > 31!
      runtime.sim.ext_int_clr |= 1 << i;        // Better not be > 31!
    }
    }
}       /* or1ksim_interrupt () */
}       /* or1ksim_interrupt () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Reset the JTAG interface
/*!Reset the JTAG interface
 
 
   @note Like all the JTAG interface functions, this must not be called
   @note Like all the JTAG interface functions, this must not be called
         re-entrantly while a call to any other function (e.g. or1kim_run ())
         re-entrantly while a call to any other function (e.g. or1kim_run ())
         is in progress. It is the responsibility of the caller to ensure this
         is in progress. It is the responsibility of the caller to ensure this
         constraint is met, for example by use of a SystemC mutex.
         constraint is met, for example by use of a SystemC mutex.
 
 
   @return  The time in seconds which the reset took.                        */
   @return  The time in seconds which the reset took.                        */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
double
double
or1ksim_jtag_reset ()
or1ksim_jtag_reset ()
{
{
  /* Number of JTAG clock cycles a reset sequence takes */
  /* Number of JTAG clock cycles a reset sequence takes */
  const double  JTAG_RESET_CYCLES = 5.0;
  const double  JTAG_RESET_CYCLES = 5.0;
 
 
  jtag_reset ();
  jtag_reset ();
 
 
  return  JTAG_RESET_CYCLES  * (double) config.debug.jtagcycle_ps / 1.0e12;
  return  JTAG_RESET_CYCLES  * (double) config.debug.jtagcycle_ps / 1.0e12;
 
 
}       /* or1ksim_jtag_reset () */
}       /* or1ksim_jtag_reset () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Shift a JTAG instruction register
/*!Shift a JTAG instruction register
 
 
   @note Like all the JTAG interface functions, this must not be called
   @note Like all the JTAG interface functions, this must not be called
         re-entrantly while a call to any other function (e.g. or1kim_run ())
         re-entrantly while a call to any other function (e.g. or1kim_run ())
         is in progress. It is the responsibility of the caller to ensure this
         is in progress. It is the responsibility of the caller to ensure this
         constraint is met, for example by use of a SystemC mutex.
         constraint is met, for example by use of a SystemC mutex.
 
 
   The register is represented as a vector of bytes, with the byte at offset
   The register is represented as a vector of bytes, with the byte at offset
   zero being shifted first, and the least significant bit in each byte being
   zero being shifted first, and the least significant bit in each byte being
   shifted first. Where the register will not fit in an exact number of bytes,
   shifted first. Where the register will not fit in an exact number of bytes,
   the odd bits are in the highest numbered byte, shifted to the low end.
   the odd bits are in the highest numbered byte, shifted to the low end.
 
 
   The only JTAG instruction for which we have any significant behavior in
   The only JTAG instruction for which we have any significant behavior in
   this model is DEBUG. For completeness the register is parsed and a warning
   this model is DEBUG. For completeness the register is parsed and a warning
   given if any register other than DEBUG is shifted.
   given if any register other than DEBUG is shifted.
 
 
   @param[in,out] jreg      The register to shift in, and the register shifted
   @param[in,out] jreg      The register to shift in, and the register shifted
                            back out.
                            back out.
   @param[in]     num_bits  The number of bits in the register. Just for
   @param[in]     num_bits  The number of bits in the register. Just for
                            sanity check (it should always be 4).
                            sanity check (it should always be 4).
 
 
   @return  The time in seconds which the shift took.                        */
   @return  The time in seconds which the shift took.                        */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
double
double
or1ksim_jtag_shift_ir (unsigned char *jreg,
or1ksim_jtag_shift_ir (unsigned char *jreg,
                       int            num_bits)
                       int            num_bits)
{
{
  jtag_shift_ir (jreg, num_bits);
  jtag_shift_ir (jreg, num_bits);
 
 
  return  (double) num_bits * (double) config.debug.jtagcycle_ps / 1.0e12;
  return  (double) num_bits * (double) config.debug.jtagcycle_ps / 1.0e12;
 
 
}       /* or1ksim_jtag_shift_ir () */
}       /* or1ksim_jtag_shift_ir () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Shift a JTAG data register
/*!Shift a JTAG data register
 
 
   @note Like all the JTAG interface functions, this must not be called
   @note Like all the JTAG interface functions, this must not be called
         re-entrantly while a call to any other function (e.g. or1kim_run ())
         re-entrantly while a call to any other function (e.g. or1kim_run ())
         is in progress. It is the responsibility of the caller to ensure this
         is in progress. It is the responsibility of the caller to ensure this
         constraint is met, for example by use of a SystemC mutex.
         constraint is met, for example by use of a SystemC mutex.
 
 
   The register is represented as a vector of bytes, with the byte at offset
   The register is represented as a vector of bytes, with the byte at offset
   zero being shifted first, and the least significant bit in each byte being
   zero being shifted first, and the least significant bit in each byte being
   shifted first. Where the register will not fit in an exact number of bytes,
   shifted first. Where the register will not fit in an exact number of bytes,
   the odd bits are in the highest numbered byte, shifted to the low end.
   the odd bits are in the highest numbered byte, shifted to the low end.
 
 
   The register is parsed to determine which of the six possible register
   The register is parsed to determine which of the six possible register
   types it could be.
   types it could be.
   - MODULE_SELECT
   - MODULE_SELECT
   - WRITE_COMMNAND
   - WRITE_COMMNAND
   - READ_COMMAND
   - READ_COMMAND
   - GO_COMMAND
   - GO_COMMAND
   - WRITE_CONTROL
   - WRITE_CONTROL
   - READ_CONTROL
   - READ_CONTROL
 
 
   @note In practice READ_COMMAND is not used. However the functionality is
   @note In practice READ_COMMAND is not used. However the functionality is
         provided for future compatibility.
         provided for future compatibility.
 
 
   @param[in,out] jreg      The register to shift in, and the register shifted
   @param[in,out] jreg      The register to shift in, and the register shifted
                            back out.
                            back out.
   @param[in]     num_bits  The number of bits in the register. This is
   @param[in]     num_bits  The number of bits in the register. This is
                            essential to prevent bugs where the size of
                            essential to prevent bugs where the size of
                            register supplied is incorrect.
                            register supplied is incorrect.
 
 
   @return  The time in seconds which the shift took.                        */
   @return  The time in seconds which the shift took.                        */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
double
double
or1ksim_jtag_shift_dr (unsigned char *jreg,
or1ksim_jtag_shift_dr (unsigned char *jreg,
                       int            num_bits)
                       int            num_bits)
{
{
  jtag_shift_dr (jreg, num_bits);
  jtag_shift_dr (jreg, num_bits);
 
 
  return  (double) num_bits * (double) config.debug.jtagcycle_ps / 1.0e12;
  return  (double) num_bits * (double) config.debug.jtagcycle_ps / 1.0e12;
 
 
}       /* or1ksim_jtag_shift_dr () */
}       /* or1ksim_jtag_shift_dr () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Read a block of memory.
/*!Read a block of memory.
 
 
   @param[in]  addr  The address to read from.
   @param[in]  addr  The address to read from.
   @param[out] buf   Where to put the data.
   @param[out] buf   Where to put the data.
   @param[in]  len   The number of bytes to read.
   @param[in]  len   The number of bytes to read.
 
 
   @return  Number of bytes read, or zero if error.                          */
   @return  Number of bytes read, or zero if error.                          */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
int
int
or1ksim_read_mem (unsigned long int  addr,
or1ksim_read_mem (unsigned long int  addr,
                  unsigned char     *buf,
                  unsigned char     *buf,
                  int                len)
                  int                len)
{
{
  int             off;                  /* Offset into the memory */
  int             off;                  /* Offset into the memory */
 
 
  /* Fill the buffer with data */
  /* Fill the buffer with data */
  for (off = 0; off < len; off++)
  for (off = 0; off < len; off++)
    {
    {
      /* Check memory area is valid */
      /* Check memory area is valid */
      if (NULL == verify_memoryarea (addr + off))
      if (NULL == verify_memoryarea (addr + off))
        {
        {
          /* Fail silently - others can raise any error message. */
          /* Fail silently - others can raise any error message. */
          return  0;
          return  0;
        }
        }
      else
      else
        {
        {
          /* Get the memory direct - no translation. */
          /* Get the memory direct - no translation. */
          buf[off] = eval_direct8 (addr + off, 0, 0);
          buf[off] = eval_direct8 (addr + off, 0, 0);
        }
        }
    }
    }
 
 
  return  len;
  return  len;
 
 
}       /* or1ksim_read_mem () */
}       /* or1ksim_read_mem () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Write a block of memory.
/*!Write a block of memory.
 
 
   @param[in] addr  The address to write to.
   @param[in] addr  The address to write to.
   @param[in] buf   Where to get the data from.
   @param[in] buf   Where to get the data from.
   @param[in] len   The number of bytes to write.
   @param[in] len   The number of bytes to write.
 
 
   @return  Number of bytes written, or zero if error.                       */
   @return  Number of bytes written, or zero if error.                       */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
int
int
or1ksim_write_mem (unsigned long int  addr,
or1ksim_write_mem (unsigned long int  addr,
                   unsigned char     *buf,
                   unsigned char     *buf,
                   int                len)
                   int                len)
{
{
  int             off;                  /* Offset into the memory */
  int             off;                  /* Offset into the memory */
 
 
  /* Write the bytes to memory */
  /* Write the bytes to memory */
  for (off = 0; off < len; off++)
  for (off = 0; off < len; off++)
    {
    {
      if (NULL == verify_memoryarea (addr + off))
      if (NULL == verify_memoryarea (addr + off))
        {
        {
          /* Fail silently - others can raise any error message. */
          /* Fail silently - others can raise any error message. */
          return  0;
          return  0;
        }
        }
      else
      else
        {
        {
          /* circumvent the read-only check usually done for mem accesses data
          /* circumvent the read-only check usually done for mem accesses data
             is in host order, because that's what set_direct32 needs */
             is in host order, because that's what set_direct32 needs */
          set_program8 (addr + off, buf[off]);
          set_program8 (addr + off, buf[off]);
        }
        }
    }
    }
 
 
  return  len;
  return  len;
 
 
}       /* or1ksim_write_mem () */
}       /* or1ksim_write_mem () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Read a SPR
/*!Read a SPR
 
 
   @param[in]  sprnum      The SPR to read.
   @param[in]  sprnum      The SPR to read.
   @param[out] sprval_ptr  Where to put the data.
   @param[out] sprval_ptr  Where to put the data.
 
 
   @return  Non-zero (TRUE) on success, zero (FALSE) otherwise.              */
   @return  Non-zero (TRUE) on success, zero (FALSE) otherwise.              */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
int
int
or1ksim_read_spr (int                sprnum,
or1ksim_read_spr (int                sprnum,
                  unsigned long int *sprval_ptr)
                  unsigned long int *sprval_ptr)
{
{
  /* SPR numbers are up to 16 bits long */
  /* SPR numbers are up to 16 bits long */
  if ((unsigned int) sprnum <= 0xffff)
  if ((unsigned int) sprnum <= 0xffff)
    {
    {
      *sprval_ptr = (unsigned int) mfspr ((uint16_t) sprnum);
      *sprval_ptr = (unsigned int) mfspr ((uint16_t) sprnum);
      return  1;
      return  1;
    }
    }
  else
  else
    {
    {
      return  0;                 /* Silent failure */
      return  0;                 /* Silent failure */
    }
    }
}       /* or1skim_read_spr () */
}       /* or1skim_read_spr () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Write a SPR
/*!Write a SPR
 
 
   @param[in] sprnum  The SPR to write.
   @param[in] sprnum  The SPR to write.
   @param[in] sprval  The data to write.
   @param[in] sprval  The data to write.
 
 
   @return  Non-zero (TRUE) on success, zero (FALSE) otherwise.              */
   @return  Non-zero (TRUE) on success, zero (FALSE) otherwise.              */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
int
int
or1ksim_write_spr (int                sprnum,
or1ksim_write_spr (int                sprnum,
                   unsigned long int  sprval)
                   unsigned long int  sprval)
{
{
  /* SPR numbers are up to 16 bits long */
  /* SPR numbers are up to 16 bits long */
  if ((unsigned int) sprnum <= 0xffff)
  if ((unsigned int) sprnum <= 0xffff)
    {
    {
      mtspr ((uint16_t) sprnum, sprval);
      mtspr ((uint16_t) sprnum, sprval);
      return  1;
      return  1;
    }
    }
  else
  else
    {
    {
      return  0;                 /* Silent failure */
      return  0;                 /* Silent failure */
    }
    }
}       /* or1ksim_write_spr () */
}       /* or1ksim_write_spr () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Read a single register
/*!Read a single register
 
 
   The registers follow the GDB sequence for OR1K: GPR0 through GPR31, PC
   The registers follow the GDB sequence for OR1K: GPR0 through GPR31, PC
   (i.e. SPR NPC) and SR (i.e. SPR SR).
   (i.e. SPR NPC) and SR (i.e. SPR SR).
 
 
   Map to the corresponding SPR.
   Map to the corresponding SPR.
 
 
   @param[in]  regnum      The register to read.
   @param[in]  regnum      The register to read.
   @param[out] regval_ptr  Where to put the data.
   @param[out] regval_ptr  Where to put the data.
 
 
   @return  Non-zero (TRUE) on success, zero (FALSE) otherwise.              */
   @return  Non-zero (TRUE) on success, zero (FALSE) otherwise.              */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
int
int
or1ksim_read_reg (int                 regnum,
or1ksim_read_reg (int                 regnum,
                  unsigned long int  *regval_ptr)
                  unsigned long int  *regval_ptr)
{
{
  /* GPR's */
  /* GPR's */
  if (regnum < MAX_GPRS)
  if (regnum < MAX_GPRS)
    {
    {
      return or1ksim_read_spr (regnum + SPR_GPR_BASE, regval_ptr);
      return or1ksim_read_spr (regnum + SPR_GPR_BASE, regval_ptr);
    }
    }
 
 
  /* SPR's or unknown */
  /* SPR's or unknown */
  switch (regnum)
  switch (regnum)
    {
    {
    case PPC_REGNUM: return or1ksim_read_spr (SPR_PPC, regval_ptr);
    case PPC_REGNUM: return or1ksim_read_spr (SPR_PPC, regval_ptr);
    case NPC_REGNUM: return or1ksim_read_spr (SPR_NPC, regval_ptr);
    case NPC_REGNUM: return or1ksim_read_spr (SPR_NPC, regval_ptr);
    case SR_REGNUM:  return or1ksim_read_spr (SPR_SR, regval_ptr);
    case SR_REGNUM:  return or1ksim_read_spr (SPR_SR, regval_ptr);
    default:
    default:
      /* Silent error response if we don't know the register */
      /* Silent error response if we don't know the register */
      return  0;
      return  0;
    }
    }
}       /* or1ksim_read_reg () */
}       /* or1ksim_read_reg () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Write a single register
/*!Write a single register
 
 
   The registers follow the GDB sequence for OR1K: GPR0 through GPR31, PC
   The registers follow the GDB sequence for OR1K: GPR0 through GPR31, PC
   (i.e. SPR NPC) and SR (i.e. SPR SR).
   (i.e. SPR NPC) and SR (i.e. SPR SR).
 
 
   Map to the corresponding SPR
   Map to the corresponding SPR
 
 
   @param[in] regval  The register to write.
   @param[in] regval  The register to write.
   @param[in] regnum  The register to write.
   @param[in] regnum  The register to write.
 
 
   @return  Non-zero (TRUE) on success, zero (FALSE) otherwise.              */
   @return  Non-zero (TRUE) on success, zero (FALSE) otherwise.              */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
int
int
or1ksim_write_reg (int                regnum,
or1ksim_write_reg (int                regnum,
                   unsigned long int  regval)
                   unsigned long int  regval)
{
{
  /* GPR's */
  /* GPR's */
  if (regnum < MAX_GPRS)
  if (regnum < MAX_GPRS)
    {
    {
      return or1ksim_write_spr (regnum + SPR_GPR_BASE, regval);
      return or1ksim_write_spr (regnum + SPR_GPR_BASE, regval);
    }
    }
 
 
  /* SPR's or unknown */
  /* SPR's or unknown */
  switch (regnum)
  switch (regnum)
    {
    {
    case PPC_REGNUM: return or1ksim_write_spr (SPR_PPC, regval);
    case PPC_REGNUM: return or1ksim_write_spr (SPR_PPC, regval);
    case NPC_REGNUM: return or1ksim_write_spr (SPR_NPC, regval);
    case NPC_REGNUM: return or1ksim_write_spr (SPR_NPC, regval);
    case SR_REGNUM:  return or1ksim_write_spr (SPR_SR,  regval);
    case SR_REGNUM:  return or1ksim_write_spr (SPR_SR,  regval);
    default:
    default:
      /* Silent error response if we don't know the register */
      /* Silent error response if we don't know the register */
      return  0;
      return  0;
    }
    }
}       /* or1ksim_write_reg () */
}       /* or1ksim_write_reg () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Set the simulator stall state.
/*!Set the simulator stall state.
 
 
   @param[in] state  The stall state to set.                                 */
   @param[in] state  The stall state to set.                                 */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
void
void
or1ksim_set_stall_state (int  state)
or1ksim_set_stall_state (int  state)
{
{
  set_stall_state (state ? 1 : 0);
  set_stall_state (state ? 1 : 0);
 
 
}       /* or1ksim_set_stall_state () */
}       /* or1ksim_set_stall_state () */
 
 

powered by: WebSVN 2.1.0

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