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:
Steve Reinhardt 2006-06-09 23:01:31 -04:00
parent 5802c46c3b
commit 29e34a739b
51 changed files with 453 additions and 327 deletions

View file

@ -158,6 +158,12 @@ env = Environment(ENV = os.environ, # inherit user's environment vars
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
# unnecessary builds, but it also seems to make trivial builds take
# noticeably longer.
@ -193,6 +199,19 @@ env.Append(LIBS = py_version_name)
if sys.exec_prefix != '/usr':
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
env.Append(LIBS=['z'])
@ -468,7 +487,7 @@ for build_path in build_paths:
# to the configured options. It returns a list of environments,
# one for each variant build (debug, opt, etc.)
envList = SConscript('src/SConscript', build_dir = build_path,
exports = 'env', duplicate = False)
exports = 'env')
# Set up the regression tests for each build.
# for e in envList:

View file

@ -1,12 +1,40 @@
from m5 import *
import os, optparse, sys
import m5
from m5.objects import *
class HelloWorld(AlphaLiveProcess):
executable = '../configs/test/hello'
cmd = 'hello'
parser = optparse.OptionParser(option_list=m5.standardOptions)
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()
mem = PhysicalMemory()
cpu = AtomicSimpleCPU(workload=HelloWorld(), mem=magicbus)
system = System(physmem=mem, cpu=cpu)
system.c1 = Connector(side_a=mem, side_b=magicbus)
root = Root(system=system)
if options.timing:
cpu = TimingSimpleCPU()
else:
cpu = AtomicSimpleCPU()
cpu.workload = process
cpu.mem = magicbus
system = System(physmem = mem, cpu = cpu)
system.c1 = Connector(side_a = mem, side_b = magicbus)
root = Root(system = system)
m5.instantiate(root)
exit_event = m5.simulate()
print 'Exiting @', m5.curTick(), 'because', exit_event.getCause()

View file

