/* 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;
|
}
|
}
|
}
|
}
|
|
|