Move main control from C++ into Python.
User script now invokes initialization and simulation loop after building configuration. These functions are exported from C++ to Python using SWIG. SConstruct: Set up SWIG builder & scanner. Set up symlinking of source files into build directory (by not disabling the default behavior). configs/test/test.py: Rewrite to use new script-driven interface. Include a sample option. src/SConscript: Set up symlinking of source files into build directory (by not disabling the default behavior). Add SWIG-generated main_wrap.cc to source list. src/arch/SConscript: Set up symlinking of source files into build directory (by not disabling the default behavior). src/arch/alpha/ev5.cc: src/arch/alpha/isa/decoder.isa: src/cpu/o3/alpha_cpu_impl.hh: src/cpu/trace/opt_cpu.cc: src/cpu/trace/trace_cpu.cc: src/sim/pseudo_inst.cc: src/sim/root.cc: src/sim/serialize.cc: src/sim/syscall_emul.cc: SimExit() is now exitSimLoop(). src/cpu/base.cc: SimExitEvent is now SimLoopExitEvent src/python/SConscript: Add SWIG build command for main.i. Use python/m5 in build dir as source for zip archive... easy now with file duplication enabled. src/python/m5/__init__.py: - Move copyright notice back to C++ so we can print it right away, even for interactive sessions. - Get rid of argument parsing code; just provide default option descriptors for user script to call optparse with. - Don't clutter m5 namespace by sucking in all of m5.config and m5.objects. - Move instantiate() function here from config.py. src/python/m5/config.py: - Move instantiate() function to __init__.py. - Param.Foo deferred type lookups must use m5.objects namespace now (not m5). src/python/m5/objects/AlphaConsole.py: src/python/m5/objects/AlphaFullCPU.py: src/python/m5/objects/AlphaTLB.py: src/python/m5/objects/BadDevice.py: src/python/m5/objects/BaseCPU.py: src/python/m5/objects/BaseCache.py: src/python/m5/objects/Bridge.py: src/python/m5/objects/Bus.py: src/python/m5/objects/CoherenceProtocol.py: src/python/m5/objects/Device.py: src/python/m5/objects/DiskImage.py: src/python/m5/objects/Ethernet.py: src/python/m5/objects/Ide.py: src/python/m5/objects/IntrControl.py: src/python/m5/objects/MemObject.py: src/python/m5/objects/MemTest.py: src/python/m5/objects/Pci.py: src/python/m5/objects/PhysicalMemory.py: src/python/m5/objects/Platform.py: src/python/m5/objects/Process.py: src/python/m5/objects/Repl.py: src/python/m5/objects/Root.py: src/python/m5/objects/SimConsole.py: src/python/m5/objects/SimpleDisk.py: src/python/m5/objects/System.py: src/python/m5/objects/Tsunami.py: src/python/m5/objects/Uart.py: Fix up imports (m5 namespace no longer includes m5.config). src/sim/eventq.cc: src/sim/eventq.hh: Support for Python-called simulate() function: - Use IsExitEvent flag to signal events that want to exit the simulation loop gracefully (instead of calling exit() to terminate the process). - Modify interface to hand exit event object back to caller so it can be inspected for cause. src/sim/host.hh: Add MaxTick constant. src/sim/main.cc: Move copyright notice back to C++ so we can print it right away, even for interactive sessions. Use PYTHONPATH environment var to set module path (instead of clunky code injection method). Move main control from here into Python: - Separate initialization code and simulation loop into separate functions callable from Python. - Make Python interpreter invocation more pure (more like directly invoking interpreter). Add -i and -p flags (only options on binary itself; other options processed by Python). Import readline package when using interactive mode. src/sim/sim_events.cc: SimExitEvent is now SimLoopExitEvent, and uses IsSimExit flag to terminate loop (instead of exiting simulator process). src/sim/sim_events.hh: SimExitEvent is now SimLoopExitEvent, and uses IsSimExit flag to terminate loop (instead of exiting simulator process). Get rid of a few unused constructors. src/sim/sim_exit.hh: SimExit() is now exitSimLoop(). Get rid of unused functions. Add comments. --HG-- extra : convert_revision : 280b0d671516b25545a6f24cefa64a68319ff3d4
This commit is contained in:
parent
5802c46c3b
commit
29e34a739b
51 changed files with 453 additions and 327 deletions
21
SConstruct
21
SConstruct
|
@ -158,6 +158,12 @@ env = Environment(ENV = os.environ, # inherit user's environment vars
|
||||||
|
|
||||||
env.SConsignFile("sconsign")
|
env.SConsignFile("sconsign")
|
||||||
|
|
||||||
|
# Default duplicate option is to use hard links, but this messes up
|
||||||
|
# when you use emacs to edit a file in the target dir, as emacs moves
|
||||||
|
# file to file~ then copies to file, breaking the link. Symbolic
|
||||||
|
# (soft) links work better.
|
||||||
|
env.SetOption('duplicate', 'soft-copy')
|
||||||
|
|
||||||
# I waffle on this setting... it does avoid a few painful but
|
# I waffle on this setting... it does avoid a few painful but
|
||||||
# unnecessary builds, but it also seems to make trivial builds take
|
# unnecessary builds, but it also seems to make trivial builds take
|
||||||
# noticeably longer.
|
# noticeably longer.
|
||||||
|
@ -193,6 +199,19 @@ env.Append(LIBS = py_version_name)
|
||||||
if sys.exec_prefix != '/usr':
|
if sys.exec_prefix != '/usr':
|
||||||
env.Append(LIBPATH = os.path.join(sys.exec_prefix, 'lib'))
|
env.Append(LIBPATH = os.path.join(sys.exec_prefix, 'lib'))
|
||||||
|
|
||||||
|
# Set up SWIG flags & scanner
|
||||||
|
|
||||||
|
env.Append(SWIGFLAGS=Split('-c++ -python -modern $_CPPINCFLAGS'))
|
||||||
|
|
||||||
|
import SCons.Scanner
|
||||||
|
|
||||||
|
swig_inc_re = '^[ \t]*[%,#][ \t]*(?:include|import)[ \t]*(<|")([^>"]+)(>|")'
|
||||||
|
|
||||||
|
swig_scanner = SCons.Scanner.ClassicCPP("SwigScan", ".i", "CPPPATH",
|
||||||
|
swig_inc_re)
|
||||||
|
|
||||||
|
env.Append(SCANNERS = swig_scanner)
|
||||||
|
|
||||||
# Other default libraries
|
# Other default libraries
|
||||||
env.Append(LIBS=['z'])
|
env.Append(LIBS=['z'])
|
||||||
|
|
||||||
|
@ -468,7 +487,7 @@ for build_path in build_paths:
|
||||||
# to the configured options. It returns a list of environments,
|
# to the configured options. It returns a list of environments,
|
||||||
# one for each variant build (debug, opt, etc.)
|
# one for each variant build (debug, opt, etc.)
|
||||||
envList = SConscript('src/SConscript', build_dir = build_path,
|
envList = SConscript('src/SConscript', build_dir = build_path,
|
||||||
exports = 'env', duplicate = False)
|
exports = 'env')
|
||||||
|
|
||||||
# Set up the regression tests for each build.
|
# Set up the regression tests for each build.
|
||||||
# for e in envList:
|
# for e in envList:
|
||||||
|
|
|
@ -1,12 +1,40 @@
|
||||||
from m5 import *
|
import os, optparse, sys
|
||||||
|
import m5
|
||||||
|
from m5.objects import *
|
||||||
|
|
||||||
class HelloWorld(AlphaLiveProcess):
|
parser = optparse.OptionParser(option_list=m5.standardOptions)
|
||||||
executable = '../configs/test/hello'
|
|
||||||
cmd = 'hello'
|
parser.add_option("-t", "--timing", action="store_true")
|
||||||
|
|
||||||
|
(options, args) = parser.parse_args()
|
||||||
|
|
||||||
|
if args:
|
||||||
|
print "Error: script doesn't take any positional arguments"
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
this_dir = os.path.dirname(__file__)
|
||||||
|
|
||||||
|
process = AlphaLiveProcess()
|
||||||
|
process.executable = os.path.join(this_dir, 'hello')
|
||||||
|
process.cmd = 'hello'
|
||||||
|
|
||||||
magicbus = Bus()
|
magicbus = Bus()
|
||||||
mem = PhysicalMemory()
|
mem = PhysicalMemory()
|
||||||
cpu = AtomicSimpleCPU(workload=HelloWorld(), mem=magicbus)
|
|
||||||
|
if options.timing:
|
||||||
|
cpu = TimingSimpleCPU()
|
||||||
|
else:
|
||||||
|
cpu = AtomicSimpleCPU()
|
||||||
|
cpu.workload = process
|
||||||
|
cpu.mem = magicbus
|
||||||
|
|
||||||
system = System(physmem = mem, cpu = cpu)
|
system = System(physmem = mem, cpu = cpu)
|
||||||
system.c1 = Connector(side_a = mem, side_b = magicbus)
|
system.c1 = Connector(side_a = mem, side_b = magicbus)
|
||||||
root = Root(system = system)
|
root = Root(system = system)
|
||||||
|
|
||||||
|
m5.instantiate(root)
|
||||||
|
|
||||||
|
exit_event = m5.simulate()
|
||||||
|
|
||||||
|
print 'Exiting @', m5.curTick(), 'because', exit_event.getCause()
|
||||||
|
|
||||||
|
|
|
@ -104,12 +104,12 @@ base_sources = Split('''
|
||||||
sim/eventq.cc
|
sim/eventq.cc
|
||||||
sim/faults.cc
|
sim/faults.cc
|
||||||
sim/main.cc
|
sim/main.cc
|
||||||
|
python/swig/main_wrap.cc
|
||||||
sim/param.cc
|
sim/param.cc
|
||||||
sim/profile.cc
|
sim/profile.cc
|
||||||
sim/root.cc
|
sim/root.cc
|
||||||
sim/serialize.cc
|
sim/serialize.cc
|
||||||
sim/sim_events.cc
|
sim/sim_events.cc
|
||||||
sim/sim_exit.cc
|
|
||||||
sim/sim_object.cc
|
sim/sim_object.cc
|
||||||
sim/startup.cc
|
sim/startup.cc
|
||||||
sim/stat_context.cc
|
sim/stat_context.cc
|
||||||
|
@ -281,14 +281,18 @@ memtest_sources = Split('''
|
||||||
cpu/memtest/memtest.cc
|
cpu/memtest/memtest.cc
|
||||||
''')
|
''')
|
||||||
|
|
||||||
|
# Include file paths are rooted in this directory. SCons will
|
||||||
|
# automatically expand '.' to refer to both the source directory and
|
||||||
|
# the corresponding build directory to pick up generated include
|
||||||
|
# files.
|
||||||
|
env.Append(CPPPATH=Dir('.'))
|
||||||
|
|
||||||
# Add a flag defining what THE_ISA should be for all compilation
|
# Add a flag defining what THE_ISA should be for all compilation
|
||||||
env.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())])
|
env.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())])
|
||||||
|
|
||||||
arch_sources = SConscript('arch/SConscript',
|
arch_sources = SConscript('arch/SConscript', exports = 'env')
|
||||||
exports = 'env', duplicate = False)
|
|
||||||
|
|
||||||
cpu_sources = SConscript('cpu/SConscript',
|
cpu_sources = SConscript('cpu/SConscript', exports = 'env')
|
||||||
exports = 'env', duplicate = False)
|
|
||||||
|
|
||||||
# This is outside of cpu/SConscript since the source directory isn't
|
# This is outside of cpu/SConscript since the source directory isn't
|
||||||
# underneath 'cpu'.
|
# underneath 'cpu'.
|
||||||
|
@ -323,7 +327,7 @@ env.Command(Split('base/traceflags.hh base/traceflags.cc'),
|
||||||
'base/traceflags.py',
|
'base/traceflags.py',
|
||||||
'python $SOURCE $TARGET.base')
|
'python $SOURCE $TARGET.base')
|
||||||
|
|
||||||
SConscript('python/SConscript', exports = ['env'], duplicate=0)
|
SConscript('python/SConscript', exports = ['env'])
|
||||||
|
|
||||||
# This function adds the specified sources to the given build
|
# This function adds the specified sources to the given build
|
||||||
# environment, and returns a list of all the corresponding SCons
|
# environment, and returns a list of all the corresponding SCons
|
||||||
|
@ -346,12 +350,6 @@ def make_objs(sources, env):
|
||||||
#
|
#
|
||||||
###################################################
|
###################################################
|
||||||
|
|
||||||
# Include file paths are rooted in this directory. SCons will
|
|
||||||
# automatically expand '.' to refer to both the source directory and
|
|
||||||
# the corresponding build directory to pick up generated include
|
|
||||||
# files.
|
|
||||||
env.Append(CPPPATH='.')
|
|
||||||
|
|
||||||
# List of constructed environments to pass back to SConstruct
|
# List of constructed environments to pass back to SConstruct
|
||||||
envList = []
|
envList = []
|
||||||
|
|
||||||
|
|
|
@ -146,7 +146,6 @@ env.Append(BUILDERS = { 'ISADesc' : isa_desc_builder })
|
||||||
isa = env['TARGET_ISA'] # someday this may be a list of ISAs
|
isa = env['TARGET_ISA'] # someday this may be a list of ISAs
|
||||||
|
|
||||||
# Let the target architecture define what additional sources it needs
|
# Let the target architecture define what additional sources it needs
|
||||||
sources += SConscript(os.path.join(isa, 'SConscript'),
|
sources += SConscript(os.path.join(isa, 'SConscript'), exports = 'env')
|
||||||
exports = 'env', duplicate = False)
|
|
||||||
|
|
||||||
Return('sources')
|
Return('sources')
|
||||||
|
|
|
@ -564,7 +564,7 @@ CPUExecContext::simPalCheck(int palFunc)
|
||||||
case PAL::halt:
|
case PAL::halt:
|
||||||
halt();
|
halt();
|
||||||
if (--System::numSystemsRunning == 0)
|
if (--System::numSystemsRunning == 0)
|
||||||
new SimExitEvent("all cpus halted");
|
exitSimLoop("all cpus halted");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PAL::bpt:
|
case PAL::bpt:
|
||||||
|
|
|
@ -697,7 +697,7 @@ decode OPCODE default Unknown::unknown() {
|
||||||
0x00: decode PALFUNC {
|
0x00: decode PALFUNC {
|
||||||
format EmulatedCallPal {
|
format EmulatedCallPal {
|
||||||
0x00: halt ({{
|
0x00: halt ({{
|
||||||
SimExit(curTick, "halt instruction encountered");
|
exitSimLoop(curTick, "halt instruction encountered");
|
||||||
}}, IsNonSpeculative);
|
}}, IsNonSpeculative);
|
||||||
0x83: callsys({{
|
0x83: callsys({{
|
||||||
xc->syscall(R0);
|
xc->syscall(R0);
|
||||||
|
|
|
@ -93,7 +93,7 @@ BaseCPU::BaseCPU(Params *p)
|
||||||
//
|
//
|
||||||
if (p->max_insts_any_thread != 0)
|
if (p->max_insts_any_thread != 0)
|
||||||
for (int i = 0; i < number_of_threads; ++i)
|
for (int i = 0; i < number_of_threads; ++i)
|
||||||
new SimExitEvent(comInstEventQueue[i], p->max_insts_any_thread,
|
new SimLoopExitEvent(comInstEventQueue[i], p->max_insts_any_thread,
|
||||||
"a thread reached the max instruction count");
|
"a thread reached the max instruction count");
|
||||||
|
|
||||||
if (p->max_insts_all_threads != 0) {
|
if (p->max_insts_all_threads != 0) {
|
||||||
|
@ -118,7 +118,7 @@ BaseCPU::BaseCPU(Params *p)
|
||||||
//
|
//
|
||||||
if (p->max_loads_any_thread != 0)
|
if (p->max_loads_any_thread != 0)
|
||||||
for (int i = 0; i < number_of_threads; ++i)
|
for (int i = 0; i < number_of_threads; ++i)
|
||||||
new SimExitEvent(comLoadEventQueue[i], p->max_loads_any_thread,
|
new SimLoopExitEvent(comLoadEventQueue[i], p->max_loads_any_thread,
|
||||||
"a thread reached the max load count");
|
"a thread reached the max load count");
|
||||||
|
|
||||||
if (p->max_loads_all_threads != 0) {
|
if (p->max_loads_all_threads != 0) {
|
||||||
|
|
|
@ -292,7 +292,7 @@ AlphaFullCPU<Impl>::simPalCheck(int palFunc)
|
||||||
case PAL::halt:
|
case PAL::halt:
|
||||||
halt();
|
halt();
|
||||||
if (--System::numSystemsRunning == 0)
|
if (--System::numSystemsRunning == 0)
|
||||||
new SimExitEvent("all cpus halted");
|
exitSimLoop("all cpus halted");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PAL::bpt:
|
case PAL::bpt:
|
||||||
|
|
|
@ -176,7 +176,7 @@ OptCPU::tick()
|
||||||
fprintf(stderr,"sys.cpu.misses %d #opt cache misses\n",misses);
|
fprintf(stderr,"sys.cpu.misses %d #opt cache misses\n",misses);
|
||||||
fprintf(stderr,"sys.cpu.hits %d #opt cache hits\n", hits);
|
fprintf(stderr,"sys.cpu.hits %d #opt cache hits\n", hits);
|
||||||
fprintf(stderr,"sys.cpu.accesses %d #opt cache acceses\n", references);
|
fprintf(stderr,"sys.cpu.accesses %d #opt cache acceses\n", references);
|
||||||
new SimExitEvent("Finshed Memory Trace");
|
exitSimLoop("end of memory trace reached");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -108,7 +108,7 @@ TraceCPU::tick()
|
||||||
if (!nextReq) {
|
if (!nextReq) {
|
||||||
// No more requests to send. Finish trailing events and exit.
|
// No more requests to send. Finish trailing events and exit.
|
||||||
if (mainEventQueue.empty()) {
|
if (mainEventQueue.empty()) {
|
||||||
new SimExitEvent("Finshed Memory Trace");
|
exitSimLoop("end of memory trace reached");
|
||||||
} else {
|
} else {
|
||||||
tickEvent.schedule(mainEventQueue.nextEventTime() + cycles(1));
|
tickEvent.schedule(mainEventQueue.nextEventTime() + cycles(1));
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,11 +38,8 @@ def join(*args):
|
||||||
|
|
||||||
Import('env')
|
Import('env')
|
||||||
|
|
||||||
# This SConscript is in charge of collecting .py files and generating a zip archive that is appended to the m5 binary.
|
# This SConscript is in charge of collecting .py files and generating
|
||||||
|
# a zip archive that is appended to the m5 binary.
|
||||||
# Copy .py source files here (relative to src/python in the build
|
|
||||||
# directory).
|
|
||||||
pyzip_root = 'zip'
|
|
||||||
|
|
||||||
# List of files & directories to include in the zip file. To include
|
# List of files & directories to include in the zip file. To include
|
||||||
# a package, list only the root directory of the package, not any
|
# a package, list only the root directory of the package, not any
|
||||||
|
@ -58,7 +55,7 @@ pyzip_dep_files = []
|
||||||
# Add the specified package to the zip archive. Adds the directory to
|
# Add the specified package to the zip archive. Adds the directory to
|
||||||
# pyzip_files and all included .py files to pyzip_dep_files.
|
# pyzip_files and all included .py files to pyzip_dep_files.
|
||||||
def addPkg(pkgdir):
|
def addPkg(pkgdir):
|
||||||
pyzip_files.append(join(pyzip_root, pkgdir))
|
pyzip_files.append(pkgdir)
|
||||||
origdir = os.getcwd()
|
origdir = os.getcwd()
|
||||||
srcdir = join(Dir('.').srcnode().abspath, pkgdir)
|
srcdir = join(Dir('.').srcnode().abspath, pkgdir)
|
||||||
os.chdir(srcdir)
|
os.chdir(srcdir)
|
||||||
|
@ -70,10 +67,7 @@ def addPkg(pkgdir):
|
||||||
|
|
||||||
for f in files:
|
for f in files:
|
||||||
if f.endswith('.py'):
|
if f.endswith('.py'):
|
||||||
source = join(pkgdir, path, f)
|
pyzip_dep_files.append(join(pkgdir, path, f))
|
||||||
target = join(pyzip_root, source)
|
|
||||||
pyzip_dep_files.append(target)
|
|
||||||
env.CopyFile(target, source)
|
|
||||||
|
|
||||||
os.chdir(origdir)
|
os.chdir(origdir)
|
||||||
|
|
||||||
|
@ -81,19 +75,25 @@ def addPkg(pkgdir):
|
||||||
# build_env flags.
|
# build_env flags.
|
||||||
def MakeDefinesPyFile(target, source, env):
|
def MakeDefinesPyFile(target, source, env):
|
||||||
f = file(str(target[0]), 'w')
|
f = file(str(target[0]), 'w')
|
||||||
print >>f, "import __main__"
|
print >>f, "m5_build_env = ",
|
||||||
print >>f, "__main__.m5_build_env = ",
|
|
||||||
print >>f, source[0]
|
print >>f, source[0]
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
optionDict = dict([(opt, env[opt]) for opt in env.ExportOptions])
|
optionDict = dict([(opt, env[opt]) for opt in env.ExportOptions])
|
||||||
env.Command('defines.py', Value(optionDict), MakeDefinesPyFile)
|
env.Command('m5/defines.py', Value(optionDict), MakeDefinesPyFile)
|
||||||
|
|
||||||
# Now specify the packages & files for the zip archive.
|
# Now specify the packages & files for the zip archive.
|
||||||
addPkg('m5')
|
addPkg('m5')
|
||||||
pyzip_files.append('defines.py')
|
pyzip_files.append('m5/defines.py')
|
||||||
pyzip_files.append(join(env['ROOT'], 'util/pbs/jobfile.py'))
|
pyzip_files.append(join(env['ROOT'], 'util/pbs/jobfile.py'))
|
||||||
|
|
||||||
|
env.Command(['swig/main_wrap.cc', 'm5/main.py'],
|
||||||
|
'swig/main.i',
|
||||||
|
'$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} '
|
||||||
|
'-o ${TARGETS[0]} $SOURCES')
|
||||||
|
|
||||||
|
pyzip_dep_files.append('m5/main.py')
|
||||||
|
|
||||||
# Action function to build the zip archive. Uses the PyZipFile module
|
# Action function to build the zip archive. Uses the PyZipFile module
|
||||||
# included in the standard Python library.
|
# included in the standard Python library.
|
||||||
def buildPyZip(target, source, env):
|
def buildPyZip(target, source, env):
|
||||||
|
|
|
@ -27,69 +27,26 @@
|
||||||
# Authors: Nathan Binkert
|
# Authors: Nathan Binkert
|
||||||
# Steve Reinhardt
|
# Steve Reinhardt
|
||||||
|
|
||||||
import sys, os, time
|
import sys, os, time, atexit, optparse
|
||||||
|
|
||||||
import __main__
|
# import the SWIG-wrapped main C++ functions
|
||||||
|
import main
|
||||||
|
# import a few SWIG-wrapped items (those that are likely to be used
|
||||||
|
# directly by user scripts) completely into this module for
|
||||||
|
# convenience
|
||||||
|
from main import simulate, SimLoopExitEvent
|
||||||
|
|
||||||
briefCopyright = '''
|
# import the m5 compile options
|
||||||
Copyright (c) 2001-2006
|
import defines
|
||||||
The Regents of The University of Michigan
|
|
||||||
All Rights Reserved
|
|
||||||
'''
|
|
||||||
|
|
||||||
fullCopyright = '''
|
|
||||||
Copyright (c) 2001-2006
|
|
||||||
The Regents of The University of Michigan
|
|
||||||
All Rights Reserved
|
|
||||||
|
|
||||||
Permission is granted to use, copy, create derivative works and
|
|
||||||
redistribute this software and such derivative works for any purpose,
|
|
||||||
so long as the copyright notice above, this grant of permission, and
|
|
||||||
the disclaimer below appear in all copies made; and so long as the
|
|
||||||
name of The University of Michigan is not used in any advertising or
|
|
||||||
publicity pertaining to the use or distribution of this software
|
|
||||||
without specific, written prior authorization.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE
|
|
||||||
UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND WITHOUT
|
|
||||||
WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE REGENTS OF
|
|
||||||
THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE FOR ANY DAMAGES,
|
|
||||||
INCLUDING DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
|
||||||
DAMAGES, WITH RESPECT TO ANY CLAIM ARISING OUT OF OR IN CONNECTION
|
|
||||||
WITH THE USE OF THE SOFTWARE, EVEN IF IT HAS BEEN OR IS HEREAFTER
|
|
||||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
|
||||||
'''
|
|
||||||
|
|
||||||
def sayHello(f):
|
|
||||||
print >> f, "M5 Simulator System"
|
|
||||||
print >> f, briefCopyright
|
|
||||||
print >> f, "M5 compiled on", __main__.compileDate
|
|
||||||
hostname = os.environ.get('HOSTNAME')
|
|
||||||
if not hostname:
|
|
||||||
hostname = os.environ.get('HOST')
|
|
||||||
if hostname:
|
|
||||||
print >> f, "M5 executing on", hostname
|
|
||||||
print >> f, "M5 simulation started", time.ctime()
|
|
||||||
|
|
||||||
sayHello(sys.stderr)
|
|
||||||
|
|
||||||
# define this here so we can use it right away if necessary
|
# define this here so we can use it right away if necessary
|
||||||
def panic(string):
|
def panic(string):
|
||||||
print >>sys.stderr, 'panic:', string
|
print >>sys.stderr, 'panic:', string
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
def m5execfile(f, global_dict):
|
# Prepend given directory to system module search path. We may not
|
||||||
# copy current sys.path
|
# need this anymore if we can structure our config library more like a
|
||||||
oldpath = sys.path[:]
|
# Python package.
|
||||||
# push file's directory onto front of path
|
|
||||||
sys.path.insert(0, os.path.abspath(os.path.dirname(f)))
|
|
||||||
execfile(f, global_dict)
|
|
||||||
# restore original path
|
|
||||||
sys.path = oldpath
|
|
||||||
|
|
||||||
# Prepend given directory to system module search path.
|
|
||||||
def AddToPath(path):
|
def AddToPath(path):
|
||||||
# if it's a relative path and we know what directory the current
|
# if it's a relative path and we know what directory the current
|
||||||
# python script is in, make the path relative to that directory.
|
# python script is in, make the path relative to that directory.
|
||||||
|
@ -100,84 +57,58 @@ def AddToPath(path):
|
||||||
# so place the new dir right after that.
|
# so place the new dir right after that.
|
||||||
sys.path.insert(1, path)
|
sys.path.insert(1, path)
|
||||||
|
|
||||||
# find the m5 compile options: must be specified as a dict in
|
|
||||||
# __main__.m5_build_env.
|
# Callback to set trace flags. Not necessarily the best way to do
|
||||||
import __main__
|
# things in the long run (particularly if we change how these global
|
||||||
if not hasattr(__main__, 'm5_build_env'):
|
# options are handled).
|
||||||
panic("__main__ must define m5_build_env")
|
def setTraceFlags(option, opt_str, value, parser):
|
||||||
|
objects.Trace.flags = value
|
||||||
|
|
||||||
|
# Standard optparse options. Need to be explicitly included by the
|
||||||
|
# user script when it calls optparse.OptionParser().
|
||||||
|
standardOptions = [
|
||||||
|
optparse.make_option("--traceflags", type="string", action="callback",
|
||||||
|
callback=setTraceFlags)
|
||||||
|
]
|
||||||
|
|
||||||
# make a SmartDict out of the build options for our local use
|
# make a SmartDict out of the build options for our local use
|
||||||
import smartdict
|
import smartdict
|
||||||
build_env = smartdict.SmartDict()
|
build_env = smartdict.SmartDict()
|
||||||
build_env.update(__main__.m5_build_env)
|
build_env.update(defines.m5_build_env)
|
||||||
|
|
||||||
# make a SmartDict out of the OS environment too
|
# make a SmartDict out of the OS environment too
|
||||||
env = smartdict.SmartDict()
|
env = smartdict.SmartDict()
|
||||||
env.update(os.environ)
|
env.update(os.environ)
|
||||||
|
|
||||||
# import the main m5 config code
|
# The final hook to generate .ini files. Called from the user script
|
||||||
from config import *
|
# once the config is built.
|
||||||
|
def instantiate(root):
|
||||||
# import the built-in object definitions
|
config.ticks_per_sec = float(root.clock.frequency)
|
||||||
from objects import *
|
# ugly temporary hack to get output to config.ini
|
||||||
|
|
||||||
|
|
||||||
args_left = sys.argv[1:]
|
|
||||||
configfile_found = False
|
|
||||||
|
|
||||||
while args_left:
|
|
||||||
arg = args_left.pop(0)
|
|
||||||
if arg.startswith('--'):
|
|
||||||
# if arg starts with '--', parse as a special python option
|
|
||||||
# of the format --<python var>=<string value>
|
|
||||||
try:
|
|
||||||
(var, val) = arg.split('=', 1)
|
|
||||||
except ValueError:
|
|
||||||
panic("Could not parse configuration argument '%s'\n"
|
|
||||||
"Expecting --<variable>=<value>\n" % arg);
|
|
||||||
eval("%s = %s" % (var, repr(val)))
|
|
||||||
elif arg.startswith('-'):
|
|
||||||
# if the arg starts with '-', it should be a simulator option
|
|
||||||
# with a format similar to getopt.
|
|
||||||
optchar = arg[1]
|
|
||||||
if len(arg) > 2:
|
|
||||||
args_left.insert(0, arg[2:])
|
|
||||||
if optchar == 'd':
|
|
||||||
outdir = args_left.pop(0)
|
|
||||||
elif optchar == 'h':
|
|
||||||
showBriefHelp(sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
elif optchar == 'E':
|
|
||||||
env_str = args_left.pop(0)
|
|
||||||
split_result = env_str.split('=', 1)
|
|
||||||
var = split_result[0]
|
|
||||||
if len(split_result == 2):
|
|
||||||
val = split_result[1]
|
|
||||||
else:
|
|
||||||
val = True
|
|
||||||
env[var] = val
|
|
||||||
elif optchar == 'I':
|
|
||||||
AddToPath(args_left.pop(0))
|
|
||||||
elif optchar == 'P':
|
|
||||||
eval(args_left.pop(0))
|
|
||||||
else:
|
|
||||||
showBriefHelp(sys.stderr)
|
|
||||||
panic("invalid argument '%s'\n" % arg_str)
|
|
||||||
else:
|
|
||||||
# In any other case, treat the option as a configuration file
|
|
||||||
# name and load it.
|
|
||||||
if not arg.endswith('.py'):
|
|
||||||
panic("Config file '%s' must end in '.py'\n" % arg)
|
|
||||||
configfile_found = True
|
|
||||||
m5execfile(arg, globals())
|
|
||||||
|
|
||||||
|
|
||||||
if not configfile_found:
|
|
||||||
panic("no configuration file specified!")
|
|
||||||
|
|
||||||
if globals().has_key('root') and isinstance(root, Root):
|
|
||||||
sys.stdout = file('config.ini', 'w')
|
sys.stdout = file('config.ini', 'w')
|
||||||
instantiate(root)
|
root.print_ini()
|
||||||
else:
|
sys.stdout.close() # close config.ini
|
||||||
print 'Instantiation skipped: no root object found.'
|
sys.stdout = sys.__stdout__ # restore to original
|
||||||
|
main.initialize() # load config.ini into C++ and process it
|
||||||
|
noDot = True # temporary until we fix dot
|
||||||
|
if not noDot:
|
||||||
|
dot = pydot.Dot()
|
||||||
|
instance.outputDot(dot)
|
||||||
|
dot.orientation = "portrait"
|
||||||
|
dot.size = "8.5,11"
|
||||||
|
dot.ranksep="equally"
|
||||||
|
dot.rank="samerank"
|
||||||
|
dot.write("config.dot")
|
||||||
|
dot.write_ps("config.ps")
|
||||||
|
|
||||||
|
# Export curTick to user script.
|
||||||
|
def curTick():
|
||||||
|
return main.cvar.curTick
|
||||||
|
|
||||||
|
# register our C++ exit callback function with Python
|
||||||
|
atexit.register(main.doExitCleanup)
|
||||||
|
|
||||||
|
# This import allows user scripts to reference 'm5.objects.Foo' after
|
||||||
|
# just doing an 'import m5' (without an 'import m5.objects'). May not
|
||||||
|
# matter since most scripts will probably 'from m5.objects import *'.
|
||||||
|
import objects
|
||||||
|
|
|
@ -728,7 +728,7 @@ class ParamDesc(object):
|
||||||
def __getattr__(self, attr):
|
def __getattr__(self, attr):
|
||||||
if attr == 'ptype':
|
if attr == 'ptype':
|
||||||
try:
|
try:
|
||||||
ptype = eval(self.ptype_str, m5.__dict__)
|
ptype = eval(self.ptype_str, m5.objects.__dict__)
|
||||||
if not isinstance(ptype, type):
|
if not isinstance(ptype, type):
|
||||||
panic("Param qualifier is not a type: %s" % self.ptype)
|
panic("Param qualifier is not a type: %s" % self.ptype)
|
||||||
self.ptype = ptype
|
self.ptype = ptype
|
||||||
|
@ -1290,23 +1290,6 @@ AllMemory = AddrRange(0, MaxAddr)
|
||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
|
|
||||||
# The final hook to generate .ini files. Called from configuration
|
|
||||||
# script once config is built.
|
|
||||||
def instantiate(root):
|
|
||||||
global ticks_per_sec
|
|
||||||
ticks_per_sec = float(root.clock.frequency)
|
|
||||||
root.print_ini()
|
|
||||||
noDot = True # temporary until we fix dot
|
|
||||||
if not noDot:
|
|
||||||
dot = pydot.Dot()
|
|
||||||
instance.outputDot(dot)
|
|
||||||
dot.orientation = "portrait"
|
|
||||||
dot.size = "8.5,11"
|
|
||||||
dot.ranksep="equally"
|
|
||||||
dot.rank="samerank"
|
|
||||||
dot.write("config.dot")
|
|
||||||
dot.write_ps("config.ps")
|
|
||||||
|
|
||||||
# __all__ defines the list of symbols that get exported when
|
# __all__ defines the list of symbols that get exported when
|
||||||
# 'from config import *' is invoked. Try to keep this reasonably
|
# 'from config import *' is invoked. Try to keep this reasonably
|
||||||
# short to avoid polluting other namespaces.
|
# short to avoid polluting other namespaces.
|
||||||
|
@ -1322,5 +1305,5 @@ __all__ = ['SimObject', 'ParamContext', 'Param', 'VectorParam',
|
||||||
'NetworkBandwidth', 'MemoryBandwidth',
|
'NetworkBandwidth', 'MemoryBandwidth',
|
||||||
'Range', 'AddrRange', 'MaxAddr', 'MaxTick', 'AllMemory',
|
'Range', 'AddrRange', 'MaxAddr', 'MaxTick', 'AllMemory',
|
||||||
'Null', 'NULL',
|
'Null', 'NULL',
|
||||||
'NextEthernetAddr', 'instantiate']
|
'NextEthernetAddr']
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from m5 import *
|
from m5.config import *
|
||||||
from Device import BasicPioDevice
|
from Device import BasicPioDevice
|
||||||
|
|
||||||
class AlphaConsole(BasicPioDevice):
|
class AlphaConsole(BasicPioDevice):
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from m5 import *
|
from m5 import build_env
|
||||||
|
from m5.config import *
|
||||||
from BaseCPU import BaseCPU
|
from BaseCPU import BaseCPU
|
||||||
|
|
||||||
class DerivAlphaFullCPU(BaseCPU):
|
class DerivAlphaFullCPU(BaseCPU):
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from m5 import *
|
from m5.config import *
|
||||||
class AlphaTLB(SimObject):
|
class AlphaTLB(SimObject):
|
||||||
type = 'AlphaTLB'
|
type = 'AlphaTLB'
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from m5 import *
|
from m5.config import *
|
||||||
from Device import BasicPioDevice
|
from Device import BasicPioDevice
|
||||||
|
|
||||||
class BadDevice(BasicPioDevice):
|
class BadDevice(BasicPioDevice):
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
from m5 import *
|
from m5 import build_env
|
||||||
|
from m5.config import *
|
||||||
|
|
||||||
class BaseCPU(SimObject):
|
class BaseCPU(SimObject):
|
||||||
type = 'BaseCPU'
|
type = 'BaseCPU'
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from m5 import *
|
from m5.config import *
|
||||||
from BaseMem import BaseMem
|
from BaseMem import BaseMem
|
||||||
|
|
||||||
class Prefetch(Enum): vals = ['none', 'tagged', 'stride', 'ghb']
|
class Prefetch(Enum): vals = ['none', 'tagged', 'stride', 'ghb']
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from m5 import *
|
from m5.config import *
|
||||||
from MemObject import MemObject
|
from MemObject import MemObject
|
||||||
|
|
||||||
class Bridge(MemObject):
|
class Bridge(MemObject):
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from m5 import *
|
from m5.config import *
|
||||||
from MemObject import MemObject
|
from MemObject import MemObject
|
||||||
|
|
||||||
class Bus(MemObject):
|
class Bus(MemObject):
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from m5 import *
|
from m5.config import *
|
||||||
class Coherence(Enum): vals = ['uni', 'msi', 'mesi', 'mosi', 'moesi']
|
class Coherence(Enum): vals = ['uni', 'msi', 'mesi', 'mosi', 'moesi']
|
||||||
|
|
||||||
class CoherenceProtocol(SimObject):
|
class CoherenceProtocol(SimObject):
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from m5 import *
|
from m5.config import *
|
||||||
from MemObject import MemObject
|
from MemObject import MemObject
|
||||||
|
|
||||||
class PioDevice(MemObject):
|
class PioDevice(MemObject):
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from m5 import *
|
from m5.config import *
|
||||||
class DiskImage(SimObject):
|
class DiskImage(SimObject):
|
||||||
type = 'DiskImage'
|
type = 'DiskImage'
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from m5 import *
|
from m5 import build_env
|
||||||
|
from m5.config import *
|
||||||
from Device import DmaDevice
|
from Device import DmaDevice
|
||||||
from Pci import PciDevice
|
from Pci import PciDevice
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from m5 import *
|
from m5.config import *
|
||||||
from Pci import PciDevice
|
from Pci import PciDevice
|
||||||
|
|
||||||
class IdeID(Enum): vals = ['master', 'slave']
|
class IdeID(Enum): vals = ['master', 'slave']
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from m5 import *
|
from m5.config import *
|
||||||
class IntrControl(SimObject):
|
class IntrControl(SimObject):
|
||||||
type = 'IntrControl'
|
type = 'IntrControl'
|
||||||
cpu = Param.BaseCPU(Parent.any, "the cpu")
|
cpu = Param.BaseCPU(Parent.any, "the cpu")
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from m5 import *
|
from m5.config import *
|
||||||
|
|
||||||
class MemObject(SimObject):
|
class MemObject(SimObject):
|
||||||
type = 'MemObject'
|
type = 'MemObject'
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from m5 import *
|
from m5.config import *
|
||||||
class MemTest(SimObject):
|
class MemTest(SimObject):
|
||||||
type = 'MemTest'
|
type = 'MemTest'
|
||||||
cache = Param.BaseCache("L1 cache")
|
cache = Param.BaseCache("L1 cache")
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from m5 import *
|
from m5.config import *
|
||||||
from Device import BasicPioDevice, DmaDevice
|
from Device import BasicPioDevice, DmaDevice
|
||||||
|
|
||||||
class PciConfigData(SimObject):
|
class PciConfigData(SimObject):
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from m5 import *
|
from m5.config import *
|
||||||
from MemObject import *
|
from MemObject import *
|
||||||
|
|
||||||
class PhysicalMemory(MemObject):
|
class PhysicalMemory(MemObject):
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from m5 import *
|
from m5.config import *
|
||||||
class Platform(SimObject):
|
class Platform(SimObject):
|
||||||
type = 'Platform'
|
type = 'Platform'
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from m5 import *
|
from m5.config import *
|
||||||
class Process(SimObject):
|
class Process(SimObject):
|
||||||
type = 'Process'
|
type = 'Process'
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from m5 import *
|
from m5.config import *
|
||||||
class Repl(SimObject):
|
class Repl(SimObject):
|
||||||
type = 'Repl'
|
type = 'Repl'
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from m5 import *
|
from m5.config import *
|
||||||
from Serialize import Serialize
|
from Serialize import Serialize
|
||||||
from Statistics import Statistics
|
from Statistics import Statistics
|
||||||
from Trace import Trace
|
from Trace import Trace
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from m5 import *
|
from m5.config import *
|
||||||
class ConsoleListener(SimObject):
|
class ConsoleListener(SimObject):
|
||||||
type = 'ConsoleListener'
|
type = 'ConsoleListener'
|
||||||
port = Param.TcpPort(3456, "listen port")
|
port = Param.TcpPort(3456, "listen port")
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from m5 import *
|
from m5.config import *
|
||||||
class SimpleDisk(SimObject):
|
class SimpleDisk(SimObject):
|
||||||
type = 'SimpleDisk'
|
type = 'SimpleDisk'
|
||||||
disk = Param.DiskImage("Disk Image")
|
disk = Param.DiskImage("Disk Image")
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from m5 import *
|
from m5 import build_env
|
||||||
|
from m5.config import *
|
||||||
|
|
||||||
class System(SimObject):
|
class System(SimObject):
|
||||||
type = 'System'
|
type = 'System'
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from m5 import *
|
from m5.config import *
|
||||||
from Device import BasicPioDevice
|
from Device import BasicPioDevice
|
||||||
from Platform import Platform
|
from Platform import Platform
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from m5 import *
|
from m5 import build_env
|
||||||
|
from m5.config import *
|
||||||
from Device import BasicPioDevice
|
from Device import BasicPioDevice
|
||||||
|
|
||||||
class Uart(BasicPioDevice):
|
class Uart(BasicPioDevice):
|
||||||
|
|
|
@ -102,7 +102,7 @@ EventQueue::remove(Event *event)
|
||||||
prev->next = curr->next;
|
prev->next = curr->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
Event *
|
||||||
EventQueue::serviceOne()
|
EventQueue::serviceOne()
|
||||||
{
|
{
|
||||||
Event *event = head;
|
Event *event = head;
|
||||||
|
@ -110,13 +110,20 @@ EventQueue::serviceOne()
|
||||||
head = event->next;
|
head = event->next;
|
||||||
|
|
||||||
// handle action
|
// handle action
|
||||||
if (!event->squashed())
|
if (!event->squashed()) {
|
||||||
event->process();
|
event->process();
|
||||||
else
|
if (event->isExitEvent()) {
|
||||||
|
assert(!event->getFlags(Event::AutoDelete)); // would be silly
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
event->clearFlags(Event::Squashed);
|
event->clearFlags(Event::Squashed);
|
||||||
|
}
|
||||||
|
|
||||||
if (event->getFlags(Event::AutoDelete) && !event->scheduled())
|
if (event->getFlags(Event::AutoDelete) && !event->scheduled())
|
||||||
delete event;
|
delete event;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,8 @@ class Event : public Serializable, public FastAlloc
|
||||||
Squashed = 0x1,
|
Squashed = 0x1,
|
||||||
Scheduled = 0x2,
|
Scheduled = 0x2,
|
||||||
AutoDelete = 0x4,
|
AutoDelete = 0x4,
|
||||||
AutoSerialize = 0x8
|
AutoSerialize = 0x8,
|
||||||
|
IsExitEvent = 0x10
|
||||||
};
|
};
|
||||||
|
|
||||||
bool getFlags(Flags f) const { return (_flags & f) == f; }
|
bool getFlags(Flags f) const { return (_flags & f) == f; }
|
||||||
|
@ -214,6 +215,9 @@ class Event : public Serializable, public FastAlloc
|
||||||
/// Check whether the event is squashed
|
/// Check whether the event is squashed
|
||||||
bool squashed() { return getFlags(Squashed); }
|
bool squashed() { return getFlags(Squashed); }
|
||||||
|
|
||||||
|
/// See if this is a SimExitEvent (without resorting to RTTI)
|
||||||
|
bool isExitEvent() { return getFlags(IsExitEvent); }
|
||||||
|
|
||||||
/// Get the time that the event is scheduled
|
/// Get the time that the event is scheduled
|
||||||
Tick when() const { return _when; }
|
Tick when() const { return _when; }
|
||||||
|
|
||||||
|
@ -298,7 +302,7 @@ class EventQueue : public Serializable
|
||||||
void reschedule(Event *ev);
|
void reschedule(Event *ev);
|
||||||
|
|
||||||
Tick nextTick() { return head->when(); }
|
Tick nextTick() { return head->when(); }
|
||||||
void serviceOne();
|
Event *serviceOne();
|
||||||
|
|
||||||
// process all events up to the given timestamp. we inline a
|
// process all events up to the given timestamp. we inline a
|
||||||
// quick test to see if there are any events to process; if so,
|
// quick test to see if there are any events to process; if so,
|
||||||
|
|
|
@ -56,6 +56,8 @@ typedef int64_t Counter;
|
||||||
*/
|
*/
|
||||||
typedef int64_t Tick;
|
typedef int64_t Tick;
|
||||||
|
|
||||||
|
const Tick MaxTick = (1LL << 62);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Address type
|
* Address type
|
||||||
* This will probably be moved somewhere else in the near future.
|
* This will probably be moved somewhere else in the near future.
|
||||||
|
|
266
src/sim/main.cc
266
src/sim/main.cc
|
@ -41,11 +41,13 @@
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "base/callback.hh"
|
||||||
#include "base/inifile.hh"
|
#include "base/inifile.hh"
|
||||||
#include "base/misc.hh"
|
#include "base/misc.hh"
|
||||||
#include "base/output.hh"
|
#include "base/output.hh"
|
||||||
|
@ -111,50 +113,39 @@ abortHandler(int sigtype)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Simulator executable name
|
|
||||||
char *myProgName = "";
|
|
||||||
|
|
||||||
///
|
const char *briefCopyright =
|
||||||
/// Echo the command line for posterity in such a way that it can be
|
"Copyright (c) 2001-2006\n"
|
||||||
/// used to rerun the same simulation (given the same .ini files).
|
"The Regents of The University of Michigan\n"
|
||||||
///
|
"All Rights Reserved\n";
|
||||||
|
|
||||||
|
/// Print welcome message.
|
||||||
void
|
void
|
||||||
echoCommandLine(int argc, char **argv, ostream &out)
|
sayHello(ostream &out)
|
||||||
{
|
{
|
||||||
out << "command line: " << argv[0];
|
extern const char *compileDate; // from date.cc
|
||||||
for (int i = 1; i < argc; i++) {
|
|
||||||
string arg(argv[i]);
|
|
||||||
|
|
||||||
out << ' ';
|
ccprintf(out, "M5 Simulator System\n");
|
||||||
|
// display copyright
|
||||||
|
ccprintf(out, "%s\n", briefCopyright);
|
||||||
|
ccprintf(out, "M5 compiled %d\n", compileDate);
|
||||||
|
ccprintf(out, "M5 started %s\n", Time::start);
|
||||||
|
|
||||||
// If the arg contains spaces, we need to quote it.
|
char *host = getenv("HOSTNAME");
|
||||||
// The rest of this is overkill to make it look purty.
|
if (!host)
|
||||||
|
host = getenv("HOST");
|
||||||
|
|
||||||
// print dashes first outside quotes
|
if (host)
|
||||||
int non_dash_pos = arg.find_first_not_of("-");
|
ccprintf(out, "M5 executing on %s\n", host);
|
||||||
out << arg.substr(0, non_dash_pos); // print dashes
|
|
||||||
string body = arg.substr(non_dash_pos); // the rest
|
|
||||||
|
|
||||||
// if it's an assignment, handle the lhs & rhs separately
|
|
||||||
int eq_pos = body.find("=");
|
|
||||||
if (eq_pos == string::npos) {
|
|
||||||
out << quote(body);
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
string lhs(body.substr(0, eq_pos));
|
|
||||||
string rhs(body.substr(eq_pos + 1));
|
|
||||||
|
|
||||||
out << quote(lhs) << "=" << quote(rhs);
|
|
||||||
}
|
extern "C" { void init_main(); }
|
||||||
}
|
|
||||||
out << endl << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
// Save off program name
|
sayHello(cerr);
|
||||||
myProgName = argv[0];
|
|
||||||
|
|
||||||
signal(SIGFPE, SIG_IGN); // may occur on misspeculated paths
|
signal(SIGFPE, SIG_IGN); // may occur on misspeculated paths
|
||||||
signal(SIGTRAP, SIG_IGN);
|
signal(SIGTRAP, SIG_IGN);
|
||||||
|
@ -163,37 +154,108 @@ main(int argc, char **argv)
|
||||||
signal(SIGINT, exitNowHandler); // dump final stats and exit
|
signal(SIGINT, exitNowHandler); // dump final stats and exit
|
||||||
signal(SIGABRT, abortHandler);
|
signal(SIGABRT, abortHandler);
|
||||||
|
|
||||||
// Python embedded interpreter invocation
|
|
||||||
Py_SetProgramName(argv[0]);
|
Py_SetProgramName(argv[0]);
|
||||||
const char *fileName = Py_GetProgramFullPath();
|
|
||||||
|
// default path to m5 python code is the currently executing
|
||||||
|
// file... Python ZipImporter will find embedded zip archive
|
||||||
|
char *pythonpath = argv[0];
|
||||||
|
|
||||||
|
bool interactive = false;
|
||||||
|
bool getopt_done = false;
|
||||||
|
do {
|
||||||
|
switch (getopt(argc, argv, "+p:i")) {
|
||||||
|
// -p <path> prepends <path> to PYTHONPATH instead of
|
||||||
|
// using built-in zip archive. Useful when
|
||||||
|
// developing/debugging changes to built-in Python
|
||||||
|
// libraries, as the new Python can be tested without
|
||||||
|
// building a new m5 binary.
|
||||||
|
case 'p':
|
||||||
|
pythonpath = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// -i forces entry into interactive mode after the
|
||||||
|
// supplied script is executed (just like the -i option to
|
||||||
|
// the Python interpreter).
|
||||||
|
case 'i':
|
||||||
|
interactive = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case -1:
|
||||||
|
getopt_done = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fatal("Unrecognized option %c\n", optopt);
|
||||||
|
}
|
||||||
|
} while (!getopt_done);
|
||||||
|
|
||||||
|
// Fix up argc & argv to hide arguments we just processed.
|
||||||
|
// getopt() sets optind to the index of the first non-processed
|
||||||
|
// argv element.
|
||||||
|
argc -= optind;
|
||||||
|
argv += optind;
|
||||||
|
|
||||||
|
// Set up PYTHONPATH to make sure the m5 module is found
|
||||||
|
string newpath(pythonpath);
|
||||||
|
|
||||||
|
char *oldpath = getenv("PYTHONPATH");
|
||||||
|
if (oldpath != NULL) {
|
||||||
|
newpath += ":";
|
||||||
|
newpath += oldpath;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setenv("PYTHONPATH", newpath.c_str(), true) == -1)
|
||||||
|
fatal("setenv: %s\n", strerror(errno));
|
||||||
|
|
||||||
|
// initialize embedded Python interpreter
|
||||||
Py_Initialize();
|
Py_Initialize();
|
||||||
PySys_SetArgv(argc, argv);
|
PySys_SetArgv(argc, argv);
|
||||||
|
|
||||||
// loadSwigModules();
|
// initialize SWIG 'main' module
|
||||||
|
init_main();
|
||||||
|
|
||||||
// Set Python module path to include current file to find embedded
|
if (argc > 0) {
|
||||||
// zip archive
|
// extra arg(s): first is script file, remaining ones are args
|
||||||
if (PyRun_SimpleString("import sys") != 0)
|
// to script file
|
||||||
panic("Python error importing 'sys' module\n");
|
char *filename = argv[0];
|
||||||
string pathCmd = csprintf("sys.path[1:1] = ['%s']", fileName);
|
FILE *fp = fopen(filename, "r");
|
||||||
if (PyRun_SimpleString(pathCmd.c_str()) != 0)
|
if (!fp) {
|
||||||
panic("Python error setting sys.path\n");
|
fatal("cannot open file '%s'\n", filename);
|
||||||
|
}
|
||||||
|
|
||||||
// Pass compile timestamp string to Python
|
PyRun_AnyFile(fp, filename);
|
||||||
extern const char *compileDate; // from date.cc
|
} else {
|
||||||
string setCompileDate = csprintf("compileDate = '%s'", compileDate);
|
// no script file argument... force interactive prompt
|
||||||
if (PyRun_SimpleString(setCompileDate.c_str()) != 0)
|
interactive = true;
|
||||||
panic("Python error setting compileDate\n");
|
}
|
||||||
|
|
||||||
// PyRun_InteractiveLoop(stdin, "stdin");
|
if (interactive) {
|
||||||
// m5/__init__.py currently contains main argv parsing loop etc.,
|
// The following code to import readline was copied from Python
|
||||||
// and will write out config.ini file before returning.
|
// 2.4.3's Modules/main.c.
|
||||||
if (PyImport_ImportModule("defines") == NULL)
|
// Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006
|
||||||
panic("Python error importing 'defines.py'\n");
|
// Python Software Foundation; All Rights Reserved
|
||||||
if (PyImport_ImportModule("m5") == NULL)
|
// We should only enable this if we're actually using an
|
||||||
panic("Python error importing 'm5' module\n");
|
// interactive prompt.
|
||||||
|
PyObject *v;
|
||||||
|
v = PyImport_ImportModule("readline");
|
||||||
|
if (v == NULL)
|
||||||
|
PyErr_Clear();
|
||||||
|
else
|
||||||
|
Py_DECREF(v);
|
||||||
|
|
||||||
|
PyRun_InteractiveLoop(stdin, "stdin");
|
||||||
|
}
|
||||||
|
|
||||||
|
// clean up Python intepreter.
|
||||||
Py_Finalize();
|
Py_Finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Initialize C++ configuration. Exported to Python via SWIG; invoked
|
||||||
|
/// from m5.instantiate().
|
||||||
|
void
|
||||||
|
initialize()
|
||||||
|
{
|
||||||
configStream = simout.find("config.out");
|
configStream = simout.find("config.out");
|
||||||
|
|
||||||
// The configuration database is now complete; start processing it.
|
// The configuration database is now complete; start processing it.
|
||||||
|
@ -212,8 +274,7 @@ main(int argc, char **argv)
|
||||||
ParamContext::parseAllContexts(inifile);
|
ParamContext::parseAllContexts(inifile);
|
||||||
ParamContext::checkAllContexts();
|
ParamContext::checkAllContexts();
|
||||||
|
|
||||||
// Echo command line and all parameter settings to stats file as well.
|
// Echo all parameter settings to stats file as well.
|
||||||
echoCommandLine(argc, argv, *outputStream);
|
|
||||||
ParamContext::showAllContexts(*configStream);
|
ParamContext::showAllContexts(*configStream);
|
||||||
|
|
||||||
// Any objects that can't connect themselves until after construction should
|
// Any objects that can't connect themselves until after construction should
|
||||||
|
@ -244,16 +305,61 @@ main(int argc, char **argv)
|
||||||
// Reset to put the stats in a consistent state.
|
// Reset to put the stats in a consistent state.
|
||||||
Stats::reset();
|
Stats::reset();
|
||||||
|
|
||||||
warn("Entering event queue. Starting simulation...\n");
|
|
||||||
SimStartup();
|
SimStartup();
|
||||||
while (!mainEventQueue.empty()) {
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Simulate for num_cycles additional cycles. If num_cycles is -1
|
||||||
|
* (the default), do not limit simulation; some other event must
|
||||||
|
* terminate the loop. Exported to Python via SWIG.
|
||||||
|
* @return The SimLoopExitEvent that caused the loop to exit.
|
||||||
|
*/
|
||||||
|
SimLoopExitEvent *
|
||||||
|
simulate(Tick num_cycles = -1)
|
||||||
|
{
|
||||||
|
warn("Entering event queue @ %d. Starting simulation...\n", curTick);
|
||||||
|
|
||||||
|
// Fix up num_cycles. Special default value -1 means simulate
|
||||||
|
// "forever"... schedule event at MaxTick just to be safe.
|
||||||
|
// Otherwise it's a delta for additional cycles to simulate past
|
||||||
|
// curTick, and thus must be non-negative.
|
||||||
|
if (num_cycles == -1)
|
||||||
|
num_cycles = MaxTick;
|
||||||
|
else if (num_cycles < 0)
|
||||||
|
fatal("simulate: num_cycles must be >= 0 (was %d)\n", num_cycles);
|
||||||
|
else
|
||||||
|
num_cycles = curTick + num_cycles;
|
||||||
|
|
||||||
|
Event *limit_event = new SimLoopExitEvent(num_cycles,
|
||||||
|
"simulate() limit reached");
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
// there should always be at least one event (the SimLoopExitEvent
|
||||||
|
// we just scheduled) in the queue
|
||||||
|
assert(!mainEventQueue.empty());
|
||||||
assert(curTick <= mainEventQueue.nextTick() &&
|
assert(curTick <= mainEventQueue.nextTick() &&
|
||||||
"event scheduled in the past");
|
"event scheduled in the past");
|
||||||
|
|
||||||
// forward current cycle to the time of the first event on the
|
// forward current cycle to the time of the first event on the
|
||||||
// queue
|
// queue
|
||||||
curTick = mainEventQueue.nextTick();
|
curTick = mainEventQueue.nextTick();
|
||||||
mainEventQueue.serviceOne();
|
Event *exit_event = mainEventQueue.serviceOne();
|
||||||
|
if (exit_event != NULL) {
|
||||||
|
// hit some kind of exit event; return to Python
|
||||||
|
// event must be subclass of SimLoopExitEvent...
|
||||||
|
SimLoopExitEvent *se_event = dynamic_cast<SimLoopExitEvent *>(exit_event);
|
||||||
|
if (se_event == NULL)
|
||||||
|
panic("Bogus exit event class!");
|
||||||
|
|
||||||
|
// if we didn't hit limit_event, delete it
|
||||||
|
if (se_event != limit_event) {
|
||||||
|
assert(limit_event->scheduled());
|
||||||
|
limit_event->deschedule();
|
||||||
|
delete limit_event;
|
||||||
|
}
|
||||||
|
|
||||||
|
return se_event;
|
||||||
|
}
|
||||||
|
|
||||||
if (async_event) {
|
if (async_event) {
|
||||||
async_event = false;
|
async_event = false;
|
||||||
|
@ -273,7 +379,7 @@ main(int argc, char **argv)
|
||||||
|
|
||||||
if (async_exit) {
|
if (async_exit) {
|
||||||
async_exit = false;
|
async_exit = false;
|
||||||
new SimExitEvent("User requested STOP");
|
exitSimLoop("user interrupt received");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (async_io || async_alarm) {
|
if (async_io || async_alarm) {
|
||||||
|
@ -284,11 +390,37 @@ main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This should never happen... every conceivable way for the
|
// not reached... only exit is return on SimLoopExitEvent
|
||||||
// simulation to terminate (hit max cycles/insts, signal,
|
}
|
||||||
// simulated system halts/exits) generates an exit event, so we
|
|
||||||
// should never run out of events on the queue.
|
/**
|
||||||
exitNow("no events on event loop! All CPUs must be idle.", 1);
|
* Queue of C++ callbacks to invoke on simulator exit.
|
||||||
|
*/
|
||||||
return 0;
|
CallbackQueue exitCallbacks;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register an exit callback.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
registerExitCallback(Callback *callback)
|
||||||
|
{
|
||||||
|
exitCallbacks.add(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do C++ simulator exit processing. Exported to SWIG to be invoked
|
||||||
|
* when simulator terminates via Python's atexit mechanism.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
doExitCleanup()
|
||||||
|
{
|
||||||
|
exitCallbacks.process();
|
||||||
|
exitCallbacks.clear();
|
||||||
|
|
||||||
|
cout.flush();
|
||||||
|
|
||||||
|
ParamContext::cleanupAllContexts();
|
||||||
|
|
||||||
|
// print simulation stats
|
||||||
|
Stats::DumpNow();
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,14 +134,14 @@ namespace AlphaPseudo
|
||||||
void
|
void
|
||||||
m5exit_old(ExecContext *xc)
|
m5exit_old(ExecContext *xc)
|
||||||
{
|
{
|
||||||
SimExit(curTick, "m5_exit_old instruction encountered");
|
exitSimLoop(curTick, "m5_exit_old instruction encountered");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
m5exit(ExecContext *xc, Tick delay)
|
m5exit(ExecContext *xc, Tick delay)
|
||||||
{
|
{
|
||||||
Tick when = curTick + delay * Clock::Int::ns;
|
Tick when = curTick + delay * Clock::Int::ns;
|
||||||
SimExit(when, "m5_exit instruction encountered");
|
exitSimLoop(when, "m5_exit instruction encountered");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include "sim/builder.hh"
|
#include "sim/builder.hh"
|
||||||
#include "sim/host.hh"
|
#include "sim/host.hh"
|
||||||
#include "sim/sim_events.hh"
|
#include "sim/sim_events.hh"
|
||||||
|
#include "sim/sim_exit.hh"
|
||||||
#include "sim/sim_object.hh"
|
#include "sim/sim_object.hh"
|
||||||
#include "sim/root.hh"
|
#include "sim/root.hh"
|
||||||
|
|
||||||
|
@ -99,7 +100,7 @@ void
|
||||||
Root::startup()
|
Root::startup()
|
||||||
{
|
{
|
||||||
if (max_tick != 0)
|
if (max_tick != 0)
|
||||||
new SimExitEvent(curTick + max_tick, "reached maximum cycle count");
|
exitSimLoop(curTick + max_tick, "reached maximum cycle count");
|
||||||
|
|
||||||
if (progress_interval != 0)
|
if (progress_interval != 0)
|
||||||
new ProgressEvent(&mainEventQueue, progress_interval);
|
new ProgressEvent(&mainEventQueue, progress_interval);
|
||||||
|
|
|
@ -248,7 +248,7 @@ Serializable::serializeAll()
|
||||||
assert(Serializable::ckptPrevCount + 1 == Serializable::ckptCount);
|
assert(Serializable::ckptPrevCount + 1 == Serializable::ckptCount);
|
||||||
Serializable::ckptPrevCount++;
|
Serializable::ckptPrevCount++;
|
||||||
if (ckptMaxCount && ++ckptCount >= ckptMaxCount)
|
if (ckptMaxCount && ++ckptCount >= ckptMaxCount)
|
||||||
SimExit(curTick + 1, "Maximum number of checkpoints dropped");
|
exitSimLoop(curTick + 1, "Maximum number of checkpoints dropped");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,26 +45,37 @@ using namespace std;
|
||||||
// handle termination event
|
// handle termination event
|
||||||
//
|
//
|
||||||
void
|
void
|
||||||
SimExitEvent::process()
|
SimLoopExitEvent::process()
|
||||||
{
|
{
|
||||||
// This event does not autodelete because exitNow may be called,
|
// if this got scheduled on a different queue (e.g. the committed
|
||||||
// and the function will never be allowed to finish.
|
// instruction queue) then make a corresponding event on the main
|
||||||
if (theQueue() == &mainEventQueue) {
|
// queue.
|
||||||
string _cause = cause;
|
if (theQueue() != &mainEventQueue) {
|
||||||
int _code = code;
|
exitSimLoop(cause, code);
|
||||||
delete this;
|
|
||||||
exitNow(_cause, _code);
|
|
||||||
} else {
|
|
||||||
new SimExitEvent(cause, code);
|
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// otherwise do nothing... the IsExitEvent flag takes care of
|
||||||
|
// exiting the simulation loop and returning this object to Python
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
SimExitEvent::description()
|
SimLoopExitEvent::description()
|
||||||
{
|
{
|
||||||
return "simulation termination";
|
return "simulation loop exit";
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exitSimLoop(Tick when, const std::string &message, int exit_code)
|
||||||
|
{
|
||||||
|
new SimLoopExitEvent(when, message, exit_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exitSimLoop(const std::string &message, int exit_code)
|
||||||
|
{
|
||||||
|
exitSimLoop(curTick, message, exit_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -90,7 +101,7 @@ void
|
||||||
CountedExitEvent::process()
|
CountedExitEvent::process()
|
||||||
{
|
{
|
||||||
if (--downCounter == 0) {
|
if (--downCounter == 0) {
|
||||||
new SimExitEvent(cause, 0);
|
exitSimLoop(cause, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +130,7 @@ CheckSwapEvent::process()
|
||||||
|
|
||||||
if (swap < 100) {
|
if (swap < 100) {
|
||||||
cerr << "\a\aAborting Simulation! Inadequate swap space!\n\n";
|
cerr << "\a\aAborting Simulation! Inadequate swap space!\n\n";
|
||||||
new SimExitEvent("Lack of swap space");
|
exitSimLoop("Lack of swap space");
|
||||||
}
|
}
|
||||||
|
|
||||||
schedule(curTick + interval);
|
schedule(curTick + interval);
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
//
|
//
|
||||||
// Event to terminate simulation at a particular cycle/instruction
|
// Event to terminate simulation at a particular cycle/instruction
|
||||||
//
|
//
|
||||||
class SimExitEvent : public Event
|
class SimLoopExitEvent : public Event
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
// string explaining why we're terminating
|
// string explaining why we're terminating
|
||||||
|
@ -44,24 +44,18 @@ class SimExitEvent : public Event
|
||||||
int code;
|
int code;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SimExitEvent(const std::string &_cause, int c = 0)
|
SimLoopExitEvent(Tick _when, const std::string &_cause, int c = 0)
|
||||||
: Event(&mainEventQueue, Sim_Exit_Pri), cause(_cause),
|
: Event(&mainEventQueue, Sim_Exit_Pri), cause(_cause),
|
||||||
code(c)
|
code(c)
|
||||||
{ schedule(curTick); }
|
{ setFlags(IsExitEvent); schedule(_when); }
|
||||||
|
|
||||||
SimExitEvent(Tick _when, const std::string &_cause, int c = 0)
|
SimLoopExitEvent(EventQueue *q,
|
||||||
: Event(&mainEventQueue, Sim_Exit_Pri), cause(_cause),
|
Tick _when, const std::string &_cause, int c = 0)
|
||||||
code(c)
|
|
||||||
{ schedule(_when); }
|
|
||||||
|
|
||||||
SimExitEvent(EventQueue *q, const std::string &_cause, int c = 0)
|
|
||||||
: Event(q, Sim_Exit_Pri), cause(_cause), code(c)
|
: Event(q, Sim_Exit_Pri), cause(_cause), code(c)
|
||||||
{ schedule(curTick); }
|
{ setFlags(IsExitEvent); schedule(_when); }
|
||||||
|
|
||||||
SimExitEvent(EventQueue *q, Tick _when, const std::string &_cause,
|
std::string getCause() { return cause; }
|
||||||
int c = 0)
|
int getCode() { return code; }
|
||||||
: Event(q, Sim_Exit_Pri), cause(_cause), code(c)
|
|
||||||
{ schedule(_when); }
|
|
||||||
|
|
||||||
void process(); // process event
|
void process(); // process event
|
||||||
|
|
||||||
|
|
|
@ -36,12 +36,23 @@
|
||||||
|
|
||||||
#include "sim/host.hh"
|
#include "sim/host.hh"
|
||||||
|
|
||||||
|
// forward declaration
|
||||||
class Callback;
|
class Callback;
|
||||||
|
|
||||||
|
/// Register a callback to be called when Python exits. Defined in
|
||||||
|
/// sim/main.cc.
|
||||||
void registerExitCallback(Callback *);
|
void registerExitCallback(Callback *);
|
||||||
|
|
||||||
void exitNow(const std::string &cause, int exit_code);
|
/// Schedule an event to exit the simulation loop (returning to
|
||||||
void exitNow(const char *cause, int exit_code);
|
/// Python) at the indicated tick. The message and exit_code
|
||||||
void SimExit(Tick when, const char *message);
|
/// parameters are saved in the SimLoopExitEvent to indicate why the
|
||||||
|
/// exit occurred.
|
||||||
|
void exitSimLoop(Tick when, const std::string &message, int exit_code = 0);
|
||||||
|
|
||||||
|
/// Schedule an event to exit the simulation loop (returning to
|
||||||
|
/// Python) at the end of the current cycle (curTick). The message
|
||||||
|
/// and exit_code parameters are saved in the SimLoopExitEvent to
|
||||||
|
/// indicate why the exit occurred.
|
||||||
|
void exitSimLoop(const std::string &cause, int exit_code = 0);
|
||||||
|
|
||||||
#endif // __SIM_EXIT_HH__
|
#endif // __SIM_EXIT_HH__
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
#include "mem/page_table.hh"
|
#include "mem/page_table.hh"
|
||||||
#include "sim/process.hh"
|
#include "sim/process.hh"
|
||||||
|
|
||||||
#include "sim/sim_events.hh"
|
#include "sim/sim_exit.hh"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace TheISA;
|
using namespace TheISA;
|
||||||
|
@ -91,7 +91,7 @@ SyscallReturn
|
||||||
exitFunc(SyscallDesc *desc, int callnum, Process *process,
|
exitFunc(SyscallDesc *desc, int callnum, Process *process,
|
||||||
ExecContext *xc)
|
ExecContext *xc)
|
||||||
{
|
{
|
||||||
new SimExitEvent("target called exit()", xc->getSyscallArg(0) & 0xff);
|
exitSimLoop("target called exit()", xc->getSyscallArg(0) & 0xff);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue