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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [or1ksim/] [libtoplevel.c] - Rev 1780

Go to most recent revision | Compare with Previous | Blame | View Log

/* libtoplevel.c -- Top level simulator library source file
 
   Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
   Copyright (C) 2008 Embecosm Limited
 
   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
   This file is part of OpenRISC 1000 Architectural Simulator.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the Free
   Software Foundation; either version 3 of the License, or (at your option)
   any later version.
 
   This program is distributed in the hope that it will be useful, but WITHOUT
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   more details.
 
   You should have received a copy of the GNU General Public License along
   with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
/* This program is commented throughout in a fashion suitable for processing
   with Doxygen. */
 
 
/* Autoconf and/or portability configuration */
#include "config.h"
 
/* System includes */
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
 
/* Package includes */
#include "or1ksim.h"
#include "sim-config.h"
#include "toplevel-support.h"
#include "sched.h"
#include "execute.h"
#include "pic.h"
 
 
/*---------------------------------------------------------------------------*/
/*!Initialize the simulator. 
 
   Allows specification of an (optional) config file and an image file. Builds
   up dummy argc/argv to pass to the existing argument parser.
 
   @param[in] config_file  Or1ksim configuration file name
   @param[in] image_file   The program image to execute
   @param[in] class_ptr    Pointer to a C++ class instance (for use when
                           called by C++)
   @param[in] upr          Upcall routine for reads
   @param[in] upw          Upcall routine for writes
 
   @return  0 on success and an error code on failure                        */
/*---------------------------------------------------------------------------*/
int
or1ksim_init (const char *config_file,
	      const char *image_file,
	      void       *class_ptr,
	      unsigned long int (*upr) (void *class_ptr,
					unsigned long int addr,
					unsigned long int mask),
	      void (*upw) (void *class_ptr,
			   unsigned long int addr,
			   unsigned long int mask, unsigned long int wdata))
{
  int   dummy_argc;
  char *dummy_argv[4];
 
  /* Dummy argv array. Varies depending on whether an image file is
     specified. */
  dummy_argv[0] = "libsim";
  dummy_argv[1] = "-f";
  dummy_argv[2] = (char *) ((NULL != config_file) ? config_file : "sim.cfg");
  dummy_argv[3] = (char *) image_file;
 
  dummy_argc = (NULL == image_file) ? 3 : 4;
 
  /* Initialization copied from existing main() */
  srand (getpid ());
  init_defconfig ();
  reg_config_secs ();
 
  if (parse_args (dummy_argc, dummy_argv))
    {
      return OR1KSIM_RC_BADINIT;
    }
 
  config.sim.profile   = 0;	/* No profiling */
  config.sim.mprofile  = 0;
 
  config.ext.class_ptr = class_ptr;	/* SystemC linkage */
  config.ext.read_up   = upr;
  config.ext.write_up  = upw;
 
  print_config ();		/* Will go eventually */
  signal (SIGINT, ctrl_c);	/* Not sure we want this really */
 
  runtime.sim.hush = 1;		/* Not sure if this is needed */
  do_stats = config.cpu.superscalar ||
             config.cpu.dependstats ||
             config.sim.history     ||
             config.sim.exe_log;
 
  sim_init ();
 
  runtime.sim.ext_int_set = 0;	/* No interrupts pending to be set */
  runtime.sim.ext_int_clr = 0;	/* No interrupts pending to be cleared */
 
  return OR1KSIM_RC_OK;
 
}	/* or1ksim_init() */
 
 
/*---------------------------------------------------------------------------*/
/*!Run the simulator
 
   The argument is a time in seconds, which is converted to a number of
   cycles, if positive. A negative value means "run for ever".
 
   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
   the upcalls to generic components adding time, and reducing the time
   permitted for ISS execution before synchronization of the parent SystemC
   wrapper.
 
   This is over-ridden if the call was for a negative duration, which means
   run forever!
 
   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.
 
   @param[in] duration  Time to execute for (seconds)
 
   @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)  */
/*---------------------------------------------------------------------------*/
int
or1ksim_run (double duration)
{
  const int  num_ints = sizeof (runtime.sim.ext_int_set) * 8;
 
  or1ksim_reset_duration (duration);
 
  /* Loop until we have done enough cycles (or forever if we had a negative
     duration) */
  while (duration < 0.0 || (runtime.sim.cycles < runtime.sim.end_cycles))
    {
 
      long long int time_start = runtime.sim.cycles;
      int i;			/* Interrupt # */
 
      /* 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
       * performed inbetween.
       */
 
      runtime.sim.mem_cycles = 0;
 
      if (cpu_clock ())
	{
	  return OR1KSIM_RC_BRKPT;	/* Hit a breakpoint */
	}
 
      runtime.sim.cycles += runtime.sim.mem_cycles;
 
      /* Take any external interrupts. Outer test is for the common case for
         efficiency. */
      if (0 != runtime.sim.ext_int_set)
	{
	  for (i = 0; i < num_ints; i++)
	    {
	      if (0x1 == ((runtime.sim.ext_int_set >> i) & 0x1))
		{
		  report_interrupt (i);
		  runtime.sim.ext_int_set &= ~(1 << i);	/* Clear req flag */
		}
	    }
	}
 
      /* Clear any interrupts as requested. For edge triggered interrupts this
	 will happen in the same cycle. For level triggered, it must be an
	 explicit call. */
      if (0 != runtime.sim.ext_int_clr)
	{
	  for (i = 0; i < num_ints; i++)
	    {
	      /* Only clear interrupts that have been explicitly cleared */
	      if(0x1 == ((runtime.sim.ext_int_clr >> i) & 0x1))
		{
		  clear_interrupt(i);
		  runtime.sim.ext_int_clr &= ~(1 << i); /* Clear clr flag */
		}
	    }
	}
 
      /* Update the scheduler queue */
 
      scheduler.job_queue->time -= (runtime.sim.cycles - time_start);
 
      if (scheduler.job_queue->time <= 0)
	{
	  do_scheduler ();
	}
    }
 
  return  OR1KSIM_RC_OK;
 
}	/* or1ksim_run() */
 
 
/*---------------------------------------------------------------------------*/
/*!Reset the run-time simulation end point
 
  Reset the time for which the simulation should run to the specified duration
  from NOW (i.e. NOT from when the run started).
 
  @param[in] duration  Time to run for in seconds                            */
