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

Subversion Repositories or1k

[/] [or1k/] [branches/] [stable_0_2_x/] [or1ksim/] [toplevel.c] - Rev 1446

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

/* toplevel.c -- Top level simulator source file
   Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
 
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
 
/* Simulator commands. Help and version output. SIGINT processing.
Stdout redirection is specific to linux (I need to fix this). */
 
 
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <stdarg.h>
#include <fcntl.h>
#include <limits.h>
#include <time.h>
 
#include "config.h"
 
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif
 
#include "port.h"
#include "arch.h"
#include "parse.h"
#include "abstract.h"
#include "labels.h"
#include "sim-config.h"
#include "opcode/or32.h"
#include "spr_defs.h"
#include "execute.h"
#include "sprs.h"
#include "vapi.h"
#include "gdbcomm.h"
#include "debug_unit.h"
#include "coff.h"
#include "sched.h"
#include "profiler.h"
#include "mprofiler.h"
#include "pm.h"
#include "pic.h"
#include "stats.h"
#include "immu.h"
#include "dmmu.h"
#include "dcache_model.h"
#include "icache_model.h"
#include "branch_predict.h"
#include "dumpverilog.h"
#include "trace.h"
#include "cuc.h"
 
/* CVS revision number. */
const char rcsrev[] = "$Revision: 1.122 $";
 
inline void debug(int level, const char *format, ...)
{
  char *p;
  va_list ap;
 
  if (config.sim.debug >= level) {
    if ((p = malloc(1000)) == NULL)
      return;
    va_start(ap, format);
    (void) vsnprintf(p, 1000, format, ap);
    va_end(ap);
    PRINTF("%s", p);
    fflush(stdout);
    free(p);
  } else {
#if DEBUG
  if ((p = malloc(1000)) == NULL)
    return;
  va_start(ap, format);
  (void) vsnprintf(p, 1000, format, ap);
  va_end(ap);
  PRINTF("%s\n", p);
  fflush(stdout);
  free(p);
#endif
  }
}
 
void ctrl_c(signum)
     int signum;
{
  runtime.sim.cont_run = runtime.cpu.stalled ? 0 : 1;
  runtime.sim.iprompt = 1;
  set_stall_state (0);
  signal(SIGINT, ctrl_c);
}
 
void version()
{
  PRINTF ("\n");
  PRINTF ("OpenRISC 1000 (OR32) Architectural Simulator, %s\n", rcsrev);
  PRINTF ("Copyright (C) 1999 Damjan Lampret, lampret@opencores.org\n");
  PRINTF ("Copyright (C) 2000 Damjan Lampret, lampret@opencores.org\n");
  PRINTF ("                   Jimmy Chen-Min Chen, jimmy@ee.nctu.edu.tw\n");
  PRINTF ("                   Johan Rydberg, johan.rydberg@insight.se\n");
  PRINTF ("                   Marko Mlinar, markom@opencores.org\n");
  PRINTF ("Copyright (C) 2001 Simon Srot, simons@opencores.org\n");
  PRINTF ("                   Marko Mlinar, markom@opencores.org\n");
  PRINTF ("Copyright (C) 2002 Marko Mlinar, markom@opencores.org\n");
  PRINTF ("                   Simon Srot, simons@opencores.org\n");
  PRINTF ("Visit http://www.opencores.org for more information about ");
  PRINTF ("OpenRISC 1000 and\nother open source cores.\n\n");
  PRINTF ("This software comes with ABSOLUTELY NO WARRANTY; for ");
  PRINTF ("details see COPYING.\nThis is free software, and you ");
  PRINTF ("are welcome to redistribute it under certain\nconditions; ");
  PRINTF ("for details see COPYING.\n");
}
 
struct sim_reset_hook {
  void *dat;
  void (*reset_hook)(void *);
  struct sim_reset_hook *next;
};
 
struct sim_reset_hook *sim_reset_hooks = NULL;
 
/* Registers a new reset hook, called when sim_reset below is called */
void reg_sim_reset(void (*reset_hook)(void *), void *dat)
{
  struct sim_reset_hook *new = malloc(sizeof(struct sim_reset_hook));
 
  if(!new) {
    fprintf(stderr, "reg_sim_reset: Out-of-memory\n");
    exit(1);
  }
 
  new->dat = dat;
  new->reset_hook = reset_hook;
  new->next = sim_reset_hooks;
  sim_reset_hooks = new;
}
 
/* Resets all subunits */
void sim_reset (void)
{
  struct sim_reset_hook *cur_reset = sim_reset_hooks;
 
  /* We absolutely MUST reset the scheduler first */
  sched_reset();
 
  while(cur_reset) {
    cur_reset->reset_hook(cur_reset->dat);
    cur_reset = cur_reset->next;
  }
 
  tick_reset();
  pm_reset();
  pic_reset();
  du_reset ();
  cpu_reset();
}
 