@ -104,12 +104,12 @@ base_sources = Split('''
sim/eventq.cc
sim/faults.cc
sim/main.cc
python/swig/main_wrap.cc
sim/param.cc
sim/profile.cc
sim/root.cc
sim/serialize.cc
sim/sim_events.cc
sim/sim_exit.cc
sim/sim_object.cc
sim/startup.cc
sim/stat_context.cc
@ -281,14 +281,18 @@ memtest_sources = Split('''
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
env.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())])
arch_sources = SConscript('arch/SConscript',
exports = 'env', duplicate = False)
arch_sources = SConscript('arch/SConscript', exports = 'env')
cpu_sources = SConscript('cpu/SConscript',
exports = 'env', duplicate = False)
cpu_sources = SConscript('cpu/SConscript', exports = 'env')
# This is outside of cpu/SConscript since the source directory isn't
# underneath 'cpu'.
@ -323,7 +327,7 @@ env.Command(Split('base/traceflags.hh base/traceflags.cc'),
'base/traceflags.py',
'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
# 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
envList = []

View file

@ -146,7 +146,6 @@ env.Append(BUILDERS = { 'ISADesc' : isa_desc_builder })
isa = env['TARGET_ISA'] # someday this may be a list of ISAs
# Let the target architecture define what additional sources it needs
sources += SConscript(os.path.join(isa, 'SConscript'),
exports = 'env', duplicate = False)
sources += SConscript(os.path.join(isa, 'SConscript'), exports = 'env')
Return('sources')

View file

@ -564,7 +564,7 @@ CPUExecContext::simPalCheck(int palFunc)
case PAL::halt:
halt();
if (--System::numSystemsRunning == 0)
new SimExitEvent("all cpus halted");
exitSimLoop("all cpus halted");
break;
case PAL::bpt:

View file

@ -697,7 +697,7 @@ decode OPCODE default Unknown::unknown() {
0x00: decode PALFUNC {
format EmulatedCallPal {
0x00: halt ({{
SimExit(curTick, "halt instruction encountered");
exitSimLoop(curTick, "halt instruction encountered");
}}, IsNonSpeculative);
0x83: callsys({{
xc->syscall(R0);

View file

@ -93,8 +93,8 @@ BaseCPU::BaseCPU(Params *p)
//
if (p->max_insts_any_thread != 0)
for (int i = 0; i < number_of_threads; ++i)
new SimExitEvent(comInstEventQueue[i], p->max_insts_any_thread,
"a thread reached the max instruction count");
new SimLoopExitEvent(comInstEventQueue[i], p->max_insts_any_thread,
"a thread reached the max instruction count");
if (p->max_insts_all_threads != 0) {
// allocate & initialize shared downcounter: each event will
@ -118,8 +118,8 @@ BaseCPU::BaseCPU(Params *p)
//
if (p->max_loads_any_thread != 0)
for (int i = 0; i < number_of_threads; ++i)
new SimExitEvent(comLoadEventQueue[i], p->max_loads_any_thread,
"a thread reached the max load count");
new SimLoopExitEvent(comLoadEventQueue[i], p->max_loads_any_thread,
"a thread reached the max load count");
if (p->max_loads_all_threads != 0) {
// allocate & initialize shared downcounter: each event will

View file

@ -292,7 +292,7 @@ AlphaFullCPU<Impl>::simPalCheck(int palFunc)
case PAL::halt:
halt();
if (--System::numSystemsRunning == 0)
new SimExitEvent("all cpus halted");
exitSimLoop("all cpus halted");
break;
case PAL::bpt:

View file

@ -176,7 +176,7 @@ OptCPU::tick()
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.accesses %d #opt cache acceses\n", references);
new SimExitEvent("Finshed Memory Trace");
exitSimLoop("end of memory trace reached");
}
void

View file

@ -108,7 +108,7 @@ TraceCPU::tick()
if (!nextReq) {
// No more requests to send. Finish trailing events and exit.
if (mainEventQueue.empty()) {
new SimExitEvent("Finshed Memory Trace");
exitSimLoop("end of memory trace reached");
} else {
tickEvent.schedule(mainEventQueue.nextEventTime() + cycles(1));
}

View file

@ -38,11 +38,8 @@ def join(*args):
Import('env')
# 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'
# This SConscript is in charge of collecting .py files and generating
# a zip archive that is appended to the m5 binary.
# List of files & directories to include in the zip file. To include
# 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
# pyzip_files and all included .py files to pyzip_dep_files.
def addPkg(pkgdir):
pyzip_files.append(join(pyzip_root, pkgdir))
pyzip_files.append(pkgdir)
origdir = os.getcwd()
srcdir = join(Dir('.').srcnode().abspath, pkgdir)
os.chdir(srcdir)
@ -70,10 +67,7 @@ def addPkg(pkgdir):
for f in files:
if f.endswith('.py'):
source = join(pkgdir, path, f)
target = join(pyzip_root, source)
pyzip_dep_files.append(target)
env.CopyFile(target, source)
pyzip_dep_files.append(join(pkgdir, path, f))
os.chdir(origdir)
@ -81,19 +75,25 @@ def addPkg(pkgdir):
# build_env flags.
def MakeDefinesPyFile(target, source, env):
f = file(str(target[0]), 'w')
print >>f, "import __main__"
print >>f, "__main__.m5_build_env = ",
print >>f, "m5_build_env = ",
print >>f, source[0]
f.close()
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.
addPkg('m5')
pyzip_files.append('defines.py')
pyzip_files.append('m5/defines.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
# included in the standard Python library.
def buildPyZip(target, source, env):

View file

@ -27,69 +27,26 @@
# Authors: Nathan Binkert
# 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 = '''
Copyright (c) 2001-2006
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)
# import the m5 compile options
import defines
# define this here so we can use it right away if necessary
def panic(string):
print >>sys.stderr, 'panic:', string
sys.exit(1)
def m5execfile(f, global_dict):
# copy current sys.path
oldpath = sys.path[:]
# 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.
# Prepend given directory to system module search path. We may not
# need this anymore if we can structure our config library more like a
# Python package.
def AddToPath(path):
# if it's a relative path and we know what directory the current
# 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.
sys.path.insert(1, path)
# find the m5 compile options: must be specified as a dict in
# __main__.m5_build_env.
import __main__
if not hasattr(__main__, 'm5_build_env'):
panic("__main__ must define m5_build_env")
# Callback to set trace flags. Not necessarily the best way to do
# things in the long run (particularly if we change how these global
# options are handled).
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
import 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
env = smartdict.SmartDict()
env.update(os.environ)
# import the main m5 config code
from config import *
# import the built-in object definitions
from objects import *
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):
# The final hook to generate .ini files. Called from the user script
# once the config is built.
def instantiate(root):
config.ticks_per_sec = float(root.clock.frequency)
# ugly temporary hack to get output to config.ini
sys.stdout = file('config.ini', 'w')
instantiate(root)
else:
print 'Instantiation skipped: no root object found.'
root.print_ini()
sys.stdout.close() # close config.ini
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

View file

@ -728,7 +728,7 @@ class ParamDesc(object):
def __getattr__(self, attr):
if attr == 'ptype':
try:
ptype = eval(self.ptype_str, m5.__dict__)
ptype = eval(self.ptype_str, m5.objects.__dict__)
if not isinstance(ptype, type):
panic("Param qualifier is not a type: %s" % self.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
# 'from config import *' is invoked. Try to keep this reasonably
# short to avoid polluting other namespaces.
@ -1322,5 +1305,5 @@ __all__ = ['SimObject', 'ParamContext', 'Param', 'VectorParam',
'NetworkBandwidth', 'MemoryBandwidth',
'Range', 'AddrRange', 'MaxAddr', 'MaxTick', 'AllMemory',
'Null', 'NULL',
'NextEthernetAddr', 'instantiate']
'NextEthernetAddr']

View file

@ -1,4 +1,4 @@
from m5 import *
from m5.config import *
from Device import BasicPioDevice
class AlphaConsole(BasicPioDevice):

View file

@ -1,4 +1,5 @@
from m5 import *
from m5 import build_env
from m5.config import *
from BaseCPU import BaseCPU
class DerivAlphaFullCPU(BaseCPU):

View file

@ -1,4 +1,4 @@
from m5 import *
from m5.config import *
class AlphaTLB(SimObject):
type = 'AlphaTLB'
abstract = True

View file

@ -1,4 +1,4 @@
from m5 import *
from m5.config import *
from Device import BasicPioDevice
class BadDevice(BasicPioDevice):

View file

@ -1,4 +1,6 @@
from m5 import *
from m5 import build_env
from m5.config import *
class BaseCPU(SimObject):
type = 'BaseCPU'
abstract = True

View file

@ -1,4 +1,4 @@
from m5 import *
from m5.config import *
from BaseMem import BaseMem
class Prefetch(Enum): vals = ['none', 'tagged', 'stride', 'ghb']

View file

@ -1,4 +1,4 @@
from m5 import *
from m5.config import *
from MemObject import MemObject
class Bridge(MemObject):

View file

@ -1,4 +1,4 @@
from m5 import *
from m5.config import *
from MemObject import MemObject
class Bus(MemObject):

View file

@ -1,4 +1,4 @@
from m5 import *
from m5.config import *
class Coherence(Enum): vals = ['uni', 'msi', 'mesi', 'mosi', 'moesi']
class CoherenceProtocol(SimObject):

View file

@ -1,4 +1,4 @@
from m5 import *
from m5.config import *
from MemObject import MemObject
class PioDevice(MemObject):

View file

@ -1,4 +1,4 @@
from m5 import *
from m5.config import *
class DiskImage(SimObject):
type = 'DiskImage'
abstract = True

View file

@ -1,4 +1,5 @@
from m5 import *
from m5 import build_env
from m5.config import *
from Device import DmaDevice
from Pci import PciDevice

View file

@ -1,4 +1,4 @@
from m5 import *
from m5.config import *
from Pci import PciDevice
class IdeID(Enum): vals = ['master', 'slave']

View file

@ -1,4 +1,4 @@
from m5 import *
from m5.config import *
class IntrControl(SimObject):
type = 'IntrControl'
cpu = Param.BaseCPU(Parent.any, "the cpu")

View file

@ -1,4 +1,4 @@
from m5 import *
from m5.config import *
class MemObject(SimObject):
type = 'MemObject'

View file

@ -1,4 +1,4 @@
from m5 import *
from m5.config import *
class MemTest(SimObject):
type = 'MemTest'
cache = Param.BaseCache("L1 cache")

View file

@ -1,4 +1,4 @@
from m5 import *
from m5.config import *
from Device import BasicPioDevice, DmaDevice
class PciConfigData(SimObject):

View file

@ -1,4 +1,4 @@
from m5 import *
from m5.config import *
from MemObject import *
class PhysicalMemory(MemObject):

View file

@ -1,4 +1,4 @@
from m5 import *
from m5.config import *
class Platform(SimObject):
type = 'Platform'
abstract = True

View file

@ -1,4 +1,4 @@
from m5 import *
from m5.config import *
class Process(SimObject):
type = 'Process'
abstract = True

View file

@ -1,4 +1,4 @@
from m5 import *
from m5.config import *
class Repl(SimObject):
type = 'Repl'
abstract = True

View file

@ -1,4 +1,4 @@
from m5 import *
from m5.config import *
from Serialize import Serialize
from Statistics import Statistics
from Trace import Trace

View file

@ -1,4 +1,4 @@
from m5 import *
from m5.config import *
class ConsoleListener(SimObject):
type = 'ConsoleListener'
port = Param.TcpPort(3456, "listen port")

View file

@ -1,4 +1,4 @@
from m5 import *
from m5.config import *
class SimpleDisk(SimObject):
type = 'SimpleDisk'
disk = Param.DiskImage("Disk Image")

View file

@ -1,4 +1,5 @@
from m5 import *
from m5 import build_env
from m5.config import *
class System(SimObject):
type = 'System'

View file

@ -1,4 +1,4 @@
from m5 import *
from m5.config import *
from Device import BasicPioDevice
from Platform import Platform

View file

@ -1,4 +1,5 @@
from m5 import *
from m5 import build_env
from m5.config import *
from Device import BasicPioDevice
class Uart(BasicPioDevice):

View file

@ -102,7 +102,7 @@ EventQueue::remove(Event *event)
prev->next = curr->next;
}
void
Event *
EventQueue::serviceOne()
{
Event *event = head;
@ -110,13 +110,20 @@ EventQueue::serviceOne()
head = event->next;
// handle action
if (!event->squashed())
if (!event->squashed()) {
event->process();
else
if (event->isExitEvent()) {
assert(!event->getFlags(Event::AutoDelete)); // would be silly
return event;
}
} else {
event->clearFlags(Event::Squashed);
}
if (event->getFlags(Event::AutoDelete) && !event->scheduled())
delete event;
return NULL;
}

View file

@ -90,7 +90,8 @@ class Event : public Serializable, public FastAlloc
Squashed = 0x1,
Scheduled = 0x2,
AutoDelete = 0x4,
AutoSerialize = 0x8
AutoSerialize = 0x8,
IsExitEvent = 0x10
};
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
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
Tick when() const { return _when; }
@ -298,7 +302,7 @@ class EventQueue : public Serializable
void reschedule(Event *ev);
Tick nextTick() { return head->when(); }
void serviceOne();
Event *serviceOne();
// process all events up to the given timestamp. we inline a
// quick test to see if there are any events to process; if so,

View file

@ -56,6 +56,8 @@ typedef int64_t Counter;
*/
typedef int64_t Tick;
const Tick MaxTick = (1LL << 62);
/**
* Address type
* This will probably be moved somewhere else in the near future.

View file

@ -41,11 +41,13 @@
#include <libgen.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <list>
#include <string>
#include <vector>
#include "base/callback.hh"
#include "base/inifile.hh"
#include "base/misc.hh"
#include "base/output.hh"
@ -111,50 +113,39 @@ abortHandler(int sigtype)
#endif
}
/// Simulator executable name
char *myProgName = "";
///
/// Echo the command line for posterity in such a way that it can be
/// used to rerun the same simulation (given the same .ini files).
///
const char *briefCopyright =
"Copyright (c) 2001-2006\n"
"The Regents of The University of Michigan\n"
"All Rights Reserved\n";
/// Print welcome message.
void
echoCommandLine(int argc, char **argv, ostream &out)
sayHello(ostream &out)
{
out << "command line: " << argv[0];
for (int i = 1; i < argc; i++) {
string arg(argv[i]);
extern const char *compileDate; // from date.cc
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.
// The rest of this is overkill to make it look purty.
char *host = getenv("HOSTNAME");
if (!host)
host = getenv("HOST");
// print dashes first outside quotes
int non_dash_pos = arg.find_first_not_of("-");
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);
}
}
out << endl << endl;
if (host)
ccprintf(out, "M5 executing on %s\n", host);
}
extern "C" { void init_main(); }
int
main(int argc, char **argv)
{
// Save off program name
myProgName = argv[0];
sayHello(cerr);
signal(SIGFPE, SIG_IGN); // may occur on misspeculated paths
signal(SIGTRAP, SIG_IGN);
@ -163,37 +154,108 @@ main(int argc, char **argv)
signal(SIGINT, exitNowHandler); // dump final stats and exit
signal(SIGABRT, abortHandler);
// Python embedded interpreter invocation
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();
PySys_SetArgv(argc, argv);
// loadSwigModules();
// initialize SWIG 'main' module
init_main();
// Set Python module path to include current file to find embedded
// zip archive
if (PyRun_SimpleString("import sys") != 0)
panic("Python error importing 'sys' module\n");
string pathCmd = csprintf("sys.path[1:1] = ['%s']", fileName);
if (PyRun_SimpleString(pathCmd.c_str()) != 0)
panic("Python error setting sys.path\n");
if (argc > 0) {
// extra arg(s): first is script file, remaining ones are args
// to script file
char *filename = argv[0];
FILE *fp = fopen(filename, "r");
if (!fp) {
fatal("cannot open file '%s'\n", filename);
}
// Pass compile timestamp string to Python
extern const char *compileDate; // from date.cc
string setCompileDate = csprintf("compileDate = '%s'", compileDate);
if (PyRun_SimpleString(setCompileDate.c_str()) != 0)
panic("Python error setting compileDate\n");
PyRun_AnyFile(fp, filename);
} else {
// no script file argument... force interactive prompt
interactive = true;
}
// PyRun_InteractiveLoop(stdin, "stdin");
// m5/__init__.py currently contains main argv parsing loop etc.,
// and will write out config.ini file before returning.
if (PyImport_ImportModule("defines") == NULL)
panic("Python error importing 'defines.py'\n");
if (PyImport_ImportModule("m5") == NULL)
panic("Python error importing 'm5' module\n");
if (interactive) {
// The following code to import readline was copied from Python
// 2.4.3's Modules/main.c.
// Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006
// Python Software Foundation; All Rights Reserved
// We should only enable this if we're actually using an
// 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();
}
/// Initialize C++ configuration. Exported to Python via SWIG; invoked
/// from m5.instantiate().
void
initialize()
{
configStream = simout.find("config.out");
// The configuration database is now complete; start processing it.
@ -212,8 +274,7 @@ main(int argc, char **argv)
ParamContext::parseAllContexts(inifile);
ParamContext::checkAllContexts();
// Echo command line and all parameter settings to stats file as well.
echoCommandLine(argc, argv, *outputStream);
// Echo all parameter settings to stats file as well.
ParamContext::showAllContexts(*configStream);
// 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.
Stats::reset();
warn("Entering event queue. Starting simulation...\n");
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() &&
"event scheduled in the past");
// forward current cycle to the time of the first event on the
// queue
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) {
async_event = false;
@ -273,7 +379,7 @@ main(int argc, char **argv)
if (async_exit) {
async_exit = false;
new SimExitEvent("User requested STOP");
exitSimLoop("user interrupt received");
}
if (async_io || async_alarm) {
@ -284,11 +390,37 @@ main(int argc, char **argv)
}
}
// This should never happen... every conceivable way for the
// 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);
return 0;
// not reached... only exit is return on SimLoopExitEvent
}
/**
* Queue of C++ callbacks to invoke on simulator exit.
*/
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();
}

View file

@ -134,14 +134,14 @@ namespace AlphaPseudo
void
m5exit_old(ExecContext *xc)
{
SimExit(curTick, "m5_exit_old instruction encountered");
exitSimLoop(curTick, "m5_exit_old instruction encountered");
}
void
m5exit(ExecContext *xc, Tick delay)
{
Tick when = curTick + delay * Clock::Int::ns;
SimExit(when, "m5_exit instruction encountered");
exitSimLoop(when, "m5_exit instruction encountered");
}
void

View file

@ -40,6 +40,7 @@
#include "sim/builder.hh"
#include "sim/host.hh"
#include "sim/sim_events.hh"
#include "sim/sim_exit.hh"
#include "sim/sim_object.hh"
#include "sim/root.hh"
@ -99,7 +100,7 @@ void
Root::startup()
{
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)
new ProgressEvent(&mainEventQueue, progress_interval);

View file

@ -248,7 +248,7 @@ Serializable::serializeAll()
assert(Serializable::ckptPrevCount + 1 == Serializable::ckptCount);
Serializable::ckptPrevCount++;
if (ckptMaxCount && ++ckptCount >= ckptMaxCount)
SimExit(curTick + 1, "Maximum number of checkpoints dropped");
exitSimLoop(curTick + 1, "Maximum number of checkpoints dropped");
}

View file

@ -45,26 +45,37 @@ using namespace std;
// handle termination event
//
void
SimExitEvent::process()
SimLoopExitEvent::process()
{
// This event does not autodelete because exitNow may be called,
// and the function will never be allowed to finish.
if (theQueue() == &mainEventQueue) {
string _cause = cause;
int _code = code;
delete this;
exitNow(_cause, _code);
} else {
new SimExitEvent(cause, code);
// if this got scheduled on a different queue (e.g. the committed
// instruction queue) then make a corresponding event on the main
// queue.
if (theQueue() != &mainEventQueue) {
exitSimLoop(cause, code);
delete this;
}
// otherwise do nothing... the IsExitEvent flag takes care of
// exiting the simulation loop and returning this object to Python
}
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()
{
if (--downCounter == 0) {
new SimExitEvent(cause, 0);
exitSimLoop(cause, 0);
}
}
@ -119,7 +130,7 @@ CheckSwapEvent::process()
if (swap < 100) {
cerr << "\a\aAborting Simulation! Inadequate swap space!\n\n";
new SimExitEvent("Lack of swap space");
exitSimLoop("Lack of swap space");
}
schedule(curTick + interval);

View file

@ -36,7 +36,7 @@
//
// Event to terminate simulation at a particular cycle/instruction
//
class SimExitEvent : public Event
class SimLoopExitEvent : public Event
{
private:
// string explaining why we're terminating
@ -44,24 +44,18 @@ class SimExitEvent : public Event
int code;
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),
code(c)
{ schedule(curTick); }
{ setFlags(IsExitEvent); schedule(_when); }
SimExitEvent(Tick _when, const std::string &_cause, int c = 0)
: Event(&mainEventQueue, Sim_Exit_Pri), cause(_cause),
code(c)
{ schedule(_when); }
SimExitEvent(EventQueue *q, const std::string &_cause, int c = 0)
SimLoopExitEvent(EventQueue *q,
Tick _when, const std::string &_cause, int c = 0)
: Event(q, Sim_Exit_Pri), cause(_cause), code(c)
{ schedule(curTick); }
{ setFlags(IsExitEvent); schedule(_when); }
SimExitEvent(EventQueue *q, Tick _when, const std::string &_cause,
int c = 0)
: Event(q, Sim_Exit_Pri), cause(_cause), code(c)
{ schedule(_when); }
std::string getCause() { return cause; }
int getCode() { return code; }
void process(); // process event

View file

@ -36,12 +36,23 @@
#include "sim/host.hh"
// forward declaration
class Callback;
/// Register a callback to be called when Python exits. Defined in
/// sim/main.cc.
void registerExitCallback(Callback *);
void exitNow(const std::string &cause, int exit_code);
void exitNow(const char *cause, int exit_code);
void SimExit(Tick when, const char *message);
/// Schedule an event to exit the simulation loop (returning to
/// Python) at the indicated tick. The message and exit_code
/// 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__

View file

@ -43,7 +43,7 @@
#include "mem/page_table.hh"
#include "sim/process.hh"
#include "sim/sim_events.hh"
#include "sim/sim_exit.hh"
using namespace std;
using namespace TheISA;
@ -91,7 +91,7 @@ SyscallReturn
exitFunc(SyscallDesc *desc, int callnum, Process *process,
ExecContext *xc)
{
new SimExitEvent("target called exit()", xc->getSyscallArg(0) & 0xff);
exitSimLoop("target called exit()", xc->getSyscallArg(0) & 0xff);
return 1;
}