/*---------------------------------------------------------------------------*/
void
or1ksim_reset_duration (double duration)
{
  runtime.sim.end_cycles =
    runtime.sim.cycles +
    (long long int) (duration * 1.0e12 / (double) config.sim.clkcycle_ps);
 
}	/* or1ksim_reset_duration() */
 
 
/*---------------------------------------------------------------------------*/
/*!Return time executed so far
 
   Internal utility to return the time executed so far. Note that this is a
   re-entrant routine.
 
   @return  Time executed so far in seconds                                  */
/*---------------------------------------------------------------------------*/
static double
internal_or1ksim_time ()
{
  return (double) runtime.sim.cycles * (double) config.sim.clkcycle_ps /
    1.0e12;
 
}	// or1ksim_cycle_count()
 
 
/*---------------------------------------------------------------------------*/
/*!Mark a time point in the simulation
 
   Sets the internal parameter recording this point in the simulation        */
/*---------------------------------------------------------------------------*/
void
or1ksim_set_time_point ()
{
  runtime.sim.time_point = internal_or1ksim_time ();
 
}	/* or1ksim_set_time_point() */
 
 
/*---------------------------------------------------------------------------*/
/*!Return the time since the time point was set
 
  Get the value from the internal parameter                                  */
/*---------------------------------------------------------------------------*/
double
or1ksim_get_time_period ()
{
  return internal_or1ksim_time () - runtime.sim.time_point;
 
}	/* or1ksim_get_time_period() */
 
 
/*---------------------------------------------------------------------------*/
/*!Return the endianism of the model
 
   Note that this is a re-entrant routine.
 
   @return 1 if the model is little endian, 0 otherwise.                     */
/*---------------------------------------------------------------------------*/
int
or1ksim_is_le ()
{
#ifdef OR32_BIG_ENDIAN
  return 0;
#else
  return 1;
#endif
 
}	/* or1ksim_is_le() */
 
 
/*---------------------------------------------------------------------------*/
/*!Return the clock rate
 
   Value is part of the configuration
 
   @return  Clock rate in Hz.                                                */
/*---------------------------------------------------------------------------*/
unsigned long int
or1ksim_clock_rate ()
{
  return (unsigned long int) (1000000000000ULL /
			      (unsigned long long int) (config.sim.
							clkcycle_ps));
}	/* or1ksim_clock_rate() */
 
 
/*---------------------------------------------------------------------------*/
/*!Trigger an edge triggered interrupt
 
   This function is appropriate for edge triggered interrupts, which are taken
   and then immediately cleared.
 
   @note There is no check that the specified interrupt number is reasonable
   (i.e. <= 31).
 
   @param[in] i  The interrupt number                                        */
/*---------------------------------------------------------------------------*/
void
or1ksim_interrupt (int i)
{
  if (!config.pic.edge_trigger)
    {
      fprintf (stderr, "Warning: or1ksim_interrupt should not be used for "
	       "edge triggered interrupts. Ignored\n");
    }
  else
    {
      runtime.sim.ext_int_set |= 1 << i;	// Better not be > 31!
      runtime.sim.ext_int_clr |= 1 << i;	// Better not be > 31!
    }
}	/* or1ksim_interrupt() */
 
 
/*---------------------------------------------------------------------------*/
/*!Set a level triggered interrupt
 
   This function is appropriate for level triggered interrupts, which must be
   explicitly cleared in a separate call.
 
   @note There is no check that the specified interrupt number is reasonable
   (i.e. <= 31).
 
   @param[in] i  The interrupt number to set                                 */
/*---------------------------------------------------------------------------*/
void
or1ksim_interrupt_set (int i)
{
  if (config.pic.edge_trigger)
    {
      fprintf (stderr, "Warning: or1ksim_interrupt_set should not be used for "
	       "level triggered interrupts. Ignored\n");
    }
  else
    {
      runtime.sim.ext_int_set |= 1 << i;	// Better not be > 31!
    }
}	/* or1ksim_interrupt() */
 
 
/*---------------------------------------------------------------------------*/
/*!Clear a level triggered interrupt
 
   This function is appropriate for level triggered interrupts, which must be
   explicitly set first in a separate call.
 
   @note There is no check that the specified interrupt number is reasonable
   (i.e. <= 31).
 
   @param[in] i  The interrupt number to clear                               */
/*---------------------------------------------------------------------------*/
void
or1ksim_interrupt_clear (int i)
{
  if (config.pic.edge_trigger)
    {
      fprintf (stderr, "Warning: or1ksim_interrupt_clear should not be used "
	       "for level triggered interrupts. Ignored\n");
    }
  else
    {
      runtime.sim.ext_int_clr |= 1 << i;	// Better not be > 31!
    }
}	/* or1ksim_interrupt() */
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

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