/* Initalizes all devices and sim */
void sim_init ()
{
  init_memory_table ();
  init_labels();
  init_breakpoints();
  initstats();
  build_automata();
 
  sched_init();
 
  if (config.sim.profile) {
    runtime.sim.fprof = fopen(config.sim.prof_fn, "wt+");
    if(!runtime.sim.fprof) {
      fprintf(stderr, "ERROR: Problems opening profile file.\n");
      exit (1);
    } else
      fprintf(runtime.sim.fprof, "+00000000 FFFFFFFF FFFFFFFF [outside_functions]\n");
  }
 
  if (config.sim.mprofile) {
    runtime.sim.fmprof = fopen(config.sim.mprof_fn, "wb+");
    if(!runtime.sim.fmprof) {
      fprintf(stderr, "ERROR: Problems opening memory profile file.\n");
      exit (1);
    }
  }
 
  if (config.sim.exe_log) {
    runtime.sim.fexe_log = fopen(config.sim.exe_log_fn, "wt+");
    if(!runtime.sim.fexe_log) {
      PRINTF("ERROR: Problems opening exe_log file.\n");
      exit (1);
    }
  }
 
  if (config.sim.spr_log) {
    PRINTF("OPENING SPRLOG\n");
    runtime.sim.fspr_log = fopen(config.sim.spr_log_fn, "wt+");
    if (!runtime.sim.fspr_log) {
      PRINTF("ERROR: Problems opening spr_log file.\n");
      exit(1);
    }
  }
 
  /* Initialize memory */
  {
    extern struct dev_memarea *dev_list;
    struct dev_memarea *area;
    int i;
    if (config.memory.type == MT_RANDOM) {
      unsigned int val = 0;
 
      if (config.memory.random_seed == -1) {
        runtime.memory.random_seed = time(NULL);
        /* Print out the seed just in case we ever need to debug */
        PRINTF("Seeding random generator with value %d\n", config.memory.random_seed);
      } else
        runtime.memory.random_seed = config.memory.random_seed;
      srandom(runtime.memory.random_seed);
 
      for (area = dev_list; area; area = area->next)
        for(i = 0; i < area->size; i++) {
          val = random();
          setsim_mem8(i + area->addr_compare, val & 0xFF);
        }
    } else if(config.memory.type == MT_PATTERN) {
      for (area = dev_list; area; area = area->next)
        for(i = 0; i < area->size; i++)          
          setsim_mem8(i + area->addr_compare, config.memory.pattern);
    } else if (config.memory.type != MT_UNKNOWN) {
      fprintf(stderr, "Invalid memory configuration type.\n");
      exit(1);
    }
  }
 
  if(runtime.sim.filename) {
    unsigned long endaddr = 0xFFFFFFFF;
    endaddr = loadcode(runtime.sim.filename, 0, 0); /* MM170901 always load at address zero.  */
    if (endaddr == -1) {
      fprintf(stderr, "Problems loading boot code.\n");
      exit(1);
    }
  }
 
  /* Disable gdb debugging, if debug module is not available.  */
  if (config.debug.gdb_enabled && !config.debug.enabled) {
    config.debug.gdb_enabled = 0;
    if (config.sim.verbose)
      fprintf (stderr, "WARNING: Debug module not enabled, cannot start gdb.\n");
  }
 
  if (config.debug.gdb_enabled)
    gdbcomm_init ();
 
  /* Enable dependency stats, if we want to do history analisis */
  if (config.sim.history && !config.cpu.dependstats) {
    config.cpu.dependstats = 1;
    if (config.sim.verbose)
      fprintf (stderr, "WARNING: dependstats stats must be enabled to do history analisis.\n");
  }
 
  /* Debug forces verbose */
  if (config.sim.debug && !config.sim.verbose) {
    config.sim.verbose = 1;
    fprintf (stderr, "WARNING: verbose turned on.\n");
  }
 
  /* Start VAPI before device initialization.  */  
  if (config.vapi.enabled) {
    runtime.vapi.enabled = 1;
    vapi_init ();
    if (config.sim.verbose)
      PRINTF ("VAPI started, waiting for clients.\n");
  }
 
  sim_reset ();
 
  lock_memory_table ();
 
  /* Wait till all test are connected.  */
  if (runtime.vapi.enabled) {    
    int numu = vapi_num_unconnected (0);
    if (numu) {
      PRINTF ("\nWaiting for VAPI tests with ids:\n");
      vapi_num_unconnected (1);     
      PRINTF ("\n");
      while ((numu = vapi_num_unconnected (0))) {
        vapi_check ();
        PRINTF ("\rStill waiting for %i VAPI test(s) to connect.       ", numu);
        usleep (100);
      }
      PRINTF ("\n");
    }
    PRINTF ("All devices connected                         \n");
  }
  /* simulator is initialized */
  runtime.sim.init = 0;
}
 
