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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [or1ksim/] [sim-config.c] - Diff between revs 220 and 224

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

Rev 220 Rev 224
/* sim-config.c -- Simulator configuration
/* sim-config.c -- Simulator configuration
 
 
   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. */
 
 
/* Simulator configuration. Eventually this one will be a lot bigger. Updated
/* Simulator configuration. Eventually this one will be a lot bigger. Updated
   to use argtable2 for argument parsing. */
   to use argtable2 for argument parsing. */
 
 
 
 
/* 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 "sim-config.h"
#include "sim-config.h"
#include "vapi.h"
#include "vapi.h"
#include "cuc.h"
#include "cuc.h"
#include "cpu-config.h"
#include "cpu-config.h"
#include "memory.h"
#include "memory.h"
#include "dmmu.h"
#include "dmmu.h"
#include "immu.h"
#include "immu.h"
#include "dcache-model.h"
#include "dcache-model.h"
#include "icache-model.h"
#include "icache-model.h"
#include "pic.h"
#include "pic.h"
#include "pm.h"
#include "pm.h"
#include "branch-predict.h"
#include "branch-predict.h"
#include "debug-unit.h"
#include "debug-unit.h"
#include "mc.h"
#include "mc.h"
#include "16450.h"
#include "16450.h"
#include "dma.h"
#include "dma.h"
#include "eth.h"
#include "eth.h"
#include "gpio.h"
#include "gpio.h"
#include "vga.h"
#include "vga.h"
#include "fb.h"
#include "fb.h"
#include "ps2kbd.h"
#include "ps2kbd.h"
#include "atahost.h"
#include "atahost.h"
#include "generic.h"
#include "generic.h"
#include "execute.h"
#include "execute.h"
#include "spr-defs.h"
#include "spr-defs.h"
#include "debug.h"
#include "debug.h"
#include "jtag.h"
#include "jtag.h"
#include "misc.h"
#include "misc.h"
#include "argtable2.h"
#include "argtable2.h"
 
 
 
 
 
/*! A structure used to represent possible parameters in a section. */
 
struct config_param
 
{
 
  char                 *name;                           /* param name */
 
  enum param_t          type;                           /* param type */
 
  void                (*func) (union param_val  val,    /* Setter function */
 
                               void            *dat);
 
  struct config_param  *next;                           /* Next param in list */
 
 
 
};      /* struct config_param */
 
 
 
 
 
/*! Config file line count */
 
static int  line_number;
 
 
 
/*! The global configuration data structure */
struct config config;
struct config config;
 
 
 
/*! The global runtime status data structure */
struct runtime runtime;
struct runtime runtime;
 
 
struct config_section *cur_section;
/*! Master list of sections it is possible to configure. */
 
static struct config_section *section_master_list = NULL;
 
 
struct config_section *sections = NULL;
 
 
 
/* Forward declarations */
/* -------------------------------------------------------------------------- */
static void read_script_file (const char *filename);
/*!Register a parameter for a section
 
 
 
   Add a new parameter to the list of parameters that may be set for a given
 
   section.
 
 
 
   @param[in] sec       The section containing the parameter.
 
   @param[in] param     Name of the parameter
 
   @param[in] type      Type of the parameter
 
   @param[in] param_cb  Call back function to set this parameter.             */
 
/* -------------------------------------------------------------------------- */
 
void
 
reg_config_param (struct config_section  *sec,
 
                  const char             *param,
 
                  enum param_t            type,
 
                  void                  (*param_cb) (union param_val,
 
                                                     void *))
 
{
 
  struct config_param *new = malloc (sizeof (struct config_param));
 
 
/*---------------------------------------------------------------------------*/
  if (!new)
 
    {
 
      fprintf (stderr, "ERROR: Out-of-memory allocating parameter: exiting,\n");
 
      exit (1);
 
    }
 
 
 
  if (!(new->name = strdup (param)))
 
    {
 
      fprintf (stderr, "ERROR: Out-of-memory allocating parameter name: "
 
               "exiting,\n");
 
      exit (1);
 
    }
 
 
 
  /* Set up the parameter */
 
  new->func = param_cb;
 
  new->type = type;
 
 
 
  /* Insert on head of list */
 
  new->next = sec->params;
 
  sec->params = new;
 
 
 
}       /* reg_config_param () */
 
 
 
 
 
/* -------------------------------------------------------------------------- */
 
/*!Register a new section.
 
 
 
   Add a new section to the list of sections that may be found in a config
 
   file.
 
 
 
   @param[in] section    The name of the new section.
 
   @param[in] sec_start  Function to call at start of section configuration
 
                         (or NULL if none)
 
   @param[in] sec_end    Function to call at end of section configuration
 
                         (or NULL if none). Returns pointer to an arbitrary
 
                         data structure.
 
 
 
   @return  A pointer to the section data structure for the new section.      */
 
/* -------------------------------------------------------------------------- */
 
struct config_section *
 
reg_config_sec (const char   *section,
 
                void       *(*sec_start) (void),
 
                void        (*sec_end) (void *))
 
{
 
  struct config_section *new = malloc (sizeof (struct config_section));
 
 
 
  if (!new)
 
    {
 
      fprintf (stderr, "ERROR: Out-of-memory allocating section: exiting,\n");
 
      exit (1);
 
    }
 
 
 
  if (!(new->name = strdup (section)))
 
    {
 
      fprintf (stderr, "ERROR: Out-of-memory allocating section name: "
 
               "exiting,\n");
 
      exit (1);
 
    }
 
 
 
  /* Set up the section */
 
  new->next      = section_master_list;
 
  new->sec_start = sec_start;
 
  new->sec_end   = sec_end;
 
  new->params    = NULL;
 
 
 
  /* Insert the section */
 
  section_master_list = new;
 
 
 
  return new;
 
 
 
}       /* reg_config_sec () */
 
 
 
 
 
/* -------------------------------------------------------------------------- */
 
/*!Look up a section
 
 
 
   Given a section name, return the data structure describing that section.
 
 
 
   @param[in] name  The section to look for.
 
 
 
   @return  A pointer to the section config data structure, or NULL if the
 
            section is not found                                              */
 
/* -------------------------------------------------------------------------- */
 
static struct config_section *
 
lookup_section (char *name)
 
{
 
  struct config_section *cur = NULL;
 
 
 
  for (cur = section_master_list; NULL != cur; cur = cur->next)
 
    {
 
      if (strcmp (cur->name, name) == 0)
 
        {
 
          break;
 
        }
 
    }
 
 
 
  return  cur;
 
 
 
}       /* lookup_section () */
 
 
 
 
 
/* -------------------------------------------------------------------------- */
 
/*!Look up a parameter for a section
 
 
 
   Given a parameter name and a section data structure, return the data
 
   structure describing that parameter
 
 
 
   @param[in] name  The parameter to look for.
 
   @param[in] sec   The section containing the parameter.
 
 
 
   @return  A pointer to the parameter config data structure, or NULL if the
 
            parameter is not found                                            */
 
/* -------------------------------------------------------------------------- */
 
static struct config_param *
 
lookup_param (char                  *name,
 
              struct config_section *sec)
 
{
 
  struct config_param *param = NULL;
 
 
 
  for (param = sec->params; NULL != param; param = param->next)
 
    {
 
      if (strcmp (param->name, name) == 0)
 
        {
 
          break;
 
        }
 
    }
 
 
 
  return  param;
 
 
 
}       /* lookup_param () */
 
 
 
 
 
/* -------------------------------------------------------------------------- */
/*!Set default configuration parameters for fixed components
/*!Set default configuration parameters for fixed components
 
 
   These values are held in the global config variable. Parameter orders
   These values are held in the global config variable. Parameter orders
   match the order in the corresponding section registration function and
   match the order in the corresponding section registration function and
   documentation.
   documentation.
 
 
   Also set some starting values for runtime elements.                       */
   Also set some starting values for runtime elements.                       */
