From af33e74638ea822fba0ddbc7fddbe7583c61d920 Mon Sep 17 00:00:00 2001 From: Steve Reinhardt Date: Tue, 22 Feb 2005 23:53:34 -0500 Subject: [PATCH 01/10] Small initial steps toward generating C++ param structs from Python object descriptions. Mostly cleanup of Python code based on things I encountered trying to figure out what's going on. Main reason I'm committing this now is to transfer work from my laptop to zizzer. sim/pyconfig/m5config.py: Small steps toward param struct generation: all param objects should now have a _cppname attribute that holds their corresponding C++ type name. Made Param ptype attribute an actual type instead of a string. String is still stored in ptype_string. Get rid of AddToPath() and Import() (redundant copies are in importer, and that seems to be the more logical place for them). Add a few comments, delete some unused code. test/genini.py: A few fixes to make the environment more compatible with what really happens when configs are executed from the m5 binary. --HG-- extra : convert_revision : 9fc8f72cd0c22ba3deada02f37484787342534f2 --- sim/pyconfig/m5config.py | 139 ++++++++++++++------------------------- test/genini.py | 8 +-- 2 files changed, 52 insertions(+), 95 deletions(-) mode change 100644 => 100755 test/genini.py diff --git a/sim/pyconfig/m5config.py b/sim/pyconfig/m5config.py index 9a48e2fa4..6393fb0b8 100644 --- a/sim/pyconfig/m5config.py +++ b/sim/pyconfig/m5config.py @@ -39,16 +39,6 @@ def panic(*args, **kwargs): print >>sys.stderr, 'panic:', string sys.exit(1) -def AddToPath(path): - path = os.path.realpath(path) - if os.path.isdir(path) and path not in sys.path: - sys.path.append(path) - -def Import(path): - AddToPath(os.path.dirname(path)) - exec('from m5config import *') - mpy_exec(file(path, 'r')) - def issequence(value): return isinstance(value, tuple) or isinstance(value, list) @@ -287,8 +277,7 @@ class MetaConfigNode(type): # deal with them as params. return super(MetaConfigNode, mcls).__new__(mcls, name, bases, priv) - # initialization: start out with an empty _params dict (makes life - # simpler if we can assume _params is always valid). + # initialization def __init__(cls, name, bases, dict): super(MetaConfigNode, cls).__init__(cls, name, bases, {}) @@ -396,8 +385,11 @@ class MetaConfigNode(type): if cls._isvalue(attr): return Value(cls, attr) + if attr == '_cppname' and hasattr(cls, 'type'): + return cls.type + '*' + raise AttributeError, \ - "object '%s' has no attribute '%s'" % (cls.__name__, cls) + "object '%s' has no attribute '%s'" % (cls.__name__, attr) # Set attribute (called on foo.attr = value when foo is an # instance of class cls). @@ -577,11 +569,6 @@ class SimObject(ConfigNode): for pname in param_names] code += "\n".join(decls) + "\n" code += "END_DECLARE_SIM_OBJECT_PARAMS(%s)\n\n" % name - code += "BEGIN_INIT_SIM_OBJECT_PARAMS(%s)\n" % name - inits = [" " + cls._params[pname].sim_init(pname) \ - for pname in param_names] - code += ",\n".join(inits) + "\n" - code += "END_INIT_SIM_OBJECT_PARAMS(%s)\n\n" % name return code _sim_code = classmethod(_sim_code) @@ -620,14 +607,13 @@ class Node(object): self.path = '.'.join(path) def find(self, realtype, path): - rtype = eval(realtype) if not path: - if issubclass(self.realtype, rtype): + if issubclass(self.realtype, realtype): return self, True obj = None for child in self.children: - if issubclass(child.realtype, rtype): + if issubclass(child.realtype, realtype): if obj is not None: raise AttributeError, \ 'Super matched more than one: %s %s' % \ @@ -643,11 +629,11 @@ class Node(object): last = path[-1] if obj.child_names.has_key(last): value = obj.child_names[last] - if issubclass(value.realtype, rtype): + if issubclass(value.realtype, realtype): return value, True elif obj.param_names.has_key(last): value = obj.param_names[last] - rtype._convert(value.value) + realtype._convert(value.value) return value.value, True except KeyError: pass @@ -754,8 +740,7 @@ class Node(object): except: print 'exception in %s:%s' % (self.name, param.name) raise - ptype = eval(param.ptype) - if isConfigNode(ptype) and string != "Null": + if isConfigNode(param.ptype) and string != "Null": simobjs.append(string) else: label += '%s = %s\\n' % (param.name, string) @@ -830,8 +815,10 @@ class Value(object): # Regular parameter. class _Param(object): - def __init__(self, ptype, *args, **kwargs): - self.ptype = ptype + def __init__(self, ptype_string, *args, **kwargs): + self.ptype_string = ptype_string + # can't eval ptype_string here to get ptype, since the type might + # not have been defined yet. Do it lazily in __getattr__. if args: if len(args) == 1: @@ -858,44 +845,32 @@ class _Param(object): if not hasattr(self, 'desc'): raise TypeError, 'desc attribute missing' + def __getattr__(self, attr): + if attr == 'ptype': + try: + self.ptype = eval(self.ptype_string) + return self.ptype + except: + raise TypeError, 'Param.%s: undefined type' % self.ptype_string + else: + raise AttributeError, "'%s' object has no attribute '%s'" % \ + (type(self).__name__, attr) + def valid(self, value): if not isinstance(value, Proxy): - ptype = eval(self.ptype) - ptype._convert(value) + self.ptype._convert(value) def convert(self, value): - ptype = eval(self.ptype) - return ptype._convert(value) + return self.ptype._convert(value) def string(self, value): - ptype = eval(self.ptype) - return ptype._string(value) - - def get(self, name, instance, owner): - # nothing to do if None or already correct type. Also allow NULL - # pointer to be assigned where a SimObject is expected. - try: - if value == None or isinstance(value, self.ptype) or \ - isConfigNode(self.ptype) and \ - (isNullPointer(value) or issubclass(value, self.ptype)): - return value - - except TypeError: - # this type conversion will raise an exception if it's illegal - return self.ptype(value) + return self.ptype._string(value) def set(self, name, instance, value): instance.__dict__[name] = value def sim_decl(self, name): - return 'Param<%s> %s;' % (self.ptype.__name__, name) - - def sim_init(self, name): - if self.default == None: - return 'INIT_PARAM(%s, "%s")' % (name, self.desc) - else: - return 'INIT_PARAM_DFLT(%s, "%s", %s)' % \ - (name, self.desc, str(self.default)) + return '%s %s;' % (self.ptype._cppname, name) class _ParamProxy(object): def __init__(self, type): @@ -931,13 +906,12 @@ class _VectorParam(_Param): if value == None: return True - ptype = eval(self.ptype) if issequence(value): for val in value: if not isinstance(val, Proxy): - ptype._convert(val) + self.ptype._convert(val) elif not isinstance(value, Proxy): - ptype._convert(value) + self.ptype._convert(value) # Convert assigned value to appropriate type. If the RHS is not a # list or tuple, it generates a single-element list. @@ -945,23 +919,21 @@ class _VectorParam(_Param): if value == None: return [] - ptype = eval(self.ptype) if issequence(value): # list: coerce each element into new list - return [ ptype._convert(v) for v in value ] + return [ self.ptype._convert(v) for v in value ] else: # singleton: coerce & wrap in a list - return ptype._convert(value) + return self.ptype._convert(value) def string(self, value): - ptype = eval(self.ptype) if issequence(value): - return ' '.join([ ptype._string(v) for v in value]) + return ' '.join([ self.ptype._string(v) for v in value]) else: - return ptype._string(value) + return self.ptype._string(value) def sim_decl(self, name): - return 'VectorParam<%s> %s;' % (self.ptype.__name__, name) + return 'std::vector<%s> %s;' % (self.ptype._cppname, name) class _VectorParamProxy(_ParamProxy): # E.g., VectorParam.Int(5, "number of widgets") @@ -1008,14 +980,14 @@ class _CheckedInt(object): _string = classmethod(_string) class CheckedInt(type): - def __new__(cls, name, min, max): + def __new__(cls, cppname, min, max): # New class derives from _CheckedInt base with proper bounding # parameters - dict = { '_name' : name, '_min' : min, '_max' : max } - return type.__new__(cls, name, (_CheckedInt, ), dict) + dict = { '_cppname' : cppname, '_min' : min, '_max' : max } + return type.__new__(cls, cppname, (_CheckedInt, ), dict) class CheckedIntType(CheckedInt): - def __new__(cls, name, size, unsigned): + def __new__(cls, cppname, size, unsigned): dict = {} if unsigned: min = 0 @@ -1024,7 +996,7 @@ class CheckedIntType(CheckedInt): min = -(2 ** (size - 1)) max = (2 ** (size - 1)) - 1 - return super(cls, CheckedIntType).__new__(cls, name, min, max) + return super(cls, CheckedIntType).__new__(cls, cppname, min, max) Int = CheckedIntType('int', 32, False) Unsigned = CheckedIntType('unsigned', 32, True) @@ -1067,15 +1039,15 @@ def RangeSize(start, size): class Range(type): def __new__(cls, type): - dict = { '_name' : 'Range<%s>' + type._name, '_type' : type } - cname = 'Range_' + type.__name__ - return super(cls, Range).__new__(cls, cname, (_Range, ), dict) + dict = { '_cppname' : 'Range<%s>' % type._cppname, '_type' : type } + clsname = 'Range_' + type.__name__ + return super(cls, Range).__new__(cls, clsname, (_Range, ), dict) AddrRange = Range(Addr) # Boolean parameter type. class Bool(object): - _name = 'bool' + _cppname = 'bool' def _convert(value): t = type(value) if t == bool: @@ -1103,7 +1075,7 @@ class Bool(object): # String-valued parameter. class String(object): - _name = 'string' + _cppname = 'string' # Constructor. Value must be Python string. def _convert(cls,value): @@ -1143,7 +1115,7 @@ class NextEthernetAddr(object): self.addr = IncEthernetAddr(self.addr, inc) class EthernetAddr(object): - _name = 'EthAddr' + _cppname = 'EthAddr' def _convert(cls, value): if value == NextEthernetAddr: @@ -1175,7 +1147,7 @@ class EthernetAddr(object): # only one copy of a particular node class NullSimObject(object): __metaclass__ = Singleton - _name = 'NULL' + _cppname = 'NULL' def __call__(cls): return cls @@ -1278,21 +1250,6 @@ G = K*M ##################################################################### -# Munge an arbitrary Python code string to get it to execute (mostly -# dealing with indentation). Stolen from isa_parser.py... see -# comments there for a more detailed description. -#def fixPythonIndentation(s): -# # get rid of blank lines first -# s = re.sub(r'(?m)^\s*\n', '', s); -# if (s != '' and re.match(r'[ \t]', s[0])): -# s = 'if 1:\n' + s -# return s - -# Hook to generate C++ parameter code. -def gen_sim_code(file): - for objname in sim_object_list: - print >> file, eval("%s._sim_code()" % objname) - # The final hook to generate .ini files. Called from configuration # script once config is built. def instantiate(root): diff --git a/test/genini.py b/test/genini.py old mode 100644 new mode 100755 index 73e7012f6..9c28ef361 --- a/test/genini.py +++ b/test/genini.py @@ -30,13 +30,14 @@ from os.path import join as joinpath, realpath mypath = sys.path[0] sys.path.append(joinpath(mypath, '..')) -sys.path.append(joinpath(mypath, '../configs/kernel')) sys.path.append(joinpath(mypath, '../util/pbs')) sys.path.append(joinpath(mypath, '../sim/pyconfig')) -from importer import mpy_exec, mpy_execfile, AddToPath +from importer import AddToPath, LoadMpyFile from m5config import * +AddToPath('.') + try: opts, args = getopt.getopt(sys.argv[1:], '-E:I:') for opt,arg in opts: @@ -55,8 +56,7 @@ except getopt.GetoptError: sys.exit('Improper Usage') for arg in args: - AddToPath(os.path.dirname(arg)) - mpy_execfile(arg) + LoadMpyFile(arg) if globals().has_key('root') and isinstance(root, type) \ and issubclass(root, Root): From 9ebeb9b2de34673fffce06baf1420f85993ba806 Mon Sep 17 00:00:00 2001 From: Ali Saidi Date: Wed, 23 Feb 2005 11:45:25 -0500 Subject: [PATCH 03/10] Added mmap start and end so detailed CPU can know if an access is in a mmaped region --HG-- extra : convert_revision : e4ee0520c84d94a0d2e804d02035228766abe71f --- sim/process.cc | 2 +- sim/process.hh | 6 ++++-- sim/syscall_emul.hh | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/sim/process.cc b/sim/process.cc index c725d3b1c..f09452c42 100644 --- a/sim/process.cc +++ b/sim/process.cc @@ -282,7 +282,7 @@ LiveProcess::LiveProcess(const string &name, ObjectFile *objFile, // Set up region for mmaps. Tru64 seems to start just above 0 and // grow up from there. - mmap_base = 0x10000; + mmap_start = mmap_end = 0x10000; // Set pointer for next thread stack. Reserve 8M for main stack. next_thread_stack_base = stack_base - (8 * 1024 * 1024); diff --git a/sim/process.hh b/sim/process.hh index bb4829875..6c7bc4222 100644 --- a/sim/process.hh +++ b/sim/process.hh @@ -93,7 +93,8 @@ class Process : public SimObject Addr next_thread_stack_base; // Base of region for mmaps (when user doesn't specify an address). - Addr mmap_base; + Addr mmap_start; + Addr mmap_end; std::string prog_fname; // file name Addr prog_entry; // entry point (initial PC) @@ -156,7 +157,8 @@ class Process : public SimObject { return ((data_base <= addr && addr < brk_point) || ((stack_base - 16*1024*1024) <= addr && addr < stack_base) || - (text_base <= addr && addr < (text_base + text_size))); + (text_base <= addr && addr < (text_base + text_size)) || + (mmap_start <= addr && addr < mmap_end)); } virtual void syscall(ExecContext *xc) = 0; diff --git a/sim/syscall_emul.hh b/sim/syscall_emul.hh index 768bc3700..831708a21 100644 --- a/sim/syscall_emul.hh +++ b/sim/syscall_emul.hh @@ -410,8 +410,8 @@ mmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) if (start == 0) { // user didn't give an address... pick one from our "mmap region" - start = p->mmap_base; - p->mmap_base += RoundUp(length, VMPageSize); + start = p->mmap_end; + p->mmap_end += RoundUp(length, VMPageSize); } if (!(flags & OS::TGT_MAP_ANONYMOUS)) { From a84159174afbdf855e370674a4a85ff1ee042095 Mon Sep 17 00:00:00 2001 From: Ali Saidi Date: Wed, 23 Feb 2005 11:46:28 -0500 Subject: [PATCH 04/10] added two validation rcs files --HG-- extra : convert_revision : 19e57e5192be3435d72652e3b36aac3b6e43d81c --- configs/boot/micro_memlat.rcS | 3 +++ configs/boot/micro_syscall.rcS | 3 +++ 2 files changed, 6 insertions(+) create mode 100644 configs/boot/micro_memlat.rcS create mode 100644 configs/boot/micro_syscall.rcS diff --git a/configs/boot/micro_memlat.rcS b/configs/boot/micro_memlat.rcS new file mode 100644 index 000000000..50ee8efb3 --- /dev/null +++ b/configs/boot/micro_memlat.rcS @@ -0,0 +1,3 @@ +/benchmarks/micros/lmbench/bin/alphaev6-linux-gnu/lat_mem_rd 512 64 +m5 exit + diff --git a/configs/boot/micro_syscall.rcS b/configs/boot/micro_syscall.rcS new file mode 100644 index 000000000..0e8e209c1 --- /dev/null +++ b/configs/boot/micro_syscall.rcS @@ -0,0 +1,3 @@ +/benchmarks/micros/lmbench/bin/alphaev6-linux-gnu/lat_syscall null +m5 exit + From b78b6341078624cf476e84475b088798609b4cef Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Wed, 23 Feb 2005 12:26:35 -0500 Subject: [PATCH 05/10] Fix the python panic message sim/pyconfig/m5config.py: Fix panic --HG-- extra : convert_revision : 56d93398e992ed6e95380f6dcdb61cbee54b3893 --- sim/pyconfig/m5config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sim/pyconfig/m5config.py b/sim/pyconfig/m5config.py index 6393fb0b8..50032476c 100644 --- a/sim/pyconfig/m5config.py +++ b/sim/pyconfig/m5config.py @@ -35,7 +35,7 @@ except: env = {} env.update(os.environ) -def panic(*args, **kwargs): +def panic(string): print >>sys.stderr, 'panic:', string sys.exit(1) From 368882a847955c712c9248eaf0fe569228c8e0fb Mon Sep 17 00:00:00 2001 From: Steve Reinhardt Date: Fri, 25 Feb 2005 12:41:08 -0500 Subject: [PATCH 09/10] Fix timing modeling of faults: functionally the very next instruction after a faulting instruction is the fault handler, which appears as an independent instruction to the timing model. New code will stall fetch and not fetch the fault handler as long as there's a faulting instruction in the pipeline (i.e., the faulting inst has to commit first). Also fix Ali's bad-address assertion that doesn't apply to full system. Added some more debugging support in the process. Hopefully we'll move to the new cpu model soon and we won't need it anymore. arch/alpha/alpha_memory.cc: Reorganize lookup() so we can trace the result of the lookup as well. arch/alpha/isa_traits.hh: Add NoopMachInst (so we can insert them in the pipeline on ifetch faults). base/traceflags.py: Replace "Dispatch" flag with "Pipeline" (since I added similar DPRINTFs in other pipe stages). cpu/exetrace.cc: Change default for printing mis-speculated instructions to true (since that's often what we want, and right now you can't change it from the command line...). --HG-- extra : convert_revision : a29a98a373076d62bbbb1d6f40ba51ecae436dbc --- arch/alpha/alpha_memory.cc | 29 ++++++++++++++++------------- arch/alpha/isa_traits.hh | 3 +++ base/traceflags.py | 2 +- cpu/exetrace.cc | 2 +- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/arch/alpha/alpha_memory.cc b/arch/alpha/alpha_memory.cc index 639abbeb8..8f6d7a51a 100644 --- a/arch/alpha/alpha_memory.cc +++ b/arch/alpha/alpha_memory.cc @@ -68,24 +68,27 @@ AlphaTLB::~AlphaTLB() AlphaISA::PTE * AlphaTLB::lookup(Addr vpn, uint8_t asn) const { - DPRINTF(TLB, "lookup %#x, asn %#x\n", vpn, (int)asn); + // assume not found... + AlphaISA::PTE *retval = NULL; PageTable::const_iterator i = lookupTable.find(vpn); - if (i == lookupTable.end()) - return NULL; + if (i != lookupTable.end()) { + while (i->first == vpn) { + int index = i->second; + AlphaISA::PTE *pte = &table[index]; + assert(pte->valid); + if (vpn == pte->tag && (pte->asma || pte->asn == asn)) { + retval = pte; + break; + } - while (i->first == vpn) { - int index = i->second; - AlphaISA::PTE *pte = &table[index]; - assert(pte->valid); - if (vpn == pte->tag && (pte->asma || pte->asn == asn)) - return pte; - - ++i; + ++i; + } } - // not found... - return NULL; + DPRINTF(TLB, "lookup %#x, asn %#x -> %s ppn %#x\n", vpn, (int)asn, + retval ? "hit" : "miss", retval ? retval->ppn : 0); + return retval; } diff --git a/arch/alpha/isa_traits.hh b/arch/alpha/isa_traits.hh index ff3da1502..8db8c6994 100644 --- a/arch/alpha/isa_traits.hh +++ b/arch/alpha/isa_traits.hh @@ -175,6 +175,9 @@ static const Addr PageOffset = PageBytes - 1; static StaticInstPtr decodeInst(MachInst); + // return a no-op instruction... used for instruction fetch faults + static const MachInst NoopMachInst; + enum annotes { ANNOTE_NONE = 0, // An impossible number for instruction annotations diff --git a/base/traceflags.py b/base/traceflags.py index ef13d9e2a..800c47bd3 100644 --- a/base/traceflags.py +++ b/base/traceflags.py @@ -110,7 +110,7 @@ baseFlags = [ 'IICMore', 'MSHR', 'Chains', - 'Dispatch', + 'Pipeline', 'Stats', 'StatEvents', 'Context', diff --git a/cpu/exetrace.cc b/cpu/exetrace.cc index ff7e90c9e..048a7d283 100644 --- a/cpu/exetrace.cc +++ b/cpu/exetrace.cc @@ -154,7 +154,7 @@ class ExecutionTraceParamContext : public ParamContext ExecutionTraceParamContext exeTraceParams("exetrace"); Param exe_trace_spec(&exeTraceParams, "speculative", - "capture speculative instructions", false); + "capture speculative instructions", true); Param exe_trace_print_cycle(&exeTraceParams, "print_cycle", "print cycle number", true); From fbe2d264878d399f0f37952c26420c83b0b2412d Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Fri, 25 Feb 2005 14:38:00 -0500 Subject: [PATCH 10/10] Make the SimConsole device dump its output to a file by default --HG-- extra : convert_revision : 59cc7c3234d1bc96919d08dc0ec7584d8aff1d6f --- objects/SimConsole.mpy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/objects/SimConsole.mpy b/objects/SimConsole.mpy index ab88db8c6..fb74f1775 100644 --- a/objects/SimConsole.mpy +++ b/objects/SimConsole.mpy @@ -8,4 +8,4 @@ simobj SimConsole(SimObject): intr_control = Param.IntrControl(Super, "interrupt controller") listener = Param.ConsoleListener("console listener") number = Param.Int(0, "console number") - output = Param.String('', "file to dump output to") + output = Param.String('console', "file to dump output to")