/* Cleanup */
void sim_done (void)
{
  if (config.sim.profile) {
    fprintf(runtime.sim.fprof,"-%08llX FFFFFFFF\n", runtime.sim.cycles);
    fclose(runtime.sim.fprof);
  }
 
  if (config.sim.mprofile) fclose(runtime.sim.fmprof);
  if (config.sim.exe_log)   fclose(runtime.sim.fexe_log);
  if (runtime.vapi.enabled)  vapi_done ();
  done_memory_table ();
  exit(0);
}
 
/* Executes jobs in time queue */ 
static inline void do_scheduler (void)
{
  struct sched_entry *tmp;
 
  /* Execute all jobs till now */
  do {  
    tmp = scheduler.job_queue;
    scheduler.job_queue = tmp->next;
    tmp->next = scheduler.free_job_queue;
    scheduler.free_job_queue = tmp;
 
    tmp->func (tmp->param);
  } while (scheduler.job_queue->time <= 0);
}
 
/* Main function */
int main(argc, argv)
     int argc;
     char *argv[];
{
  srand(getpid());
  init_defconfig();
  reg_config_secs();
  if (parse_args(argc, argv)) {
    PRINTF("Usage: %s [options] <filename>\n", argv[0]);
    PRINTF("Options:\n");
    PRINTF(" -v                   version and copyright note\n");
    PRINTF(" -i                   enable interactive command prompt\n");
    PRINTF(" --nosrv              do not launch JTAG proxy server\n"); /* (CZ) */
    PRINTF(" --srv <n>            launch JTAG proxy server on port <n>; [random]\n"); /* (CZ) */
    PRINTF(" -f or --file         load script file [sim.cfg]\n");
    PRINTF(" --enable-profile     enable profiling.\n"); 
    PRINTF(" --enable-mprofile    enable memory profiling.\n"); 
    PRINTF(" --output-cfg         prints C structure of current\n");
    PRINTF("                      configuration to standard output\n"); 
    PRINTF("\nor   : %s ", argv[0]);
    mp_help ();
    PRINTF("\nor   : %s ", argv[0]);
    prof_help ();
    exit(-1);
  }
 
  /* Read configuration file.  */
  if (!runtime.sim.script_file_specified)
    read_script_file ("sim.cfg");
 
  /* Overide parameters with command line ones */
  if (runtime.simcmd.profile) config.sim.profile = 1;
  if (runtime.simcmd.mprofile) config.sim.mprofile = 1;
 
  if (!runtime.sim.script_file_specified && config.sim.verbose)
    fprintf (stderr, "WARNING: No config file read, assuming default configuration.\n");
  if (runtime.sim.output_cfg) {
    output_cfg (stdout);
    exit (0);
  }
  print_config();
  sim_init ();
  signal(SIGINT, ctrl_c);
 
  runtime.sim.hush = 1;
  runtime.sim.cont_run = -1;
 
  while(1) {
    if (runtime.sim.iprompt)
        handle_sim_command();
 
    { /* Needed by execution */
      extern int do_stats;
      do_stats = config.cpu.dependstats || config.cpu.superscalar || config.cpu.dependstats
              || config.sim.history || config.sim.exe_log;
    }
 
    /* MM: 'run -1' means endless execution.  */
    while(runtime.sim.cont_run) {
      long long time_start = runtime.sim.cycles;
      if (config.debug.enabled) {
        du_clock(); // reset watchpoints
        if (runtime.cpu.stalled) {
          if(config.debug.gdb_enabled) {
            BlockJTAG();
            HandleServerSocket(false);
          } else {
            fprintf (stderr, "WARNING: CPU stalled and gdb connection not enabled.");
            runtime.sim.cont_run = 0;
          }
          continue;
        }
      }
 
      /* 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 (!config.pm.enabled || !testsprbits(SPR_PMR, SPR_PMR_DME | SPR_PMR_SME)) {
        if (runtime.sim.cont_run > 0) runtime.sim.cont_run--;
        if (cpu_clock ()) break;
      }
 
      if (config.vapi.enabled && runtime.vapi.enabled) vapi_check();
      if (config.debug.gdb_enabled) HandleServerSocket(false); /* block & check_stdin = false */
      if(config.debug.enabled)
        if (testsprbits(SPR_DMR1, SPR_DMR1_ST)) set_stall_state (1);
 
      runtime.sim.cycles += runtime.sim.mem_cycles;
      scheduler.job_queue->time -= runtime.sim.cycles - time_start;
      if (scheduler.job_queue->time <= 0) do_scheduler ();
      if (!runtime.sim.hush) dumpreg();
    }
    runtime.sim.hush = 0;
    fflush(stdout);
    runtime.sim.fout = stdout;
 
    if (!runtime.sim.iprompt)  /* non-interactive quit */
      sim_done();
  }
  sim_done();
}
 

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.