/*---------------------------------------------------------------------------*/
/* -------------------------------------------------------------------------- */
void
void
init_defconfig ()
init_defconfig ()
{
{
  int  set_bits;                /* Temporaries for computing bit fields */
  int  set_bits;                /* Temporaries for computing bit fields */
  int  way_bits;
  int  way_bits;
 
 
  memset (&config, 0, sizeof (config));
  memset (&config, 0, sizeof (config));
 
 
  /* External linkage disabled here. */
  /* External linkage disabled here. */
  config.ext.class_ptr = NULL;
  config.ext.class_ptr = NULL;
  config.ext.read_up   = NULL;
  config.ext.read_up   = NULL;
  config.ext.write_up  = NULL;
  config.ext.write_up  = NULL;
 
 
  /* Sim */
  /* Sim */
  config.sim.is_library          = 0;    /* Not library operation */
  config.sim.is_library          = 0;    /* Not library operation */
  config.sim.verbose             = 0;
  config.sim.verbose             = 0;
  config.sim.debug               = 0;
  config.sim.debug               = 0;
  config.sim.profile             = 0;
  config.sim.profile             = 0;
  config.sim.prof_fn             = strdup ("sim.profile");
  config.sim.prof_fn             = strdup ("sim.profile");
  config.sim.mprofile            = 0;
  config.sim.mprofile            = 0;
  config.sim.mprof_fn            = strdup ("sim.mprofile");
  config.sim.mprof_fn            = strdup ("sim.mprofile");
  config.sim.history             = 0;
  config.sim.history             = 0;
  config.sim.exe_log             = 0;
  config.sim.exe_log             = 0;
  config.sim.exe_log_type        = EXE_LOG_HARDWARE;
  config.sim.exe_log_type        = EXE_LOG_HARDWARE;
  config.sim.exe_log_start       = 0;
  config.sim.exe_log_start       = 0;
  config.sim.exe_log_end         = 0;
  config.sim.exe_log_end         = 0;
  config.sim.exe_log_marker      = 0;
  config.sim.exe_log_marker      = 0;
  config.sim.exe_log_fn          = strdup ("executed.log");
  config.sim.exe_log_fn          = strdup ("executed.log");
  config.sim.exe_bin_insn_log    = 0;
  config.sim.exe_bin_insn_log    = 0;
  config.sim.exe_bin_insn_log_fn = strdup ("exe-insn.bin");
  config.sim.exe_bin_insn_log_fn = strdup ("exe-insn.bin");
  config.sim.clkcycle_ps         = 4000;        /* 4000 for 4ns (250MHz) */
  config.sim.clkcycle_ps         = 4000;        /* 4000 for 4ns (250MHz) */
 
 
  /* Debug */
  /* Debug */
  config.debug.jtagcycle_ps = 40000;    /* 40000 for 40ns (25MHz) */
  config.debug.jtagcycle_ps = 40000;    /* 40000 for 40ns (25MHz) */
 
 
  /* VAPI */
  /* VAPI */
  config.vapi.enabled        = 0;
  config.vapi.enabled        = 0;
  config.vapi.server_port    = 50000;
  config.vapi.server_port    = 50000;
  config.vapi.log_enabled    = 0;
  config.vapi.log_enabled    = 0;
  config.vapi.hide_device_id = 0;
  config.vapi.hide_device_id = 0;
  config.vapi.vapi_fn        = strdup ("vapi.log");
  config.vapi.vapi_fn        = strdup ("vapi.log");
 
 
  /* CUC */
  /* CUC */
  config.cuc.calling_convention = 1;
  config.cuc.calling_convention = 1;
  config.cuc.enable_bursts      = 1;
  config.cuc.enable_bursts      = 1;
  config.cuc.no_multicycle      = 1;
  config.cuc.no_multicycle      = 1;
  config.cuc.memory_order       = MO_STRONG;
  config.cuc.memory_order       = MO_STRONG;
  config.cuc.timings_fn         = strdup ("virtex.tim");
  config.cuc.timings_fn         = strdup ("virtex.tim");
 
 
  /* CPU */
  /* CPU */
  cpu_state.sprs[SPR_VR]      = 0;
  cpu_state.sprs[SPR_VR]      = 0;
  cpu_state.sprs[SPR_UPR]     = SPR_UPR_UP | SPR_UPR_TTP;
  cpu_state.sprs[SPR_UPR]     = SPR_UPR_UP | SPR_UPR_TTP;
  cpu_state.sprs[SPR_SR]      = SPR_SR_FO  | SPR_SR_SM;
  cpu_state.sprs[SPR_SR]      = SPR_SR_FO  | SPR_SR_SM;
  cpu_state.sprs[SPR_CPUCFGR] = SPR_CPUCFGR_OB32S;
  cpu_state.sprs[SPR_CPUCFGR] = SPR_CPUCFGR_OB32S;
  config.cpu.superscalar      = 0;
  config.cpu.superscalar      = 0;
  config.cpu.hazards          = 0;
  config.cpu.hazards          = 0;
  config.cpu.dependstats      = 0;
  config.cpu.dependstats      = 0;
  config.cpu.sbuf_len         = 0;
  config.cpu.sbuf_len         = 0;
  config.cpu.hardfloat        = 0;
  config.cpu.hardfloat        = 0;
 
 
  /* Data cache (IC is set dynamically). Also set relevant SPR bits */
  /* Data cache (IC is set dynamically). Also set relevant SPR bits */
  config.dc.enabled         = 0;
  config.dc.enabled         = 0;
  config.dc.nsets           = 1;
  config.dc.nsets           = 1;
  config.dc.nways           = 1;
  config.dc.nways           = 1;
  config.dc.blocksize       = 1;
  config.dc.blocksize       = 1;
  config.dc.ustates         = 2;
  config.dc.ustates         = 2;
  config.dc.load_hitdelay   = 2;
  config.dc.load_hitdelay   = 2;
  config.dc.load_missdelay  = 2;
  config.dc.load_missdelay  = 2;
  config.dc.store_hitdelay  = 0;
  config.dc.store_hitdelay  = 0;
  config.dc.store_missdelay = 0;
  config.dc.store_missdelay = 0;
 
 
  if (config.dc.enabled)
  if (config.dc.enabled)
    {
    {
      cpu_state.sprs[SPR_UPR] |= SPR_UPR_DCP;
      cpu_state.sprs[SPR_UPR] |= SPR_UPR_DCP;
    }
    }
  else
  else
    {
    {
      cpu_state.sprs[SPR_UPR] &= ~SPR_UPR_DCP;
      cpu_state.sprs[SPR_UPR] &= ~SPR_UPR_DCP;
    }
    }
 
 
  set_bits = log2_int (config.dc.nsets);
  set_bits = log2_int (config.dc.nsets);
  cpu_state.sprs[SPR_DCCFGR] &= ~SPR_DCCFGR_NCS;
  cpu_state.sprs[SPR_DCCFGR] &= ~SPR_DCCFGR_NCS;
  cpu_state.sprs[SPR_DCCFGR] |= set_bits << SPR_DCCFGR_NCS_OFF;
  cpu_state.sprs[SPR_DCCFGR] |= set_bits << SPR_DCCFGR_NCS_OFF;
 
 
  way_bits = log2_int (config.dc.nways);
  way_bits = log2_int (config.dc.nways);
  cpu_state.sprs[SPR_DCCFGR] &= ~SPR_DCCFGR_NCW;
  cpu_state.sprs[SPR_DCCFGR] &= ~SPR_DCCFGR_NCW;
  cpu_state.sprs[SPR_DCCFGR] |= way_bits << SPR_DCCFGR_NCW_OFF;
  cpu_state.sprs[SPR_DCCFGR] |= way_bits << SPR_DCCFGR_NCW_OFF;
 
 
  if (MIN_DC_BLOCK_SIZE == config.dc.blocksize)
  if (MIN_DC_BLOCK_SIZE == config.dc.blocksize)
    {
    {
      cpu_state.sprs[SPR_DCCFGR] &= ~SPR_DCCFGR_CBS;
      cpu_state.sprs[SPR_DCCFGR] &= ~SPR_DCCFGR_CBS;
    }
    }
  else
  else
    {
    {
      cpu_state.sprs[SPR_DCCFGR] |= SPR_DCCFGR_CBS;
      cpu_state.sprs[SPR_DCCFGR] |= SPR_DCCFGR_CBS;
    }
    }
 
 
  /* Power management */
  /* Power management */
  config.pm.enabled = 0;
  config.pm.enabled = 0;
 
 
  if (config.pm.enabled)
  if (config.pm.enabled)
    {
    {
      cpu_state.sprs[SPR_UPR] |= SPR_UPR_PMP;
      cpu_state.sprs[SPR_UPR] |= SPR_UPR_PMP;
    }
    }
  else
  else
    {
    {
      cpu_state.sprs[SPR_UPR] &= ~SPR_UPR_PMP;
      cpu_state.sprs[SPR_UPR] &= ~SPR_UPR_PMP;
    }
    }
 
 
  /* Programmable Interrupt Controller */
  /* Programmable Interrupt Controller */
  config.pic.enabled      = 0;
  config.pic.enabled      = 0;
  config.pic.edge_trigger = 1;
  config.pic.edge_trigger = 1;
 
 
  if (config.pic.enabled)
  if (config.pic.enabled)
    {
    {
      cpu_state.sprs[SPR_UPR] |= SPR_UPR_PICP;
      cpu_state.sprs[SPR_UPR] |= SPR_UPR_PICP;
    }
    }
  else
  else
    {
    {
      cpu_state.sprs[SPR_UPR] &= ~SPR_UPR_PICP;
      cpu_state.sprs[SPR_UPR] &= ~SPR_UPR_PICP;
    }
    }
 
 
  /* Branch Prediction */
  /* Branch Prediction */
  config.bpb.enabled     = 0;
  config.bpb.enabled     = 0;
  config.bpb.btic        = 0;
  config.bpb.btic        = 0;
  config.bpb.sbp_bnf_fwd = 0;
  config.bpb.sbp_bnf_fwd = 0;
  config.bpb.sbp_bf_fwd  = 0;
  config.bpb.sbp_bf_fwd  = 0;
  config.bpb.missdelay   = 0;
  config.bpb.missdelay   = 0;
  config.bpb.hitdelay    = 0;
  config.bpb.hitdelay    = 0;
 
 
  /* Debug */
  /* Debug */
  config.debug.enabled     = 0;
  config.debug.enabled     = 0;
  config.debug.gdb_enabled = 0;
  config.debug.gdb_enabled = 0;
  config.debug.rsp_enabled = 0;
  config.debug.rsp_enabled = 0;
  config.debug.server_port = 51000;
  config.debug.server_port = 51000;
  config.debug.rsp_port    = 51000;
  config.debug.rsp_port    = 51000;
  config.debug.vapi_id     = 0;
  config.debug.vapi_id     = 0;
 
 
  cpu_state.sprs[SPR_DCFGR] = SPR_DCFGR_WPCI |
  cpu_state.sprs[SPR_DCFGR] = SPR_DCFGR_WPCI |
                              MATCHPOINTS_TO_NDP (MAX_MATCHPOINTS);
                              MATCHPOINTS_TO_NDP (MAX_MATCHPOINTS);
 
 
  if (config.debug.enabled)
  if (config.debug.enabled)
    {
    {
      cpu_state.sprs[SPR_UPR] |= SPR_UPR_DUP;
      cpu_state.sprs[SPR_UPR] |= SPR_UPR_DUP;
    }
    }
  else
  else
    {
    {
      cpu_state.sprs[SPR_UPR] &= ~SPR_UPR_DUP;
      cpu_state.sprs[SPR_UPR] &= ~SPR_UPR_DUP;
    }
    }
 
 
  /* Configure runtime */
  /* Configure runtime */
  memset (&runtime, 0, sizeof (runtime));
  memset (&runtime, 0, sizeof (runtime));
 
 
  /* Sim */
  /* Sim */
  runtime.sim.fexe_log              = NULL;
  runtime.sim.fexe_log              = NULL;
  runtime.sim.iprompt               = 0;
  runtime.sim.iprompt               = 0;
  runtime.sim.fprof                 = NULL;
  runtime.sim.fprof                 = NULL;
  runtime.sim.fmprof                = NULL;
  runtime.sim.fmprof                = NULL;
  runtime.sim.fout                  = stdout;
  runtime.sim.fout                  = stdout;
 
 
  /* Debug */
  /* Debug */
  runtime.debug.instr           = JI_UNDEFINED;
  runtime.debug.instr           = JI_UNDEFINED;
  runtime.debug.mod_id          = JM_UNDEFINED;
  runtime.debug.mod_id          = JM_UNDEFINED;
  runtime.debug.write_defined_p = 0;             /* No WRITE_COMMAND yet */
  runtime.debug.write_defined_p = 0;             /* No WRITE_COMMAND yet */
 
 
  /* NPC state. Set to 1 when NPC is changed while the processor is stalled. */
  /* NPC state. Set to 1 when NPC is changed while the processor is stalled. */
  cpu_state.npc_not_valid = 0;
  cpu_state.npc_not_valid = 0;
 
 
  /* VAPI */
  /* VAPI */
  runtime.vapi.vapi_file = NULL;
  runtime.vapi.vapi_file = NULL;
  runtime.vapi.enabled   = 0;
  runtime.vapi.enabled   = 0;
 
 
}       /* init_defconfig() */
}       /* init_defconfig() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/* -------------------------------------------------------------------------- */
/*! Parse the arguments for the standalone simulator
/*!Set a configuration parameter.
 
 
    Updated by Jeremy Bennett to use argtable2.
 
 
 
    @param[in] argc  Number of command args
   We have a string representing the value, and a data structure representing
    @param[in] argv  Vector of the command args
   the particular parameter. Break out the value and call the setter function
 
   to set its value in the section.
 
 
 
   The value text is guaranteed to have no leading or trailing whitespace.
 
 
 
   @param[in] cur_section  Spec of the section currently being configured.
 
   @param[in] param        Spec of the parameter we are setting.
 
   @param[in] val_text     The parameter value text                           */
 
