/* 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"
|
|
|
|
|
struct config config;
|
struct config config;
|
struct runtime runtime;
|
struct runtime runtime;
|
|
|
struct config_section *cur_section;
|
struct config_section *cur_section;
|
|
|
struct config_section *sections = NULL;
|
struct config_section *sections = NULL;
|
|
|
/* Forward declarations */
|
/* Forward declarations */
|
static void read_script_file (const char *filename);
|
static void read_script_file (const char *filename);
|
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
/*!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.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.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;
|
|
|
/* 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
|
/*! Parse the arguments for the standalone simulator
|
|
|
Updated by Jeremy Bennett to use argtable2.
|
Updated by Jeremy Bennett to use argtable2.
|
|
|
@param[in] argc Number of command args
|
@param[in] argc Number of command args
|
@param[in] argv Vector of the command args
|
@param[in] argv Vector of the command args
|
|
|
@return 0 on success, 1 on failure */
|
@return 0 on success, 1 on failure */
|
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
int
|
int
|
parse_args (int argc, char *argv[])
|
parse_args (int argc, char *argv[])
|
{
|
{
|
struct arg_lit *vercop;
|
struct arg_lit *vercop;
|
struct arg_lit *help;
|
struct arg_lit *help;
|
struct arg_file *cfg_file;
|
struct arg_file *cfg_file;
|
struct arg_lit *nosrv;
|
struct arg_lit *nosrv;
|
struct arg_int *srv;
|
struct arg_int *srv;
|
struct arg_str *dbg;
|
struct arg_str *dbg;
|
struct arg_lit *command;
|
struct arg_lit *command;
|
struct arg_lit *strict_npc;
|
struct arg_lit *strict_npc;
|
struct arg_lit *profile;
|
struct arg_lit *profile;
|
struct arg_lit *mprofile;
|
struct arg_lit *mprofile;
|
struct arg_file *load_file;
|
struct arg_file *load_file;
|
struct arg_end *end;
|
struct arg_end *end;
|
|
|
void *argtab[12];
|
void *argtab[12];
|
int nerrors;
|
int nerrors;
|
|
|
/* Specify each argument, with fall back values */
|
/* Specify each argument, with fall back values */
|
vercop = arg_lit0 ("v", "version", "version and copyright notice");
|
vercop = arg_lit0 ("v", "version", "version and copyright notice");
|
help = arg_lit0 ("h", "help", "print this help message");
|
help = arg_lit0 ("h", "help", "print this help message");
|
cfg_file = arg_file0 ("f", "file", "<file>",
|
cfg_file = arg_file0 ("f", "file", "<file>",
|
"config file (default \"sim.cfg\")");
|
"config file (default \"sim.cfg\")");
|
cfg_file->filename[0] = "sim.cfg";
|
cfg_file->filename[0] = "sim.cfg";
|
nosrv = arg_lit0 (NULL, "nosrv", "do not launch JTAG proxy server");
|
nosrv = arg_lit0 (NULL, "nosrv", "do not launch JTAG proxy server");
|
srv = arg_int0 (NULL, "srv", "<n>", "port number (default random)");
|
srv = arg_int0 (NULL, "srv", "<n>", "port number (default random)");
|
srv->ival[0] = rand () % (65536 - 49152) + 49152;
|
srv->ival[0] = rand () % (65536 - 49152) + 49152;
|
srv->hdr.flag |= ARG_HASOPTVALUE;
|
srv->hdr.flag |= ARG_HASOPTVALUE;
|
dbg = arg_str0 ("d", "debug-config", "<str>", "Debug config string");
|
dbg = arg_str0 ("d", "debug-config", "<str>", "Debug config string");
|
command = arg_lit0 ("i", "interactive", "launch interactive prompt");
|
command = arg_lit0 ("i", "interactive", "launch interactive prompt");
|
strict_npc = arg_lit0 (NULL, "strict-npc", "setting NPC flushes pipeline");
|
strict_npc = arg_lit0 (NULL, "strict-npc", "setting NPC flushes pipeline");
|
profile = arg_lit0 (NULL, "enable-profile", "enable profiling");
|
profile = arg_lit0 (NULL, "enable-profile", "enable profiling");
|
mprofile = arg_lit0 (NULL, "enable-mprofile", "enable memory profiling");
|
mprofile = arg_lit0 (NULL, "enable-mprofile", "enable memory profiling");
|
load_file = arg_file0 (NULL, NULL, "<file>", "OR32 executable");
|
load_file = arg_file0 (NULL, NULL, "<file>", "OR32 executable");
|
end = arg_end (20);
|
end = arg_end (20);
|
|
|
/* Set up the argument table */
|
/* Set up the argument table */
|
argtab[ 0] = vercop;
|
argtab[ 0] = vercop;
|
argtab[ 1] = help;
|
argtab[ 1] = help;
|
argtab[ 2] = cfg_file;
|
argtab[ 2] = cfg_file;
|
argtab[ 3] = nosrv;
|
argtab[ 3] = nosrv;
|
argtab[ 4] = srv;
|
argtab[ 4] = srv;
|
argtab[ 5] = dbg;
|
argtab[ 5] = dbg;
|
argtab[ 6] = command;
|
argtab[ 6] = command;
|
argtab[ 7] = strict_npc;
|
argtab[ 7] = strict_npc;
|
argtab[ 8] = profile;
|
argtab[ 8] = profile;
|
argtab[ 9] = mprofile;
|
argtab[ 9] = mprofile;
|
argtab[10] = load_file;
|
argtab[10] = load_file;
|
argtab[11] = end;
|
argtab[11] = end;
|
|
|
/* Parse */
|
/* Parse */
|
nerrors = arg_parse (argc, argv, argtab);
|
nerrors = arg_parse (argc, argv, argtab);
|
|
|
/* Special case here is if help or version is specified, we ignore any other
|
/* 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. */
|
errors and just print the help or version information and then give up. */
|
if (vercop->count > 0)
|
if (vercop->count > 0)
|
{
|
{
|
PRINTF ("OpenRISC 1000 Architectural Simulator, version %s\n",
|
PRINTF ("OpenRISC 1000 Architectural Simulator, version %s\n",
|
PACKAGE_VERSION);
|
PACKAGE_VERSION);
|
|
|
arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
|
arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
|
return 1;
|
return 1;
|
}
|
}
|
|
|
if (help->count > 0)
|
if (help->count > 0)
|
{
|
{
|
printf ("Usage:\n %s ", argv[0]);
|
printf ("Usage:\n %s ", argv[0]);
|
arg_print_syntax (stdout, argtab, "\n\n");
|
arg_print_syntax (stdout, argtab, "\n\n");
|
arg_print_glossary (stdout, argtab, " %-25s %s\n");
|
arg_print_glossary (stdout, argtab, " %-25s %s\n");
|
|
|
arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
|
arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
|
return 1;
|
return 1;
|
}
|
}
|
|
|
/* Deal with any errors */
|
/* Deal with any errors */
|
if (0 != nerrors)
|
if (0 != nerrors)
|
{
|
{
|
arg_print_errors (stderr, end, "or1ksim");
|
arg_print_errors (stderr, end, "or1ksim");
|
printf ("\nUsage:\n %s ", argv[0]);
|
printf ("\nUsage:\n %s ", argv[0]);
|
arg_print_syntaxv (stderr, argtab, "\n");
|
arg_print_syntaxv (stderr, argtab, "\n");
|
|
|
arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
|
arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
|
return 1;
|
return 1;
|
}
|
}
|
|
|
/* Process config file next, so any other command args will override */
|
/* Process config file next, so any other command args will override */
|
if (0 == cfg_file->count)
|
if (0 == cfg_file->count)
|
{
|
{
|
fprintf (stderr,
|
fprintf (stderr,
|
"Warning: No config file given, default configuration used\n");
|
"Warning: No config file given, default configuration used\n");
|
}
|
}
|
|
|
read_script_file (cfg_file->filename[0]);
|
read_script_file (cfg_file->filename[0]);
|
|
|
|
|
/* Remote debug server */
|
/* Remote debug server */
|
if (nosrv->count > 0)
|
if (nosrv->count > 0)
|
{
|
{
|
if (srv->count > 0)
|
if (srv->count > 0)
|
{
|
{
|
fprintf (stderr,
|
fprintf (stderr,
|
"%s: cannot specify --nosrv with --srv. Ignoring --nosrv\n",
|
"%s: cannot specify --nosrv with --srv. Ignoring --nosrv\n",
|
argv[0]);
|
argv[0]);
|
}
|
}
|
else
|
else
|
{
|
{
|
config.debug.enabled = 0;
|
config.debug.enabled = 0;
|
config.debug.gdb_enabled = 0;
|
config.debug.gdb_enabled = 0;
|
}
|
}
|
}
|
}
|
|
|
if (srv->count > 0)
|
if (srv->count > 0)
|
{
|
{
|
config.debug.enabled = 1;
|
config.debug.enabled = 1;
|
config.debug.gdb_enabled = 1;
|
config.debug.gdb_enabled = 1;
|
config.debug.server_port = srv->ival[0];
|
config.debug.server_port = srv->ival[0];
|
}
|
}
|
|
|
/* Runtime debug messages */
|
/* Runtime debug messages */
|
if (dbg->count > 0)
|
if (dbg->count > 0)
|
{
|
{
|
parse_dbchs (dbg->sval[0]);
|
parse_dbchs (dbg->sval[0]);
|
}
|
}
|
|
|
/* Interactive operation */
|
/* Interactive operation */
|
runtime.sim.iprompt = command->count;
|
runtime.sim.iprompt = command->count;
|
|
|
/* Request for strict NPC behavior (flush the pipeline on change) */
|
/* Request for strict NPC behavior (flush the pipeline on change) */
|
config.sim.strict_npc = strict_npc->count;
|
config.sim.strict_npc = strict_npc->count;
|
|
|
/* Profiling requests */
|
/* Profiling requests */
|
config.sim.profile = profile->count;
|
config.sim.profile = profile->count;
|
config.sim.mprofile = mprofile->count;
|
config.sim.mprofile = mprofile->count;
|
|
|
/* Executable file */
|
/* Executable file */
|
if (load_file->count > 0)
|
if (load_file->count > 0)
|
{
|
{
|
runtime.sim.filename = strdup (load_file->filename[0]);
|
runtime.sim.filename = strdup (load_file->filename[0]);
|
}
|
}
|
else
|
else
|
{
|
{
|
runtime.sim.filename = NULL;
|
runtime.sim.filename = NULL;
|
}
|
}
|
|
|
arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
|
arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
|
return 0; /* Success */
|
return 0; /* Success */
|
|
|
} /* parse_args() */
|
} /* parse_args() */
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
/*!Print the current configuration */
|
/*!Print the current configuration */
|
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
void
|
void
|
print_config ()
|
print_config ()
|
{
|
{
|
if (config.sim.verbose)
|
if (config.sim.verbose)
|
{
|
{
|
char temp[20];
|
char temp[20];
|
PRINTF ("Verbose on, ");
|
PRINTF ("Verbose on, ");
|
if (config.sim.debug)
|
if (config.sim.debug)
|
PRINTF ("simdebug on, ");
|
PRINTF ("simdebug on, ");
|
else
|
else
|
PRINTF ("simdebug off, ");
|
PRINTF ("simdebug off, ");
|
if (runtime.sim.iprompt)
|
if (runtime.sim.iprompt)
|
PRINTF ("interactive prompt on\n");
|
PRINTF ("interactive prompt on\n");
|
else
|
else
|
PRINTF ("interactive prompt off\n");
|
PRINTF ("interactive prompt off\n");
|
|
|
PRINTF ("Machine initialization...\n");
|
PRINTF ("Machine initialization...\n");
|
generate_time_pretty (temp, config.sim.clkcycle_ps);
|
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
|
struct config_param
|
{
|
{
|
char *name;
|
char *name;
|
enum param_t type;
|
enum param_t type;
|
void (*func) (union param_val, void *dat);
|
void (*func) (union param_val, void *dat);
|
struct config_param *next;
|
struct config_param *next;
|
};
|
};
|
|
|
void
|
void
|
base_include (union param_val val, void *dat)
|
base_include (union param_val val, void *dat)
|
{
|
{
|
read_script_file (val.str_val);
|
read_script_file (val.str_val);
|
cur_section = NULL;
|
cur_section = NULL;
|
}
|
}
|
|
|
/*---------------------------------------------[ Simulator configuration ]---*/
|
/*---------------------------------------------[ Simulator configuration ]---*/
|
|
|
|
|
void
|
void
|
sim_verbose (union param_val val, void *dat)
|
sim_verbose (union param_val val, void *dat)
|
{
|
{
|
config.sim.verbose = val.int_val;
|
config.sim.verbose = val.int_val;
|
}
|
}
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
/*!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
|
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
|
void
|
sim_profile (union param_val val, void *dat)
|
sim_profile (union param_val val, void *dat)
|
{
|
{
|
config.sim.profile = val.int_val;
|
config.sim.profile = val.int_val;
|
}
|
}
|
|
|
void
|
void
|
sim_prof_fn (union param_val val, void *dat)
|
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
|
void
|
sim_mprofile (union param_val val, void *dat)
|
sim_mprofile (union param_val val, void *dat)
|
{
|
{
|
config.sim.mprofile = val.int_val;
|
config.sim.mprofile = val.int_val;
|
}
|
}
|
|
|
void
|
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
|
void
|
sim_history (union param_val val, void *dat)
|
sim_history (union param_val val, void *dat)
|
{
|
{
|
config.sim.history = val.int_val;
|
config.sim.history = val.int_val;
|
}
|
}
|
|
|
void
|
void
|
sim_exe_log (union param_val val, void *dat)
|
sim_exe_log (union param_val val, void *dat)
|
{
|
{
|
config.sim.exe_log = val.int_val;
|
config.sim.exe_log = val.int_val;
|
}
|
}
|
|
|
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
/*!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
|
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
|
void
|
sim_exe_log_start (union param_val val, void *dat)
|
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
|
void
|
sim_exe_log_end (union param_val val, void *dat)
|
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
|
void
|
sim_exe_log_marker (union param_val val, void *dat)
|
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
|
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);
|
}
|
}
|
|
|
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
/*!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, "clkcycle", paramt_word, sim_clkcycle);
|
reg_config_param (sec, "clkcycle", paramt_word, sim_clkcycle);
|
|
|
} /* reg_sim_sec() */
|
} /* reg_sim_sec() */
|
|
|
|
|
void
|
void
|
reg_config_secs (void)
|
reg_config_secs (void)
|
{
|
{
|
reg_config_param (reg_config_sec ("base", NULL, NULL), "include",
|
reg_config_param (reg_config_sec ("base", NULL, NULL), "include",
|
paramt_str, base_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
|
void
|
reg_config_param (struct config_section *sec, const char *param,
|
reg_config_param (struct config_section *sec, const char *param,
|
enum param_t type,
|
enum param_t type,
|
void (*param_cb) (union param_val, void *))
|
void (*param_cb) (union param_val, void *))
|
{
|
{
|
struct config_param *new = malloc (sizeof (struct config_param));
|
struct config_param *new = malloc (sizeof (struct config_param));
|
|
|
if (!new)
|
if (!new)
|
{
|
{
|
fprintf (stderr, "Out-of-memory\n");
|
fprintf (stderr, "Out-of-memory\n");
|
exit (1);
|
exit (1);
|
}
|
}
|
|
|
if (!(new->name = strdup (param)))
|
if (!(new->name = strdup (param)))
|
{
|
{
|
fprintf (stderr, "Out-of-memory\n");
|
fprintf (stderr, "Out-of-memory\n");
|
exit (1);
|
exit (1);
|
}
|
}
|
|
|
new->func = param_cb;
|
new->func = param_cb;
|
new->type = type;
|
new->type = type;
|
|
|
new->next = sec->params;
|
new->next = sec->params;
|
sec->params = new;
|
sec->params = new;
|
}
|
}
|
|
|
struct config_section *
|
struct config_section *
|
reg_config_sec (const char *section,
|
reg_config_sec (const char *section,
|
void *(*sec_start) (void), void (*sec_end) (void *))
|
void *(*sec_start) (void), void (*sec_end) (void *))
|
{
|
{
|
struct config_section *new = malloc (sizeof (struct config_section));
|
struct config_section *new = malloc (sizeof (struct config_section));
|
|
|
if (!new)
|
if (!new)
|
{
|
{
|
fprintf (stderr, "Out-of-memory\n");
|
fprintf (stderr, "Out-of-memory\n");
|
exit (1);
|
exit (1);
|
}
|
}
|
|
|
if (!(new->name = strdup (section)))
|
if (!(new->name = strdup (section)))
|
{
|
{
|
fprintf (stderr, "Out-of-memory\n");
|
fprintf (stderr, "Out-of-memory\n");
|
exit (1);
|
exit (1);
|
}
|
}
|
|
|
new->next = sections;
|
new->next = sections;
|
new->sec_start = sec_start;
|
new->sec_start = sec_start;
|
new->sec_end = sec_end;
|
new->sec_end = sec_end;
|
new->params = NULL;
|
new->params = NULL;
|
|
|
sections = new;
|
sections = new;
|
|
|
return new;
|
return new;
|
}
|
}
|
|
|
static void
|
static void
|
switch_param (char *param, struct config_param *cur_param)
|
switch_param (char *param, struct config_param *cur_param)
|
{
|
{
|
char *end_p;
|
char *end_p;
|
union param_val val;
|
union param_val val;
|
|
|
/* Skip over an = sign if it exists */
|
/* Skip over an = sign if it exists */
|
if (*param == '=')
|
if (*param == '=')
|
{
|
{
|
param++;
|
param++;
|
while (*param && isspace (*param))
|
while (*param && isspace (*param))
|
param++;
|
param++;
|
}
|
}
|
|
|
switch (cur_param->type)
|
switch (cur_param->type)
|
{
|
{
|
case paramt_int:
|
case paramt_int:
|
val.int_val = strtol (param, NULL, 0);
|
val.int_val = strtol (param, NULL, 0);
|
break;
|
break;
|
case paramt_longlong:
|
case paramt_longlong:
|
val.longlong_val = strtoll (param, NULL, 0);
|
val.longlong_val = strtoll (param, NULL, 0);
|
break;
|
break;
|
case paramt_addr:
|
case paramt_addr:
|
val.addr_val = strtoul (param, NULL, 0);
|
val.addr_val = strtoul (param, NULL, 0);
|
break;
|
break;
|
case paramt_str:
|
case paramt_str:
|
if (*param != '"')
|
if (*param != '"')
|
{
|
{
|
fprintf (stderr,
|
fprintf (stderr,
|
"Warning: String value for parameter expected: ignored\n");
|
"Warning: String value for parameter expected: ignored\n");
|
return;
|
return;
|
}
|
}
|
|
|
param++;
|
param++;
|
end_p = param;
|
end_p = param;
|
while (*end_p && (*end_p != '"'))
|
while (*end_p && (*end_p != '"'))
|
end_p++;
|
end_p++;
|
*end_p = '\0';
|
*end_p = '\0';
|
val.str_val = param;
|
val.str_val = param;
|
break;
|
break;
|
case paramt_word:
|
case paramt_word:
|
end_p = param;
|
end_p = param;
|
while (*end_p && !isspace (*end_p))
|
while (*end_p && !isspace (*end_p))
|
end_p++;
|
end_p++;
|
*end_p = '\0';
|
*end_p = '\0';
|
val.str_val = param;
|
val.str_val = param;
|
break;
|
break;
|
case paramt_none:
|
case paramt_none:
|
break;
|
break;
|
}
|
}
|
|
|
cur_param->func (val, cur_section->dat);
|
cur_param->func (val, cur_section->dat);
|
}
|
}
|
|
|
/* Read environment from a script file. Does not fail - assumes default configuration instead.
|
/* Read environment from a script file. Does not fail - assumes default configuration instead.
|
The syntax of script file is:
|
The syntax of script file is:
|
param = value
|
param = value
|
section x
|
section x
|
data
|
data
|
param = value
|
param = value
|
end
|
end
|
|
|
Example:
|
Example:
|
section mc
|
section mc
|
memory_table_file = sim.mem
|
memory_table_file = sim.mem
|
enable = 1
|
enable = 1
|
POC = 0x47892344
|
POC = 0x47892344
|
end
|
end
|
|
|
*/
|
*/
|
|
|
static void
|
static void
|
read_script_file (const char *filename)
|
read_script_file (const char *filename)
|
{
|
{
|
FILE *f;
|
FILE *f;
|
char *home = getenv ("HOME");
|
char *home = getenv ("HOME");
|
char ctmp[STR_SIZE];
|
char ctmp[STR_SIZE];
|
int local = 1;
|
int local = 1;
|
cur_section = NULL;
|
cur_section = NULL;
|
|
|
sprintf (ctmp, "%s/.or1k/%s", home, filename);
|
sprintf (ctmp, "%s/.or1k/%s", home, filename);
|
if ((f = fopen (filename, "rt")) || (home && (f = fopen (ctmp, "rt"))))
|
if ((f = fopen (filename, "rt")) || (home && (f = fopen (ctmp, "rt"))))
|
{
|
{
|
if (config.sim.verbose)
|
if (config.sim.verbose)
|
PRINTF ("Reading script file from '%s'...\n",
|
PRINTF ("Reading script file from '%s'...\n",
|
local ? filename : ctmp);
|
local ? filename : ctmp);
|
|
|
while (!feof (f))
|
while (!feof (f))
|
{
|
{
|
char param[STR_SIZE];
|
char param[STR_SIZE];
|
if (fscanf (f, "%s ", param) != 1)
|
if (fscanf (f, "%s ", param) != 1)
|
break;
|
break;
|
/* Is this a section? */
|
/* Is this a section? */
|
if (strcmp (param, "section") == 0)
|
if (strcmp (param, "section") == 0)
|
{
|
{
|
struct config_section *cur;
|
struct config_section *cur;
|
cur_section = NULL;
|
cur_section = NULL;
|
if (fscanf (f, "%s\n", param) != 1)
|
if (fscanf (f, "%s\n", param) != 1)
|
{
|
{
|
fprintf (stderr, "%s: ERROR: Section name required.\n",
|
fprintf (stderr, "%s: ERROR: Section name required.\n",
|
local ? filename : ctmp);
|
local ? filename : ctmp);
|
exit (1);
|
exit (1);
|
}
|
}
|
for (cur = sections; cur; cur = cur->next)
|
for (cur = sections; cur; cur = cur->next)
|
if (strcmp (cur->name, param) == 0)
|
if (strcmp (cur->name, param) == 0)
|
{
|
{
|
cur_section = cur;
|
cur_section = cur;
|
break;
|
break;
|
}
|
}
|
if (!cur)
|
if (!cur)
|
{
|
{
|
fprintf (stderr,
|
fprintf (stderr,
|
"Warning: Unknown config section: %s; ignoring.\n",
|
"Warning: Unknown config section: %s; ignoring.\n",
|
param);
|
param);
|
/* just skip section */
|
/* just skip section */
|
while (fscanf (f, "%s\n", param) == 1
|
while (fscanf (f, "%s\n", param) == 1
|
&& strcmp (param, "end"));
|
&& strcmp (param, "end"));
|
}
|
}
|
else
|
else
|
{
|
{
|
cur->dat = NULL;
|
cur->dat = NULL;
|
if (cur->sec_start)
|
if (cur->sec_start)
|
cur->dat = cur->sec_start ();
|
cur->dat = cur->sec_start ();
|
}
|
}
|
}
|
}
|
else if (strcmp (param, "end") == 0)
|
else if (strcmp (param, "end") == 0)
|
{
|
{
|
if (cur_section->sec_end)
|
if (cur_section->sec_end)
|
cur_section->sec_end (cur_section->dat);
|
cur_section->sec_end (cur_section->dat);
|
cur_section = NULL;
|
cur_section = NULL;
|
}
|
}
|
else if (strncmp (param, "/*", 2) == 0)
|
else if (strncmp (param, "/*", 2) == 0)
|
{
|
{
|
char c0 = 0, c1 = 0;
|
char c0 = 0, c1 = 0;
|
while (c0 != '*' || c1 != '/')
|
while (c0 != '*' || c1 != '/')
|
{
|
{
|
c0 = c1;
|
c0 = c1;
|
c1 = fgetc (f);
|
c1 = fgetc (f);
|
if (feof (f))
|
if (feof (f))
|
{
|
{
|
fprintf (stderr, "%s: ERROR: Comment reached EOF.\n",
|
fprintf (stderr, "%s: ERROR: Comment reached EOF.\n",
|
local ? filename : ctmp);
|
local ? filename : ctmp);
|
exit (1);
|
exit (1);
|
}
|
}
|
}
|
}
|
}
|
}
|
else
|
else
|
{
|
{
|
struct config_param *cur_param = NULL;
|
struct config_param *cur_param = NULL;
|
char *cur_p;
|
char *cur_p;
|
/* If we have a corrupt file, this could be encountered outside
|
/* If we have a corrupt file, this could be encountered outside
|
a section. So make sure cur_section is defined. */
|
a section. So make sure cur_section is defined. */
|
if (cur_section)
|
if (cur_section)
|
{
|
{
|
for (cur_param = cur_section->params; cur_param;
|
for (cur_param = cur_section->params; cur_param;
|
cur_param = cur_param->next)
|
cur_param = cur_param->next)
|
{
|
{
|
if (strcmp (cur_param->name, param) == 0)
|
if (strcmp (cur_param->name, param) == 0)
|
{
|
{
|
break;
|
break;
|
}
|
}
|
}
|
}
|
}
|
}
|
if (!cur_param)
|
if (!cur_param)
|
{
|
{
|
fprintf (stderr, "Warning: Invalid parameter: %s; ignored\n",
|
fprintf (stderr, "Warning: Invalid parameter: %s; ignored\n",
|
param);
|
param);
|
while (fgetc (f) != '\n' || feof (f));
|
while (fgetc (f) != '\n' || feof (f));
|
continue;
|
continue;
|
}
|
}
|
|
|
if (cur_param->type == paramt_none)
|
if (cur_param->type == paramt_none)
|
continue;
|
continue;
|
|
|
/* Parse parameter value */
|
/* Parse parameter value */
|
cur_p = fgets (param, STR_SIZE, f);
|
cur_p = fgets (param, STR_SIZE, f);
|
|
|
while (*cur_p && isspace (*cur_p))
|
while (*cur_p && isspace (*cur_p))
|
cur_p++;
|
cur_p++;
|
|
|
switch_param (cur_p, cur_param);
|
switch_param (cur_p, cur_param);
|
}
|
}
|
}
|
}
|
fclose (f);
|
fclose (f);
|
}
|
}
|
else if (config.sim.verbose)
|
else if (config.sim.verbose)
|
fprintf (stderr,
|
fprintf (stderr,
|
"Warning: Cannot read script file from '%s' of '%s'.\n",
|
"Warning: Cannot read script file from '%s' of '%s'.\n",
|
filename, ctmp);
|
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;
|
struct config_param *cur_param;
|
struct config_param *cur_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 = NULL;
|
for (cur = sections; cur; cur = cur->next)
|
for (cur = sections; cur; cur = cur->next)
|
if (strcmp (cur->name, argv[1]) == 0)
|
if (strcmp (cur->name, argv[1]) == 0)
|
{
|
{
|
cur_section = cur;
|
cur_section = cur;
|
break;
|
break;
|
}
|
}
|
|
|
if (!cur_section)
|
if (!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 (cur_param = cur->params; cur_param; cur_param = cur_param->next)
|
if (strcmp (cur_param->name, argv[2]) == 0)
|
if (strcmp (cur_param->name, argv[2]) == 0)
|
{
|
{
|
break;
|
break;
|
}
|
}
|
if (!cur_param)
|
if (!cur_param)
|
return 2;
|
return 2;
|
|
|
/* Parse parameter value */
|
/* Parse parameter value */
|
if (cur_param->type)
|
if (cur_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);
|
switch_param (argv[3], cur_param);
|
}
|
}
|
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 *cur_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 = sections; cur; cur = cur->next)
|
PRINTF ("%s ", cur->name);
|
PRINTF ("%s ", cur->name);
|
PRINTF ("\n");
|
PRINTF ("\n");
|
break;
|
break;
|
case 2:
|
case 2:
|
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 (cur_param = cur_section->params; cur_param;
|
cur_param = cur_param->next)
|
cur_param = cur_param->next)
|
PRINTF ("%s ", cur_param->name);
|
PRINTF ("%s ", cur_param->name);
|
PRINTF ("\n");
|
PRINTF ("\n");
|
break;
|
break;
|
case 3:
|
case 3:
|
PRINTF ("Invalid parameters specified.\n");
|
PRINTF ("Invalid parameters specified.\n");
|
break;
|
break;
|
}
|
}
|
}
|
}
|
|
|