/* -------------------------------------------------------------------------- */
 
static void
 
set_config_param (struct config_section *cur_section,
 
                  struct config_param   *param,
 
                  char                  *val_text)
 
{
 
  union param_val  val;
 
 
    @return  0 on success, 1 on failure                                      */
  /* Break out the different parameter types */
/*---------------------------------------------------------------------------*/
  switch (param->type)
int
 
parse_args (int argc, char *argv[])
 
{
{
  struct arg_lit *vercop;
    case PARAMT_NONE:
  struct arg_lit *help;
      break;
  struct arg_file *cfg_file;
 
  struct arg_lit *nosrv;
 
  struct arg_int *srv;
 
  struct arg_str *dbg;
 
  struct arg_lit *command;
 
  struct arg_lit *quiet;
 
  struct arg_lit *report_mem_errs;
 
  struct arg_lit *strict_npc;
 
  struct arg_lit *profile;
 
  struct arg_lit *mprofile;
 
  struct arg_file *load_file;
 
  struct arg_end *end;
 
 
 
  void *argtab[14];
    case PARAMT_INT:
  int nerrors;
      val.int_val = strtol (val_text, NULL, 0);
 
      break;
 
 
  /* Specify each argument, with fall back values */
    case PARAMT_LONGLONG:
  vercop = arg_lit0 ("v", "version", "version and copyright notice");
      val.longlong_val = strtoll (val_text, NULL, 0);
  help = arg_lit0 ("h", "help", "print this help message");
      break;
  cfg_file = arg_file0 ("f", "file", "<file>",
 
                        "config file (default \"sim.cfg\")");
 
  cfg_file->filename[0] = "sim.cfg";
 
  nosrv = arg_lit0 (NULL, "nosrv", "do not launch JTAG proxy server");
 
  srv = arg_int0 (NULL, "srv", "<n>", "port number (default random)");
 
  srv->ival[0] = rand () % (65536 - 49152) + 49152;
 
  srv->hdr.flag |= ARG_HASOPTVALUE;
 
  dbg = arg_str0 ("d", "debug-config", "<str>", "Debug config string");
 
  command = arg_lit0 ("i", "interactive", "launch interactive prompt");
 
  quiet = arg_lit0 ("q", "quiet", "minimal message output");
 
  report_mem_errs = arg_lit0 (NULL, "report-memory-errors",
 
                              "Report out of memory accesses");
 
  strict_npc = arg_lit0 (NULL, "strict-npc", "setting NPC flushes pipeline");
 
  profile = arg_lit0 (NULL, "enable-profile", "enable profiling");
 
  mprofile = arg_lit0 (NULL, "enable-mprofile", "enable memory profiling");
 
  load_file = arg_file0 (NULL, NULL, "<file>", "OR32 executable");
 
  end = arg_end (20);
 
 
 
  /* Set up the argument table */
    case PARAMT_ADDR:
  argtab[ 0] = vercop;
      val.addr_val = strtoul (val_text, NULL, 0);
  argtab[ 1] = help;
      break;
  argtab[ 2] = cfg_file;
 
  argtab[ 3] = nosrv;
 
  argtab[ 4] = srv;
 
  argtab[ 5] = dbg;
 
  argtab[ 6] = command;
 
  argtab[ 7] = quiet;
 
  argtab[ 8] = report_mem_errs;
 
  argtab[ 9] = strict_npc;
 
  argtab[10] = profile;
 
  argtab[11] = mprofile;
 
  argtab[12] = load_file;
 
  argtab[13] = end;
 
 
 
  /* Parse */
    case PARAMT_WORD:
  nerrors = arg_parse (argc, argv, argtab);
    case PARAMT_STR:
 
      /* Word and string are the same thing by now. */
 
      val.str_val = val_text;
 
      break;
 
    }
 
 
  /* Special case here is if help or version is specified, we ignore any other
  /* Call the setter function */
     errors and just print the help or version information and then give up. */
  param->func (val, cur_section->dat);
  if (vercop->count > 0)
 
    {
 
      PRINTF ("OpenRISC 1000 Architectural Simulator, version %s\n",
 
              PACKAGE_VERSION);
 
 
 
      arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
}       /* set_config_param () */
      return 1;
 
    }
 
 
 
  if (help->count > 0)
 
    {
 
      printf ("Usage:\n  %s ", argv[0]);
 
      arg_print_syntax (stdout, argtab, "\n\n");
 
      arg_print_glossary (stdout, argtab, "  %-25s %s\n");
 
 
 
      arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
/* -------------------------------------------------------------------------- */
      return 1;
/*!Scan the next word, skipping any preceding space.
    }
 
 
 
  /* Deal with any errors */
   A word is anything that is not white space, except where the white space is
  if (0 != nerrors)
   within quotation marks. Return the number of newlines we have to skip.
    {
 
      arg_print_errors (stderr, end, "or1ksim");
 
      printf ("\nUsage:\n  %s ", argv[0]);
 
      arg_print_syntaxv (stderr, argtab, "\n");
 
 
 
      arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
   @param[in] f     The file handle to read from
      return 1;
   @param[in] word  A buffer in which to store the word.
    }
 
 
 
  /* Process config file next, so any other command args will override */
   @return  The text of the next entity or NULL at end of file. Note strings
  if (0 == cfg_file->count)
            have their quotation marks removed.                               */
 
/* -------------------------------------------------------------------------- */
 
static char *
 
next_word (FILE *f,
 
           char  word[])
    {
    {
      fprintf (stderr,
  int  c;
               "Warning: No config file given, default configuration used\n");
  int  i;
    }
 
 
 
  read_script_file (cfg_file->filename[0]);
  /* Skip the whitespace */
 
  do
 
    {
 
      c = fgetc (f);
 
 
 
      line_number += ('\n' == c) ? 1: 0;
 
    }
 
  while ((EOF != c) && isspace (c));
 
 
  /* Remote debug server */
  /* Get the word> Special treatment if it is a string. */
  if (nosrv->count > 0)
  if ('"' == c)
    {
    {
      if (srv->count > 0)
      /* We have a string. Skip the opening quote. */
 
      c = fgetc (f);
 
 
 
      for (i = 0; i < (STR_SIZE - 1); i++)
        {
        {
          fprintf (stderr,
          if ('"' == c)
                   "%s: cannot specify --nosrv with --srv. Ignoring --nosrv\n",
            {
                   argv[0]);
              c = fgetc (f);            /* So ungetc works */
 
              break;                    /* End of the string */
        }
        }
      else
          else if ('\n' == c)
        {
        {
          config.debug.enabled = 0;
              line_number++;
          config.debug.gdb_enabled = 0;
 
        }
        }
 
          else if (EOF == c)
 
            {
 
              fprintf (stderr, "ERROR: EOF in middle of string: exiting.\n");
 
              exit (1);
    }
    }
 
 
  if (srv->count > 0)
          word[i] = c;
 
          c = fgetc (f);
 
        }
 
 
 
      /* Skip the closing quote */
 
      c = fgetc (f);
 
    }
 
  else
    {
    {
      config.debug.enabled = 1;
      /* We have a space delimited word */
      config.debug.gdb_enabled = 1;
      for (i = 0; i < (STR_SIZE - 1); i++)
      config.debug.server_port = srv->ival[0];
        {
 
          if ((EOF == c) || isspace (c))
 
            {
 
              break;                    /* End of the word */
    }
    }
 
 
  /* Runtime debug messages */
          word[i] = c;
  if (dbg->count > 0)
          c = fgetc (f);
 
        }
 
    }
 
 
 
  word[i] = '\0';                       /* Terminate the word */
 
 
 
  if ((STR_SIZE - 1) == i)
    {
    {
      parse_dbchs (dbg->sval[0]);
      word[10]= '\0';
 
      fprintf (stderr,
 
               "ERROR: Symbol beginning %s on line %d too long: exiting.\n",
 
               word, line_number);
 
      exit (1);
    }
    }
 
 
  /* Interactive operation */
  ungetc (c, f);                        /* Ready for next time */
  runtime.sim.iprompt = command->count;
 
 
 
  /* Request for quiet running */
  return  (0 == i) ? NULL : word;
  config.sim.quiet = quiet->count;
 
 
 
  /* Request for quiet running */
}       /* next_word () */
  config.sim.report_mem_errs = report_mem_errs->count;
 
 
 
  /* Request for strict NPC behavior (flush the pipeline on change) */
 
  config.sim.strict_npc = strict_npc->count;
 
 
 
  /* Profiling requests */
/* -------------------------------------------------------------------------- */
  config.sim.profile = profile->count;
/*!Read the next lexeme from the a config file.
  config.sim.mprofile = mprofile->count;
 
 
 
  /* Executable file */
   At this stage we are just breaking things out into space delimited
  if (load_file->count > 0)
   entities, stripping out comments.
 
 
 
   @param[in] f       The file handle to read from
 
   @param[in] lexeme  A buffer in which to store the lexeme.
 
 
 
   @return  The text of the next entity or NULL at end of file.               */
 
/* -------------------------------------------------------------------------- */
 
static char *
 
next_lexeme (FILE *f,
 
             char  lexeme[])
    {
    {
      runtime.sim.filename = strdup (load_file->filename[0]);
  if (NULL == next_word (f, lexeme))
    }
 
  else
 
    {
    {
      runtime.sim.filename = NULL;
      return  NULL;
    }
    }
 
 
  arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
  /* Skip any comments */
  return 0;                      /* Success */
  while (0 ==strncmp (lexeme, "/*", 2))
 
    {
 
      /* Look for the closing '*' and '/'. */
 
      char  c0 = '\0';
 
      char  c1 = '\0';
 
 
}       /* parse_args() */
      while (('*' != c0) || ('/' != c1))
 
        {
 
          c0 = c1;
 
          c1 = fgetc (f);
 
 
 
          line_number += ('\n' == c1) ? 1 : 0;
 
 
/*---------------------------------------------------------------------------*/
          /* We assume if we hit EOF we have a serious problem and die. */
/*!Print the current configuration                                           */
          if (feof (f))
/*---------------------------------------------------------------------------*/
 
void
 
print_config ()
 
{
{
  if (config.sim.verbose)
              fprintf (stderr, "ERROR: Comment reached EOF.\n");
 
              exit (1);
 
            }
 
        }
 
 
 
      /* Get the next lexeme */
 
      if (NULL == next_word (f, lexeme))
    {
    {
      char temp[20];
          return  NULL;
      PRINTF ("Verbose on, ");
        }
      if (config.sim.debug)
    }
        PRINTF ("simdebug on, ");
 
      else
 
        PRINTF ("simdebug off, ");
 
      if (runtime.sim.iprompt)
 
        PRINTF ("interactive prompt on\n");
 
      else
 
        PRINTF ("interactive prompt off\n");
 
 
 
      PRINTF ("Machine initialization...\n");
  return  lexeme;
      generate_time_pretty (temp, config.sim.clkcycle_ps);
 
 
}       /* next_lexeme () */
 
 
 
 
 
/* -------------------------------------------------------------------------- */
 
/*!Read configuration from a script file.
 
 
 
   The syntax of script file is:
 
 
 
     [section x
 
       [param [=] value]+
 
     end]*
 
 
 
   Example:
 
 
 
     section mc
 
       enabled = 1
 
       POC     = 0x47892344
 
     end
 
 
 
   The config file is searched for first in the local directory, then in
 
   ${HOME}/.or1ksim, then (for backwards compatibility) in ${HOME}/.or1ksim.
 
 
 
   If the file is not found, then a rude message is printed. The system will
 
   just use default values.
 
 
 
   @param[in] filename  The configuration file to use.                        */
 
/* -------------------------------------------------------------------------- */
 
static void
 
read_script_file (const char *filename)
 
{
 
  FILE *f;
 
  char *home = getenv ("HOME");
 
  char  ctmp1[STR_SIZE];
 
  char  ctmp2[STR_SIZE];
 
  char *dir;
 
 
 
  /* Attempt to open the config file. If we fail, give up with a rude
 
     message. */
 
  sprintf (ctmp1, "%s/.or1ksim/%s", home, filename);
 
  sprintf (ctmp2, "%s/.or1k/%s", home, filename);
 
 
 
  if (NULL != (f = fopen (filename, "r")))
 
    {
 
      dir = ".";
 
    }
 
  else if (home && (NULL != (f = fopen (ctmp1, "r"))))
 
    {
 
      dir = ctmp1;
 
    }
 
  else if (home && (NULL != (f = fopen (ctmp2, "r"))))
 
    {
 
      dir = ctmp2;
 
    }
 
  else
 
    {
 
      fprintf (stderr, "Warning: Failed to open script file \"%s\". Ignored.\n",
 
               filename);
 
      return;
 
    }
 
 
 
  /* Log the config file we have just opened if required. */
 
  if (config.sim.verbose)
 
    {
 
      PRINTF ("Reading script file from \"%s/%s\"...\n", dir, filename);
 
    }
 
 
 
  /* Process the config file. */
 
  char lexeme[STR_SIZE];                /* Next entity from the input */
 
  int  in_section_p = 0;         /* Are we processing a section */
 
 
 
  struct config_section *cur_section = NULL;    /* Section being processed */
 
 
 
  line_number = 1;
 
 
 
  while (NULL != next_lexeme (f, lexeme))
 
    {
 
      /* Get the next symbol. Four possibilities.
 
 
 
         1. It's "section". Only if we are not currently in a section. Process
 
            the start of a section.
 
 
 
         2. It's "end". Only if we are currently in a section. Process the end
 
            of a section.
 
 
 
         3. Anything else while we are in a section. Assume it is a parameter
 
            for the current section.
 
 
 
         4. Anything else. An error.
 
      */
 
      if (!in_section_p && (0 == strcmp (lexeme, "section")))
 
        {
 
          /* We have the start of a section */
 
          if (NULL == next_lexeme (f, lexeme))
 
            {
 
              fprintf (stderr, "ERROR: %s/%s: Section name required at line "
 
                       "%d. Exiting\n", dir, filename, line_number);
 
              exit (1);
 
            }
 
 
 
          cur_section = lookup_section (lexeme);
 
 
 
          if (NULL != cur_section)
 
            {
 
              /* Valid section, run its startup code, with any data saved. */
 
              cur_section->dat = NULL;
 
 
 
              if (cur_section->sec_start)
 
                {
 
                  cur_section->dat = cur_section->sec_start ();
 
                }
 
 
 
              in_section_p = 1;         /* Now in a section */
 
            }
 
          else
 
            {
 
              /* Skip an unrecognized section with a warning. */
 
              fprintf (stderr, "Warning: %s/%s: Unrecognized section: %s at "
 
                       "line %d: ignoring.\n", dir, filename, lexeme,
 
                       line_number);
 
 
 
              /* just skip section */
 
              while (NULL != next_lexeme (f, lexeme))
 
                {
 
                  if (strcmp (lexeme, "end"))
 
                    {
 
                      break;
 
                    }
 
                }
 
            }
 
        }
 
      else if (in_section_p && strcmp (lexeme, "end") == 0)
 
        {
 
          /* End of section. Run the end of section code */
 
          if (cur_section->sec_end)
 
            {
 
              cur_section->sec_end (cur_section->dat);
 
            }
 
 
 
          in_section_p = 0;              /* Not in a section any more */
 
        }
 
      else if (in_section_p)
 
        {
 
          /* We're in a section, so this must be a parameter. */
 
          struct config_param *param;
 
          char                *param_val;
 
 
 
          param = lookup_param (lexeme, cur_section);
 
 
 
          /* If we didn't recognize, then warn and skip to end of line/file) */
 
          if (NULL == param)
 
            {
 
              fprintf (stderr, "Warning: %s/%s: Unrecognized parameter: %s at "
 
                       "line %d; ignored.\n", dir, filename, lexeme,
 
                       line_number);
 
 
 
              /* Skip to end of line */
 
              while (( '\n' != fgetc (f)) || feof (f))
 
                ;
 
 
 
              line_number++;
 
              continue;                 /* Start looking again */
 
            }
 
 
 
          /* Get the argument if one is expected. */
 
          if (PARAMT_NONE != param->type)
 
            {
 
              param_val = next_lexeme (f, lexeme);
 
 
 
              if (NULL == param_val)
 
                {
 
                  fprintf (stderr, "Warning: %s/%s: No argument to parameter "
 
                           "%s at line %d; ignored.\n", dir, filename,
 
                           param->name, line_number);
 
 
 
                  /* Skip to end of line */
 
                  while (( '\n' != fgetc (f)) || feof (f))
 
                    ;
 
 
 
                  line_number++;
 
                  continue;                     /* Start looking again */
 
                }
 
 
 
              /* We allow an optional '=' */
 
              if (0 == strcmp (lexeme, "="))
 
                {
 
                  param_val = next_lexeme (f, lexeme);
 
 
 
                  if (NULL == param_val)
 
                    {
 
                      fprintf (stderr, "Warning: %s/%s: No argument to "
 
                               "parameter %s at line %d; ignored.\n", dir,
 
                               filename, param->name, line_number);
 
 
 
                      /* Skip to end of line */
 
                      while (( '\n' != fgetc (f)) || feof (f))
 
                        ;
 
 
 
                      line_number++;
 
                      continue;                 /* Start looking again */
 
                    }
 
                }
 
            }
 
          else
 
            {
 
              /* No argument */
 
              param_val = NULL;
 
            }
 
 
 
          /* Apply the parameter */
 
          set_config_param (cur_section, param, param_val);
 
        }
 
      else
 
        {
 
          /* We're not in a section, so we don't know what we have */
 
          fprintf (stderr, "Warning: %s/%s: Unrecognized config file contents "
 
                   " at line %d: ignored.\n", dir, filename, line_number);
 
 
 
          /* Skip to end of line */
 
          while (( '\n' != fgetc (f)) || feof (f))
 
            ;
 
 
 
          line_number++;
 
          continue;                     /* Start looking again */
 
        }
 
    }
 
 
 
  fclose (f);           /* All done */
 
 
 
}       /* read_script_file () */
 
 
 
 
 
/*---------------------------------------------------------------------------*/
 
/*!Allocate a memory block
 
 
 
   We can request a block of memory be allocated from the command line, rather
 
   than in a configuration file. It will be allocated, starting at address
 
   zero.
 
 
 
   The memory size may be presented in any format recognized by strtol,
 
   optionally followed by "G" or "g", "M" or "m" or "K" or "k" for giga, mega
 
   and kilo bytes respectively, and leading to mutliplcation by 2^30, 2^20 and
 
   2^10 respectively.
 
 
 
   This is intended for simple use of the simulator in tool chain
 
   verification, where the detailed memory behavior does not matter.
 
 
 
   @param[in] size  Memory size.                                             */
 
/*---------------------------------------------------------------------------*/
 
static void
 
alloc_memory_block (const char *size)
 
{
 
  /* Sort out the memory size. */
 
  unsigned long int  multiplier;
 
  int                last_ch = strlen (size) - 1;
 
 
 
  switch (size[last_ch])
 
    {
 
    case 'G': case 'g': multiplier = 0x40000000UL; break;
 
    case 'M': case 'm': multiplier =   0x100000UL; break;
 
    case 'K': case 'k': multiplier =      0x400UL; break;
 
    default:            multiplier =        0x1UL; break;
 
    }
 
  unsigned long int  mem_size = strtoul (size, NULL, 0) * multiplier;
 
 
 
  if (0 == mem_size)
 
    {
 
      fprintf (stderr, "Warning: Memory size %s not recognized: ignored.\n",
 
               size);
 
      return;
 
    }
 
 
 
  if (mem_size > 0xffffffff)
 
    {
 
      fprintf (stderr, "Warning: Memory size %s too large: ignored.\n",
 
               size);
 
      return;
 
    }
 
 
 
  /* Turn the memory size back into a decimal string and allocate it */
 
  char str_size[11];
 
  sprintf (str_size, "%lu\n", mem_size);
 
 
 
  struct config_section *sec = lookup_section ("memory");
 
 
 
  sec->dat = sec->sec_start ();
 
 
 
  set_config_param (sec, lookup_param ("name", sec),     "Default RAM");
 
  set_config_param (sec, lookup_param ("type", sec),     "unknown");
 
  set_config_param (sec, lookup_param ("baseaddr", sec), "0");
 
  set_config_param (sec, lookup_param ("size", sec),     str_size);
 
 
 
  sec->sec_end (sec->dat);
 
 
 
}       /* alloc_memory_block () */
 
 
 
 
 
/*---------------------------------------------------------------------------*/
 
/*! Parse the arguments for the standalone simulator
 
 
 
    Updated by Jeremy Bennett to use argtable2.
 
 
 
    @param[in] argc  Number of command args
 
    @param[in] argv  Vector of the command args
 
 
 
    @return  0 on success, 1 on failure                                      */
 
/*---------------------------------------------------------------------------*/
 
int
 
parse_args (int argc, char *argv[])
 
{
 
  struct arg_lit  *vercop;
 
  struct arg_lit  *help;
 
  struct arg_file *cfg_file;
 
  struct arg_lit  *nosrv;
 
  struct arg_int  *srv;
 
  struct arg_str  *mem;
 
  struct arg_str  *dbg;
 
  struct arg_lit  *command;
 
  struct arg_lit  *quiet;
 
  struct arg_lit  *verbose;
 
  struct arg_lit  *report_mem_errs;
 
  struct arg_lit  *strict_npc;
 
  struct arg_lit  *profile;
 
  struct arg_lit  *mprofile;
 
  struct arg_file *load_file;
 
  struct arg_end  *end;
 
 
 
  /* Specify each argument, with fall back values */
 
  vercop = arg_lit0 ("v", "version", "version and copyright notice");
 
  help = arg_lit0 ("h", "help", "print this help message");
 
  cfg_file = arg_file0 ("f", "file", "<file>",
 
                        "config file (default \"sim.cfg\")");
 
  cfg_file->filename[0] = "sim.cfg";
 
  nosrv = arg_lit0 (NULL, "nosrv", "do not launch JTAG proxy server");
 
  srv = arg_int0 (NULL, "srv", "<n>", "port number (default random)");
 
  srv->ival[0] = rand () % (65536 - 49152) + 49152;
 
  srv->hdr.flag |= ARG_HASOPTVALUE;
 
  mem = arg_str0 ("m", "memory", "<n>", "add memory block of <n> bytes");
 
  dbg = arg_str0 ("d", "debug-config", "<str>", "Debug config string");
 
  command = arg_lit0 ("i", "interactive", "launch interactive prompt");
 
  quiet = arg_lit0 ("q", "quiet", "minimal message output");
 
  verbose = arg_lit0 ("V", "verbose", "verbose message output");
 
  report_mem_errs = arg_lit0 (NULL, "report-memory-errors",
 
                              "Report out of memory accesses");
 
  strict_npc = arg_lit0 (NULL, "strict-npc", "setting NPC flushes pipeline");
 
  profile = arg_lit0 (NULL, "enable-profile", "enable profiling");
 
  mprofile = arg_lit0 (NULL, "enable-mprofile", "enable memory profiling");
 
  load_file = arg_file0 (NULL, NULL, "<file>", "OR32 executable");
 
  end = arg_end (20);
 
 
 
  /* The argument table */
 
  void *argtab[] = {
 
    vercop,
 
    help,
 
    cfg_file,
 
    nosrv,
 
    srv,
 
    mem,
 
    dbg,
 
    command,
 
    quiet,
 
    verbose,
 
    report_mem_errs,
 
    strict_npc,
 
    profile,
 
    mprofile,
 
    load_file,
 
    end };
 
 
 
  /* Parse */
 
  int  nerrors = arg_parse (argc, argv, argtab);
 
 
 
  /* Special case here is if help or version is specified, we ignore any other
 
     errors and just print the help or version information and then give up. */
 
  if (vercop->count > 0)
 
    {
 
      PRINTF ("OpenRISC 1000 Architectural Simulator, version %s\n",
 
              PACKAGE_VERSION);
 
 
 
      arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
 
      return 1;
 
    }
 
 
 
  if (help->count > 0)
 
    {
 
      printf ("Usage:\n  %s ", argv[0]);
 
      arg_print_syntax (stdout, argtab, "\n\n");
 
      arg_print_glossary (stdout, argtab, "  %-25s %s\n");
 
 
 
      arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
 
      return 1;
 
    }
 
 
 
  /* Deal with any errors */
 
  if (0 != nerrors)
 
    {
 
      arg_print_errors (stderr, end, "or1ksim");
 
      printf ("\nUsage:\n  %s ", argv[0]);
 
      arg_print_syntaxv (stderr, argtab, "\n");
 
 
 
      arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
 
      return 1;
 
    }
 
 
 
  /* Request for quiet running */
 
  config.sim.quiet = quiet->count;
 
 
 
  /* Request for verbose running. Not sensible to use with quiet as well. */
 
  if (quiet->count && verbose->count)
 
    {
 
      fprintf (stderr, "Warning: Cannot specify both --verbose and --quiet: "
 
               "--vervose ignored.\n");
 
      config.sim.verbose = 0;
 
    }
 
  else
 
    {
 
      config.sim.verbose = verbose->count;
 
    }
 
 
 
  /* Request for memory errors */
 
  config.sim.report_mem_errs = report_mem_errs->count;
 
 
 
  /* Process config file next (if given), so any other command args will
 
     override */
 
  if (0 == cfg_file->count)
 
    {
 
      if (config.sim.verbose)
 
        {
 
          fprintf (stderr, "Default configuration used\n");
 
        }
 
    }
 
  else
 
    {
 
      read_script_file (cfg_file->filename[0]);
 
    }
 
 
 
  /* Allocate a memory block */
 
  if (mem->count > 0)
 
    {
 
      alloc_memory_block (mem->sval[0]);
 
    }
 
 
 
  /* Remote debug server */
 
  if (nosrv->count > 0)
 
    {
 
      if (srv->count > 0)
 
        {
 
          fprintf (stderr,
 
                   "%s: cannot specify --nosrv with --srv. Ignoring --nosrv\n",
 
                   argv[0]);
 
        }
 
      else
 
        {
 
          config.debug.enabled = 0;
 
          config.debug.gdb_enabled = 0;
 
        }
 
    }
 
 
 
  if (srv->count > 0)
 
    {
 
      config.debug.enabled = 1;
 
      config.debug.gdb_enabled = 1;
 
      config.debug.server_port = srv->ival[0];
 
    }
 
 
 
  /* Runtime debug messages */
 
  if (dbg->count > 0)
 
    {
 
      parse_dbchs (dbg->sval[0]);
 
    }
 
 
 
  /* Interactive operation */
 
  runtime.sim.iprompt = command->count;
 
 
 
  /* Request for strict NPC behavior (flush the pipeline on change) */
 
  config.sim.strict_npc = strict_npc->count;
 
 
 
  /* Profiling requests */
 
  config.sim.profile = profile->count;
 
  config.sim.mprofile = mprofile->count;
 
 
 
  /* Executable file */
 
  if (load_file->count > 0)
 
    {
 
      runtime.sim.filename = strdup (load_file->filename[0]);
 
    }
 
  else
 
    {
 
      runtime.sim.filename = NULL;
 
    }
 
 
 
  arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
 
  return 0;                      /* Success */
 
 
 
}       /* parse_args() */
 
 
 
 
 
/*---------------------------------------------------------------------------*/
 
/*!Print the current configuration                                           */
 
/*---------------------------------------------------------------------------*/
 
void
 
print_config ()
 
{
 
  if (config.sim.verbose)
 
    {
 
      char temp[20];
 
      PRINTF ("Verbose on, ");
 
      if (config.sim.debug)
 
        PRINTF ("simdebug on, ");
 
      else
 
        PRINTF ("simdebug off, ");
 
      if (runtime.sim.iprompt)
 
        PRINTF ("interactive prompt on\n");
 
      else
 
        PRINTF ("interactive prompt off\n");
 
 
 
      PRINTF ("Machine initialization...\n");
 
      generate_time_pretty (temp, config.sim.clkcycle_ps);
      PRINTF ("Clock cycle: %s\n", temp);
      PRINTF ("Clock cycle: %s\n", temp);
      if (cpu_state.sprs[SPR_UPR] & SPR_UPR_DCP)
      if (cpu_state.sprs[SPR_UPR] & SPR_UPR_DCP)
        PRINTF ("Data cache present.\n");
        PRINTF ("Data cache present.\n");
      else
      else
        PRINTF ("No data cache.\n");
        PRINTF ("No data cache.\n");
      if (cpu_state.sprs[SPR_UPR] & SPR_UPR_ICP)
      if (cpu_state.sprs[SPR_UPR] & SPR_UPR_ICP)
        PRINTF ("Insn cache tag present.\n");
        PRINTF ("Insn cache tag present.\n");
      else
      else
        PRINTF ("No instruction cache.\n");
        PRINTF ("No instruction cache.\n");
      if (config.bpb.enabled)
      if (config.bpb.enabled)
        PRINTF ("BPB simulation on.\n");
        PRINTF ("BPB simulation on.\n");
      else
      else
        PRINTF ("BPB simulation off.\n");
        PRINTF ("BPB simulation off.\n");
      if (config.bpb.btic)
      if (config.bpb.btic)
        PRINTF ("BTIC simulation on.\n");
        PRINTF ("BTIC simulation on.\n");
      else
      else
        PRINTF ("BTIC simulation off.\n");
        PRINTF ("BTIC simulation off.\n");
    }
    }
}
}
 
 
struct config_param
/* Simulator configuration */
{
 
  char *name;
 
  enum param_t type;
 
  void (*func) (union param_val, void *dat);
 
  struct config_param *next;
 
};
 
 
 
void
 
base_include (union param_val val, void *dat)
 
{
 
  read_script_file (val.str_val);
 
  cur_section = NULL;
 
}
 
 
 
/*---------------------------------------------[ Simulator configuration ]---*/
 
 
 
 
/*---------------------------------------------------------------------------*/
 
/*!Turn on verbose messages.
 
 
void
   @param[in] val  Non-zero (TRUE) to turn on verbose messages, zero (FALSE)
sim_verbose (union param_val val, void *dat)
                   otherwise.
 
   @param[in] dat  The config data structure (not used here)                 */
 
/*---------------------------------------------------------------------------*/
 
static void
 
sim_verbose (union param_val  val,
 
             void            *dat)
{
{
  config.sim.verbose = val.int_val;
  config.sim.verbose = val.int_val;
}
 
 
}       /* sim_verbose () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Set the simulator debug message level
/*!Set the simulator debug message level
 
 
   Value must be in the range 0 (no messages) to 9. Values outside this range
   Value must be in the range 0 (no messages) to 9. Values outside this range
   are converted to the nearer end of the range with a warning.
   are converted to the nearer end of the range with a warning.
 
 
   @param[in] val  The value to use
   @param[in] val  The value to use
   @param[in] dat  The config data structure (not used here)                 */
   @param[in] dat  The config data structure (not used here)                 */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
void
static void
sim_debug (union param_val  val,
sim_debug (union param_val  val,
           void            *dat)
           void            *dat)
{
{
  if (val.int_val < 0)
  if (val.int_val < 0)
    {
    {
      fprintf (stderr,
      fprintf (stderr,
               "Warning: Config debug value negative: 0 substituted\n");
               "Warning: Config debug value negative: 0 substituted\n");
      config.sim.debug = 0;
      config.sim.debug = 0;
    }
    }
  else if (val.int_val > 9)
  else if (val.int_val > 9)
    {
    {
      fprintf (stderr,
      fprintf (stderr,
               "Warning: Config debug value too large: 9 substituted\n");
               "Warning: Config debug value too large: 9 substituted\n");
      config.sim.debug = 9;
      config.sim.debug = 9;
    }
    }
  else
  else
    {
    {
      config.sim.debug = val.int_val;
      config.sim.debug = val.int_val;
    }
    }
}       /* sim_debug() */
}       /* sim_debug() */
 
 
 
 
void
/*---------------------------------------------------------------------------*/
sim_profile (union param_val val, void *dat)
/*!Turn on profiling
 
 
 
   @param[in] val  Non-zero (TRUE) to turn on profiling, zero (FALSE) otherwise.
 
   @param[in] dat  The config data structure (not used here)                 */
 
/*---------------------------------------------------------------------------*/
 
static void
 
sim_profile (union param_val  val,
 
             void            *dat)
{
{
  config.sim.profile = val.int_val;
  config.sim.profile = val.int_val;
}
 
 
 
void
}       /* sim_profile () */
sim_prof_fn (union param_val val, void *dat)
 
 
 
 
/*---------------------------------------------------------------------------*/
 
/*!Specify the profiling file name.
 
 
 
   @param[in] val  The profiling file name
 
   @param[in] dat  The config data structure (not used here)                 */
 
/*---------------------------------------------------------------------------*/
 
static void
 
sim_prof_fn (union param_val  val,
 
             void            *dat)
{
{
  if (NULL != config.sim.prof_fn)
  if (NULL != config.sim.prof_fn)
    {
    {
      free (config.sim.prof_fn);
      free (config.sim.prof_fn);
    }
    }
 
 
  config.sim.prof_fn = strdup(val.str_val);
  config.sim.prof_fn = strdup(val.str_val);
}
 
 
 
void
}       /* sim_prof_fn () */
sim_mprofile (union param_val val, void *dat)
 
 
 
 
/*---------------------------------------------------------------------------*/
 
/*!Turn on memory profiling
 
 
 
   @param[in] val  Non-zero (TRUE) to turn on memory profiling, zero (FALSE)
 
                   otherwise.
 
   @param[in] dat  The config data structure (not used here)                 */
 
/*---------------------------------------------------------------------------*/
 
static void
 
sim_mprofile (union param_val  val,
 
              void            *dat)
{
{
  config.sim.mprofile = val.int_val;
  config.sim.mprofile = val.int_val;
}
 
 
 
void
}       /* sim_mprofile () */
 
 
 
 
 
/*---------------------------------------------------------------------------*/
 
/*!Specify the memory profiling file name.
 
 
 
   @param[in] val  The memory profiling file name
 
   @param[in] dat  The config data structure (not used here)                 */
 
/*---------------------------------------------------------------------------*/
 
static void
sim_mprof_fn (union param_val val, void *dat)
sim_mprof_fn (union param_val val, void *dat)
{
{
  if (NULL != config.sim.mprof_fn)
  if (NULL != config.sim.mprof_fn)
    {
    {
      free (config.sim.mprof_fn);
      free (config.sim.mprof_fn);
    }
    }
 
 
  config.sim.mprof_fn = strdup (val.str_val);
  config.sim.mprof_fn = strdup (val.str_val);
}
 
 
 
void
}       /* sim_mprof_fn () */
sim_history (union param_val val, void *dat)
 
 
 
 
/*---------------------------------------------------------------------------*/
 
/*!Turn on execution tracking.
 
 
 
   @param[in] val  Non-zero (TRUE) to turn on tracking, zero (FALSE) otherwise.
 
   @param[in] dat  The config data structure (not used here)                 */
 
/*---------------------------------------------------------------------------*/
 
static void
 
sim_history (union param_val  val,
 
             void            *dat)
{
{
  config.sim.history = val.int_val;
  config.sim.history = val.int_val;
}
}
 
 
void
 
sim_exe_log (union param_val val, void *dat)
/*---------------------------------------------------------------------------*/
 
/*!Record an execution log
 
 
 
   @param[in] val  Non-zero (TRUE) to turn on logging, zero (FALSE) otherwise.
 
   @param[in] dat  The config data structure (not used here)                 */
 
/*---------------------------------------------------------------------------*/
 
static void
 
sim_exe_log (union param_val  val,
 
             void            *dat)
{
{
  config.sim.exe_log = val.int_val;
  config.sim.exe_log = val.int_val;
}
 
 
}       /* sim_exe_log () */
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Set the execution log type
/*!Set the execution log type
 
 
   Value must be one of default, hardware, simple or software. Invalid values
   Value must be one of default, hardware, simple or software. Invalid values
   are ignored with a warning.
   are ignored with a warning.
 
 
   @param[in] val  The value to use
   @param[in] val  The value to use
   @param[in] dat  The config data structure (not used here)                 */
   @param[in] dat  The config data structure (not used here)                 */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
void
static void
sim_exe_log_type (union param_val  val,
sim_exe_log_type (union param_val  val,
                  void            *dat)
                  void            *dat)
{
{
  if (strcasecmp (val.str_val, "default") == 0)
  if (strcasecmp (val.str_val, "default") == 0)
    {
    {
      config.sim.exe_log_type = EXE_LOG_HARDWARE;
      config.sim.exe_log_type = EXE_LOG_HARDWARE;
    }
    }
  else if (strcasecmp (val.str_val, "hardware") == 0)
  else if (strcasecmp (val.str_val, "hardware") == 0)
    {
    {
      config.sim.exe_log_type = EXE_LOG_HARDWARE;
      config.sim.exe_log_type = EXE_LOG_HARDWARE;
    }
    }
  else if (strcasecmp (val.str_val, "simple") == 0)
  else if (strcasecmp (val.str_val, "simple") == 0)
    {
    {
      config.sim.exe_log_type = EXE_LOG_SIMPLE;
      config.sim.exe_log_type = EXE_LOG_SIMPLE;
    }
    }
  else if (strcasecmp (val.str_val, "software") == 0)
  else if (strcasecmp (val.str_val, "software") == 0)
    {
    {
      config.sim.exe_log_type = EXE_LOG_SOFTWARE;
      config.sim.exe_log_type = EXE_LOG_SOFTWARE;
    }
    }
  else
  else
    {
    {
      fprintf (stderr, "Warning: Execution log type %s invalid. Ignored",
      fprintf (stderr, "Warning: Execution log type %s invalid. Ignored",
               val.str_val);
               val.str_val);
    }
    }
}       /* sim_exe_log_type() */
}       /* sim_exe_log_type() */
 
 
 
 
void
/*---------------------------------------------------------------------------*/
sim_exe_log_start (union param_val val, void *dat)
/*!Set the execution log start address
 
 
 
   Address at which to start logging.
 
 
 
   @param[in] val  The value to use
 
   @param[in] dat  The config data structure (not used here)                 */
 
/*---------------------------------------------------------------------------*/
 
static void
 
sim_exe_log_start (union param_val  val,
 
                   void            *dat)
{
{
  config.sim.exe_log_start = val.longlong_val;
  config.sim.exe_log_start = val.longlong_val;
}
 
 
 
void
}       /* sim_exe_log_start () */
sim_exe_log_end (union param_val val, void *dat)
 
 
 
 
/*---------------------------------------------------------------------------*/
 
/*!Set the execution log end address
 
 
 
   Address at which to end logging.
 
 
 
   @param[in] val  The value to use
 
   @param[in] dat  The config data structure (not used here)                 */
 
/*---------------------------------------------------------------------------*/
 
static void
 
sim_exe_log_end (union param_val  val,
 
                 void            *dat)
{
{
  config.sim.exe_log_end = val.longlong_val;
  config.sim.exe_log_end = val.longlong_val;
}
 
 
 
void
}       /* sim_exe_log_end () */
sim_exe_log_marker (union param_val val, void *dat)
 
 
 
 
/*---------------------------------------------------------------------------*/
 
/*!Specify number of instruction between printing horizontal markers
 
 
 
   Control of log format
 
 
 
   @param[in] val  The value to use
 
   @param[in] dat  The config data structure (not used here)                 */
 
/*---------------------------------------------------------------------------*/
 
static void
 
sim_exe_log_marker (union param_val  val,
 
                    void            *dat)
{
{
  config.sim.exe_log_marker = val.int_val;
  config.sim.exe_log_marker = val.int_val;
}
 
 
 
void
}       /* sim_exe_log_marker () */
 
 
 
 
 
/*---------------------------------------------------------------------------*/
 
/*!Specify the execution log file name.
 
 
 
   @param[in] val  The execution log file name
 
   @param[in] dat  The config data structure (not used here)                 */
 
/*---------------------------------------------------------------------------*/
 
static void
sim_exe_log_fn (union param_val val, void *dat)
sim_exe_log_fn (union param_val val, void *dat)
{
{
  if (NULL != config.sim.exe_log_fn)
  if (NULL != config.sim.exe_log_fn)
    {
    {
      free (config.sim.exe_log_fn);
      free (config.sim.exe_log_fn);
    }
    }
 
 
  config.sim.exe_log_fn = strdup (val.str_val);
  config.sim.exe_log_fn = strdup (val.str_val);
}
 
 
 
void
}       /* sim_exe_log_fn () */
 
 
 
 
 
/*---------------------------------------------------------------------------*/
 
/*!Turn on binary instruction logging
 
 
 
   @param[in] val  Non-zero (TRUE) to turn on logging, zero (FALSE) otherwise.
 
   @param[in] dat  The config data structure (not used here)                 */
 
/*---------------------------------------------------------------------------*/
 
static void
sim_exe_bin_insn_log (union param_val val, void *dat)
sim_exe_bin_insn_log (union param_val val, void *dat)
{
{
  config.sim.exe_bin_insn_log = val.int_val;
  config.sim.exe_bin_insn_log = val.int_val;
}
 
 
 
void
}       /* sim_exe_bin_insn_log () */
 
 
 
 
 
/*---------------------------------------------------------------------------*/
 
/*!Specify the binary instruction log file name.
 
 
 
   @param[in] val  The binary instruction log file name
 
   @param[in] dat  The config data structure (not used here)                 */
 
/*---------------------------------------------------------------------------*/
 
static void
sim_exe_bin_insn_log_fn (union param_val val, void *dat)
sim_exe_bin_insn_log_fn (union param_val val, void *dat)
{
{
  if (NULL != config.sim.exe_bin_insn_log_fn)
  if (NULL != config.sim.exe_bin_insn_log_fn)
    {
    {
      free (config.sim.exe_bin_insn_log_fn);
      free (config.sim.exe_bin_insn_log_fn);
    }
    }
 
 
  config.sim.exe_bin_insn_log_fn = strdup (val.str_val);
  config.sim.exe_bin_insn_log_fn = strdup (val.str_val);
}
 
 
 
 
 
 
 
 
}       /* sim_exe_bin_insn_log_fn () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Set the clock cycle time.
/*!Set the clock cycle time.
 
 
   Value must be an integer followed by one of ps, ns, us or ms.
   Value must be an integer followed by one of ps, ns, us or ms.
 
 
   If a valid time is not presented, the value is unchanged.
   If a valid time is not presented, the value is unchanged.
 
 
   @param[in] val  The value to use
   @param[in] val  The value to use
   @param[in] dat  The config data structure (not used here)                 */
   @param[in] dat  The config data structure (not used here)                 */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
void
void
sim_clkcycle (union param_val  val,
sim_clkcycle (union param_val  val,
              void            *dat)
              void            *dat)
{
{
  int len = strlen (val.str_val);
  int len = strlen (val.str_val);
  int pos = len - 1;
  int pos = len - 1;
  long time;
  long time;
  if ((len < 2) || (val.str_val[pos--] != 's'))
  if ((len < 2) || (val.str_val[pos--] != 's'))
    {
    {
      fprintf (stderr, "Warning: Clock cycle time %s invalid: ignored\n",
      fprintf (stderr, "Warning: Clock cycle time %s invalid: ignored\n",
               val.str_val);
               val.str_val);
      return;
      return;
    }
    }
 
 
  switch (val.str_val[pos--])
  switch (val.str_val[pos--])
    {
    {
    case 'p':
    case 'p':
      time = 1;
      time = 1;
      break;
      break;
    case 'n':
    case 'n':
      time = 1000;
      time = 1000;
      break;
      break;
    case 'u':
    case 'u':
      time = 1000000;
      time = 1000000;
      break;
      break;
    case 'm':
    case 'm':
      time = 1000000000;
      time = 1000000000;
      break;
      break;
    default:
    default:
      fprintf (stderr, "Warning: Clock cycle time %s invalid: ignored\n",
      fprintf (stderr, "Warning: Clock cycle time %s invalid: ignored\n",
               val.str_val);
               val.str_val);
      return;
      return;
    }
    }
 
 
  val.str_val[pos + 1] = 0;
  val.str_val[pos + 1] = 0;
  time = time * atol (val.str_val);
  time = time * atol (val.str_val);
 
 
  if (0 == time)
  if (0 == time)
    {
    {
      fprintf (stderr, "Warning: Clock cycle time of zero invalid: ignored\n");
      fprintf (stderr, "Warning: Clock cycle time of zero invalid: ignored\n");
      return;
      return;
    }
    }
 
 
  config.sim.clkcycle_ps = time;
  config.sim.clkcycle_ps = time;
 
 
}       /* sim_clkcycle() */
}       /* sim_clkcycle() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Register the functions to handle a section sim
/*!Register the functions to handle a section sim
 
 
   This section does not allocate dynamically a data structure holding its
   This section does not allocate dynamically a data structure holding its
   config information. It's all in the global config.sim data
   config information. It's all in the global config.sim data
   structure. Therefore it does not need a start and end function to
   structure. Therefore it does not need a start and end function to
   initialize default values (although it might be clearer to do so). The
   initialize default values (although it might be clearer to do so). The
   default values are set in init_defconfig().
   default values are set in init_defconfig().
 
 
   New preferred parameter names are introduced (_file for filenames), but
   New preferred parameter names are introduced (_file for filenames), but
   the legacy names (_fn) are also present for backwards compatibility       */
   the legacy names (_fn) are also present for backwards compatibility       */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
reg_sim_sec ()
reg_sim_sec ()
{
{
  struct config_section *sec = reg_config_sec ("sim", NULL, NULL);
  struct config_section *sec = reg_config_sec ("sim", NULL, NULL);
 
 
  reg_config_param (sec, "verbose",        paramt_int,      sim_verbose);
  reg_config_param (sec, "verbose",        PARAMT_INT,      sim_verbose);
  reg_config_param (sec, "debug",          paramt_int,      sim_debug);
  reg_config_param (sec, "debug",          PARAMT_INT,      sim_debug);
  reg_config_param (sec, "profile",        paramt_int,      sim_profile);
  reg_config_param (sec, "profile",        PARAMT_INT,      sim_profile);
  reg_config_param (sec, "prof_file",      paramt_str,      sim_prof_fn);
  reg_config_param (sec, "prof_file",      PARAMT_STR,      sim_prof_fn);
  reg_config_param (sec, "prof_fn",        paramt_str,      sim_prof_fn);
  reg_config_param (sec, "prof_fn",        PARAMT_STR,      sim_prof_fn);
  reg_config_param (sec, "mprofile",       paramt_int,      sim_mprofile);
  reg_config_param (sec, "mprofile",       PARAMT_INT,      sim_mprofile);
  reg_config_param (sec, "mprof_file",     paramt_str,      sim_mprof_fn);
  reg_config_param (sec, "mprof_file",     PARAMT_STR,      sim_mprof_fn);
  reg_config_param (sec, "mprof_fn",       paramt_str,      sim_mprof_fn);
  reg_config_param (sec, "mprof_fn",       PARAMT_STR,      sim_mprof_fn);
  reg_config_param (sec, "history",        paramt_int,      sim_history);
  reg_config_param (sec, "history",        PARAMT_INT,      sim_history);
  reg_config_param (sec, "exe_log",        paramt_int,      sim_exe_log);
  reg_config_param (sec, "exe_log",        PARAMT_INT,      sim_exe_log);
  reg_config_param (sec, "exe_log_type",   paramt_word,     sim_exe_log_type);
  reg_config_param (sec, "exe_log_type",   PARAMT_WORD,     sim_exe_log_type);
  reg_config_param (sec, "exe_log_start",  paramt_longlong, sim_exe_log_start);
  reg_config_param (sec, "exe_log_start",  PARAMT_LONGLONG, sim_exe_log_start);
  reg_config_param (sec, "exe_log_end",    paramt_longlong, sim_exe_log_end);
  reg_config_param (sec, "exe_log_end",    PARAMT_LONGLONG, sim_exe_log_end);
  reg_config_param (sec, "exe_log_marker", paramt_int,      sim_exe_log_marker);
  reg_config_param (sec, "exe_log_marker", PARAMT_INT,      sim_exe_log_marker);
  reg_config_param (sec, "exe_log_file",   paramt_str,      sim_exe_log_fn);
  reg_config_param (sec, "exe_log_file",   PARAMT_STR,      sim_exe_log_fn);
  reg_config_param (sec, "exe_log_fn",     paramt_str,      sim_exe_log_fn);
  reg_config_param (sec, "exe_log_fn",     PARAMT_STR,      sim_exe_log_fn);
  reg_config_param (sec, "exe_bin_insn_log",paramt_int,     sim_exe_bin_insn_log);
 
  reg_config_param (sec, "exe_bin_insn_log_fn",paramt_str,  sim_exe_bin_insn_log_fn);
  reg_config_param (sec, "exe_bin_insn_log",      PARAMT_INT,
  reg_config_param (sec, "exe_bin_insn_log_file",paramt_str,  sim_exe_bin_insn_log_fn);
                    sim_exe_bin_insn_log);
  reg_config_param (sec, "clkcycle",       paramt_word,     sim_clkcycle);
  reg_config_param (sec, "exe_bin_insn_log_fn",   PARAMT_STR,
 
                    sim_exe_bin_insn_log_fn);
 
  reg_config_param (sec, "exe_bin_insn_log_file", PARAMT_STR,
 
                    sim_exe_bin_insn_log_fn);
 
 
 
  reg_config_param (sec, "clkcycle",       PARAMT_WORD,     sim_clkcycle);
 
 
}       /* reg_sim_sec() */
}       /* reg_sim_sec() */
 
 
 
 
 
/*---------------------------------------------------------------------------*/
 
/*!Register all the possible sections which we support.
 
 
 
   Each section type provides a registration function. This returns a struct
 
   config_section, which in turn contains a list of config_params.           */
 
/*---------------------------------------------------------------------------*/
void
void
reg_config_secs (void)
reg_config_secs ()
{
{
  reg_config_param (reg_config_sec ("base", NULL, NULL), "include",
 
                    paramt_str, base_include);
 
 
 
  reg_generic_sec ();           /* JPB */
  reg_generic_sec ();           /* JPB */
  reg_sim_sec ();
  reg_sim_sec ();
  reg_cpu_sec ();
  reg_cpu_sec ();
  reg_pic_sec ();
  reg_pic_sec ();
  reg_memory_sec ();
  reg_memory_sec ();
  reg_mc_sec ();
  reg_mc_sec ();
  reg_uart_sec ();
  reg_uart_sec ();
  reg_dma_sec ();
  reg_dma_sec ();
  reg_debug_sec ();
  reg_debug_sec ();
  reg_vapi_sec ();
  reg_vapi_sec ();
  reg_ethernet_sec ();
  reg_ethernet_sec ();
  reg_immu_sec ();
  reg_immu_sec ();
  reg_dmmu_sec ();
  reg_dmmu_sec ();
  reg_ic_sec ();
  reg_ic_sec ();
  reg_dc_sec ();
  reg_dc_sec ();
  reg_gpio_sec ();
  reg_gpio_sec ();
  reg_bpb_sec ();
  reg_bpb_sec ();
  reg_pm_sec ();
  reg_pm_sec ();
  reg_vga_sec ();
  reg_vga_sec ();
  reg_fb_sec ();
  reg_fb_sec ();
  reg_kbd_sec ();
  reg_kbd_sec ();
  reg_ata_sec ();
  reg_ata_sec ();
  reg_cuc_sec ();
  reg_cuc_sec ();
}
}
 
 
void
 
reg_config_param (struct config_section *sec, const char *param,
 
                  enum param_t type,
 
                  void (*param_cb) (union param_val, void *))
 
{
 
  struct config_param *new = malloc (sizeof (struct config_param));
 
 
 
  if (!new)
 
    {
 
      fprintf (stderr, "Out-of-memory\n");
 
      exit (1);
 
    }
 
 
 
  if (!(new->name = strdup (param)))
 
    {
 
      fprintf (stderr, "Out-of-memory\n");
 
      exit (1);
 
    }
 
 
 
  new->func = param_cb;
 
  new->type = type;
 
 
 
  new->next = sec->params;
 
  sec->params = new;
 
}
 
 
 
struct config_section *
 
reg_config_sec (const char *section,
 
                void *(*sec_start) (void), void (*sec_end) (void *))
 
{
 
  struct config_section *new = malloc (sizeof (struct config_section));
 
 
 
  if (!new)
 
    {
 
      fprintf (stderr, "Out-of-memory\n");
 
      exit (1);
 
    }
 
 
 
  if (!(new->name = strdup (section)))
 
    {
 
      fprintf (stderr, "Out-of-memory\n");
 
      exit (1);
 
    }
 
 
 
  new->next = sections;
 
  new->sec_start = sec_start;
 
  new->sec_end = sec_end;
 
  new->params = NULL;
 
 
 
  sections = new;
 
 
 
  return new;
 
}
 
 
 
static void
 
switch_param (char *param, struct config_param *cur_param)
 
{
 
  char *end_p;
 
  union param_val val;
 
 
 
  /* Skip over an = sign if it exists */
 
  if (*param == '=')
 
    {
 
      param++;
 
      while (*param && isspace (*param))
 
        param++;
 
    }
 
 
 
  switch (cur_param->type)
 
    {
 
    case paramt_int:
 
      val.int_val = strtol (param, NULL, 0);
 
      break;
 
    case paramt_longlong:
 
      val.longlong_val = strtoll (param, NULL, 0);
 
      break;
 
    case paramt_addr:
 
      val.addr_val = strtoul (param, NULL, 0);
 
      break;
 
    case paramt_str:
 
      if (*param != '"')
 
        {
 
          fprintf (stderr,
 
                   "Warning: String value for parameter expected: ignored\n");
 
          return;
 
        }
 
 
 
      param++;
 
      end_p = param;
 
      while (*end_p && (*end_p != '"'))
 
        end_p++;
 
      *end_p = '\0';
 
      val.str_val = param;
 
      break;
 
    case paramt_word:
 
      end_p = param;
 
      while (*end_p && !isspace (*end_p))
 
        end_p++;
 
      *end_p = '\0';
 
      val.str_val = param;
 
      break;
 
    case paramt_none:
 
      break;
 
    }
 
 
 
  cur_param->func (val, cur_section->dat);
 
}
 
 
 
/* Read environment from a script file. Does not fail - assumes default configuration instead.
 
   The syntax of script file is:
 
   param = value
 
   section x
 
     data
 
     param = value
 
   end
 
 
 
   Example:
 
   section mc
 
     memory_table_file = sim.mem
 
     enable = 1
 
     POC = 0x47892344
 
   end
 
 
 
 */
 
 
 
static void
 
read_script_file (const char *filename)
 
{
 
  FILE *f;
 
  char *home = getenv ("HOME");
 
  char ctmp[STR_SIZE];
 
  int local = 1;
 
  cur_section = NULL;
 
 
 
  sprintf (ctmp, "%s/.or1k/%s", home, filename);
 
  if ((f = fopen (filename, "rt")) || (home && (f = fopen (ctmp, "rt"))))
 
    {
 
      if (config.sim.verbose)
 
        PRINTF ("Reading script file from '%s'...\n",
 
                local ? filename : ctmp);
 
 
 
      while (!feof (f))
 
        {
 
          char param[STR_SIZE];
 
          if (fscanf (f, "%s ", param) != 1)
 
            break;
 
          /* Is this a section? */
 
          if (strcmp (param, "section") == 0)
 
            {
 
              struct config_section *cur;
 
              cur_section = NULL;
 
              if (fscanf (f, "%s\n", param) != 1)
 
                {
 
                  fprintf (stderr, "%s: ERROR: Section name required.\n",
 
                           local ? filename : ctmp);
 
                  exit (1);
 
                }
 
              for (cur = sections; cur; cur = cur->next)
 
                if (strcmp (cur->name, param) == 0)
 
                  {
 
                    cur_section = cur;
 
                    break;
 
                  }
 
              if (!cur)
 
                {
 
                  fprintf (stderr,
 
                           "Warning: Unknown config section: %s; ignoring.\n",
 
                           param);
 
                  /* just skip section */
 
                  while (fscanf (f, "%s\n", param) == 1
 
                         && strcmp (param, "end"));
 
                }
 
              else
 
                {
 
                  cur->dat = NULL;
 
                  if (cur->sec_start)
 
                    cur->dat = cur->sec_start ();
 
                }
 
            }
 
          else if (strcmp (param, "end") == 0)
 
            {
 
              if (cur_section->sec_end)
 
                cur_section->sec_end (cur_section->dat);
 
              cur_section = NULL;
 
            }
 
          else if (strncmp (param, "/*", 2) == 0)
 
            {
 
              char c0 = 0, c1 = 0;
 
              while (c0 != '*' || c1 != '/')
 
                {
 
                  c0 = c1;
 
                  c1 = fgetc (f);
 
                  if (feof (f))
 
                    {
 
                      fprintf (stderr, "%s: ERROR: Comment reached EOF.\n",
 
                               local ? filename : ctmp);
 
                      exit (1);
 
                    }
 
                }
 
            }
 
          else
 
            {
 
              struct config_param *cur_param = NULL;
 
              char *cur_p;
 
              /* If we have a corrupt file, this could be encountered outside
 
                 a section. So make sure cur_section is defined. */
 
              if (cur_section)
 
                {
 
                  for (cur_param = cur_section->params; cur_param;
 
                       cur_param = cur_param->next)
 
                    {
 
                      if (strcmp (cur_param->name, param) == 0)
 
                        {
 
                          break;
 
                        }
 
                    }
 
                }
 
              if (!cur_param)
 
                {
 
                  fprintf (stderr, "Warning: Invalid parameter: %s; ignored\n",
 
                           param);
 
                  while (fgetc (f) != '\n' || feof (f));
 
                  continue;
 
                }
 
 
 
              if (cur_param->type == paramt_none)
 
                continue;
 
 
 
              /* Parse parameter value */
 
              cur_p = fgets (param, STR_SIZE, f);
 
 
 
              while (*cur_p && isspace (*cur_p))
 
                cur_p++;
 
 
 
              switch_param (cur_p, cur_param);
 
            }
 
        }
 
      fclose (f);
 
    }
 
  else if (config.sim.verbose)
 
    fprintf (stderr,
 
             "Warning: Cannot read script file from '%s' of '%s'.\n",
 
             filename, ctmp);
 
}
 
 
 
/* Utility for execution of set sim command.  */
/* Utility for execution of set sim command.  */
static int
static int
set_config (int argc, char **argv)
set_config (int argc, char **argv)
{
{
  struct config_section *cur;
  struct config_section *cur_section;
  struct config_param *cur_param;
  struct config_param *param;
 
 
  if (argc < 2)
  if (argc < 2)
    return 1;
    return 1;
 
 
  PRINTF ("sec:%s\n", argv[1]);
  PRINTF ("sec:%s\n", argv[1]);
  cur_section = NULL;
  cur_section = lookup_section (argv[1]);
  for (cur = sections; cur; cur = cur->next)
 
    if (strcmp (cur->name, argv[1]) == 0)
 
      {
 
        cur_section = cur;
 
        break;
 
      }
 
 
 
  if (!cur_section)
  if (NULL == cur_section)
    return 1;
    return 1;
 
 
  if (argc < 3)
  if (argc < 3)
    return 2;
    return 2;
 
 
  PRINTF ("item:%s\n", argv[2]);
  PRINTF ("item:%s\n", argv[2]);
  {
  {
    for (cur_param = cur->params; cur_param; cur_param = cur_param->next)
    for (param = cur_section->params; param; param = param->next)
      if (strcmp (cur_param->name, argv[2]) == 0)
      if (strcmp (param->name, argv[2]) == 0)
        {
        {
          break;
          break;
        }
        }
    if (!cur_param)
    if (!param)
      return 2;
      return 2;
 
 
    /* Parse parameter value */
    /* Parse parameter value */
    if (cur_param->type)
    if (param->type)
      {
      {
        if (argc < 4)
        if (argc < 4)
          return 3;
          return 3;
        PRINTF ("params:%s\n", argv[3]);
        PRINTF ("params:%s\n", argv[3]);
      }
      }
 
 
    switch_param (argv[3], cur_param);
    set_config_param (cur_section, param, argv[3]);
  }
  }
  return 0;
  return 0;
}
}
 
 
/* Executes set sim command, displays error.  */
/* Executes set sim command, displays error.  */
void
void
set_config_command (int argc, char **argv)
set_config_command (int argc, char **argv)
{
{
  struct config_section *cur;
  struct config_section *cur;
  struct config_param *cur_param;
  struct config_param *param;
 
 
  switch (set_config (argc, argv))
  switch (set_config (argc, argv))
    {
    {
    case 1:
    case 1:
      PRINTF
      PRINTF
        ("Invalid or missing section name.  One of valid sections must be specified:\n");
        ("Invalid or missing section name.  One of valid sections must be specified:\n");
      for (cur = sections; cur; cur = cur->next)
      for (cur = section_master_list; cur; cur = cur->next)
        PRINTF ("%s ", cur->name);
        PRINTF ("%s ", cur->name);
      PRINTF ("\n");
      PRINTF ("\n");
      break;
      break;
    case 2:
    case 2:
 
      cur = lookup_section (argv[1]);
      PRINTF
      PRINTF
        ("Invalid or missing item name.  One of valid items must be specified:\n");
        ("Invalid or missing item name.  One of valid items must be specified:\n");
      for (cur_param = cur_section->params; cur_param;
      for (param = cur->params; param;
           cur_param = cur_param->next)
           param = param->next)
        PRINTF ("%s ", cur_param->name);
        PRINTF ("%s ", param->name);
      PRINTF ("\n");
      PRINTF ("\n");
      break;
      break;
    case 3:
    case 3:
      PRINTF ("Invalid parameters specified.\n");
      PRINTF ("Invalid parameters specified.\n");
      break;
      break;
    }
    }
}
}
 
 

powered by: WebSVN 2.1.0

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